60 |
|
{ } |
61 |
|
{************************************************************************} |
62 |
|
unit FB25Blob; |
63 |
+ |
{$IFDEF MSWINDOWS} |
64 |
+ |
{$DEFINE WINDOWS} |
65 |
+ |
{$ENDIF} |
66 |
|
|
67 |
|
{$IFDEF FPC} |
68 |
< |
{$mode objfpc}{$H+} |
68 |
> |
{$mode delphi} |
69 |
|
{$interfaces COM} |
70 |
|
{$ENDIF} |
71 |
|
|
73 |
|
|
74 |
|
uses |
75 |
|
Classes, SysUtils, IB, IBHeader,IBExternals, FBClientAPI, FB25ClientAPI, FB25Attachment, |
76 |
< |
FB25Transaction, FBActivityMonitor, FBBlob; |
76 |
> |
FB25Transaction, FBActivityMonitor, FBBlob, FBOutputBlock; |
77 |
|
|
78 |
|
type |
79 |
|
|
85 |
|
FAttachment: TFB25Attachment; |
86 |
|
FTransaction: TFB25Transaction; |
87 |
|
protected |
88 |
+ |
function Attachment: IAttachment; override; |
89 |
|
procedure NeedFullMetadata; override; |
90 |
|
public |
91 |
|
constructor Create(Attachment: TFB25Attachment; Transaction: TFB25Transaction; |
92 |
< |
RelationName, ColumnName: string); overload; |
92 |
> |
RelationName, ColumnName: AnsiString); overload; |
93 |
|
constructor Create(Attachment: TFB25Attachment; Transaction: TFB25Transaction; |
94 |
< |
RelationName, ColumnName: string; SubType: integer); overload; |
94 |
> |
RelationName, ColumnName: AnsiString; SubType: integer); overload; |
95 |
|
end; |
96 |
|
|
97 |
|
|
105 |
|
procedure CheckReadable; override; |
106 |
|
procedure CheckWritable; override; |
107 |
|
function GetIntf: IBlob; override; |
108 |
+ |
procedure GetInfo(Request: array of byte; Response: IBlobInfo); override; |
109 |
|
procedure InternalClose(Force: boolean); override; |
110 |
|
procedure InternalCancel(Force: boolean); override; |
111 |
|
public |
118 |
|
property Handle: TISC_BLOB_HANDLE read FHandle; |
119 |
|
|
120 |
|
public |
116 |
– |
procedure GetInfo(var NumSegments: Int64; var MaxSegmentSize, TotalSize: Int64; |
117 |
– |
var BlobType: TBlobType); override; |
121 |
|
function Read(var Buffer; Count: Longint): Longint; override; |
122 |
|
function Write(const Buffer; Count: Longint): Longint; override; |
123 |
|
end; |
128 |
|
|
129 |
|
{ TFB25BlobMetaData } |
130 |
|
|
131 |
+ |
function TFB25BlobMetaData.Attachment: IAttachment; |
132 |
+ |
begin |
133 |
+ |
Result := FAttachment; |
134 |
+ |
end; |
135 |
+ |
|
136 |
|
procedure TFB25BlobMetaData.NeedFullMetadata; |
137 |
|
var |
138 |
|
BlobDesc: TISC_BLOB_DESC; |
139 |
|
Global: array [0..31] of char; |
140 |
+ |
RelName: AnsiString; |
141 |
+ |
ColName: AnsiString; |
142 |
|
begin |
143 |
|
if FHasFullMetaData then Exit; |
144 |
|
|
135 |
– |
FCharSetID := 0; |
145 |
|
FSegmentSize := 80; |
146 |
< |
FUnconfirmedCharacterSet := false; |
147 |
< |
if (GetColumnName <> '') and (GetRelationName <> '') then |
146 |
> |
RelName := AnsiUpperCase(GetRelationName); |
147 |
> |
ColName := AnsiUpperCase(GetColumnName); |
148 |
> |
if (ColName <> '') and (RelName <> '') then |
149 |
|
begin |
150 |
|
with Firebird25ClientAPI do |
151 |
|
Call(isc_blob_lookup_desc(StatusVector,@(FAttachment.Handle), |
152 |
|
@(FTransaction.Handle), |
153 |
< |
PChar(AnsiUpperCase(GetRelationName)),PChar(AnsiUpperCase(GetColumnName)),@BlobDesc,@Global)); |
154 |
< |
FCharSetID := BlobDesc.blob_desc_charset; |
153 |
> |
PAnsiChar(RelName),PAnsiChar(ColName),@BlobDesc,@Global)); |
154 |
> |
if FUnconfirmedCharacterSet then |
155 |
> |
FCharSetID := BlobDesc.blob_desc_charset; |
156 |
|
FSubType := BlobDesc.blob_desc_subtype; |
157 |
|
FSegmentSize := BlobDesc.blob_desc_segment_size ; |
158 |
< |
end |
148 |
< |
else |
149 |
< |
FUnconfirmedCharacterSet := true; |
158 |
> |
end; |
159 |
|
|
160 |
< |
if (FCharSetID > 1) and FAttachment.HasDefaultCharSet then |
160 |
> |
if FUnconfirmedCharacterSet and (FCharSetID > 1) and FAttachment.HasDefaultCharSet then |
161 |
|
begin |
162 |
|
FCharSetID := FAttachment.CharSetID; |
163 |
|
FUnconfirmedCharacterSet := false; |
169 |
|
end; |
170 |
|
|
171 |
|
constructor TFB25BlobMetaData.Create(Attachment: TFB25Attachment; |
172 |
< |
Transaction: TFB25Transaction; RelationName, ColumnName: string); |
172 |
> |
Transaction: TFB25Transaction; RelationName, ColumnName: AnsiString); |
173 |
|
begin |
174 |
|
inherited Create(Transaction,RelationName,ColumnName); |
175 |
|
FAttachment := Attachment; |
177 |
|
end; |
178 |
|
|
179 |
|
constructor TFB25BlobMetaData.Create(Attachment: TFB25Attachment; |
180 |
< |
Transaction: TFB25Transaction; RelationName, ColumnName: string; |
180 |
> |
Transaction: TFB25Transaction; RelationName, ColumnName: AnsiString; |
181 |
|
SubType: integer); |
182 |
|
begin |
183 |
|
Create(Attachment,Transaction,RelationName,ColumnName); |
204 |
|
Result := self; |
205 |
|
end; |
206 |
|
|
207 |
+ |
procedure TFB25Blob.GetInfo(Request: array of byte; Response: IBlobInfo); |
208 |
+ |
begin |
209 |
+ |
if FHandle = nil then |
210 |
+ |
IBError(ibxeBlobNotOpen,[nil]); |
211 |
+ |
|
212 |
+ |
with Firebird25ClientAPI, Response as TBlobInfo do |
213 |
+ |
Call(isc_blob_info(StatusVector, @FHandle, Length(Request),@Request, |
214 |
+ |
GetBufSize, Buffer)); |
215 |
+ |
end; |
216 |
+ |
|
217 |
|
procedure TFB25Blob.InternalClose(Force: boolean); |
218 |
|
begin |
219 |
|
if FHandle = nil then |
294 |
|
@FBlobID, getDataLength, getBuffer)); |
295 |
|
end; |
296 |
|
|
278 |
– |
procedure TFB25Blob.GetInfo(var NumSegments: Int64; var MaxSegmentSize, |
279 |
– |
TotalSize: Int64; var BlobType: TBlobType); |
280 |
– |
var |
281 |
– |
items: array[0..3] of Char; |
282 |
– |
results: array[0..99] of Char; |
283 |
– |
i, item_length: Integer; |
284 |
– |
item: Integer; |
285 |
– |
begin |
286 |
– |
if FHandle = nil then |
287 |
– |
IBError(ibxeBlobNotOpen,[nil]); |
288 |
– |
|
289 |
– |
items[0] := Char(isc_info_blob_num_segments); |
290 |
– |
items[1] := Char(isc_info_blob_max_segment); |
291 |
– |
items[2] := Char(isc_info_blob_total_length); |
292 |
– |
items[3] := Char(isc_info_blob_type); |
293 |
– |
|
294 |
– |
with Firebird25ClientAPI do |
295 |
– |
begin |
296 |
– |
Call(isc_blob_info(StatusVector, @FHandle, 4, @items[0], SizeOf(results), |
297 |
– |
@results[0])); |
298 |
– |
i := 0; |
299 |
– |
while (i < SizeOf(results)) and (results[i] <> Char(isc_info_end)) do |
300 |
– |
begin |
301 |
– |
item := Integer(results[i]); Inc(i); |
302 |
– |
item_length := isc_portable_integer(@results[i], 2); Inc(i, 2); |
303 |
– |
case item of |
304 |
– |
isc_info_blob_num_segments: |
305 |
– |
NumSegments := isc_portable_integer(@results[i], item_length); |
306 |
– |
isc_info_blob_max_segment: |
307 |
– |
MaxSegmentSize := isc_portable_integer(@results[i], item_length); |
308 |
– |
isc_info_blob_total_length: |
309 |
– |
TotalSize := isc_portable_integer(@results[i], item_length); |
310 |
– |
isc_info_blob_type: |
311 |
– |
if isc_portable_integer(@results[i], item_length) = 0 then |
312 |
– |
BlobType := btSegmented |
313 |
– |
else |
314 |
– |
BlobType := btStream; |
315 |
– |
end; |
316 |
– |
Inc(i, item_length); |
317 |
– |
end; |
318 |
– |
end; |
319 |
– |
end; |
320 |
– |
|
297 |
|
function TFB25Blob.Read(var Buffer; Count: Longint): Longint; |
298 |
|
var |
299 |
|
BytesRead : UShort; |
300 |
< |
LocalBuffer: PChar; |
300 |
> |
LocalBuffer: PByte; |
301 |
|
returnCode: long; |
302 |
|
localCount: uShort; |
303 |
|
begin |
306 |
|
if FEOB then |
307 |
|
Exit; |
308 |
|
|
309 |
< |
LocalBuffer := PChar(@Buffer); |
309 |
> |
LocalBuffer := PByte(@Buffer); |
310 |
|
repeat |
311 |
|
if Count > MaxuShort then |
312 |
|
localCount := MaxuShort |
328 |
|
|
329 |
|
function TFB25Blob.Write(const Buffer; Count: Longint): Longint; |
330 |
|
var |
331 |
< |
LocalBuffer: PChar; |
331 |
> |
LocalBuffer: PByte; |
332 |
|
localCount: uShort; |
333 |
|
begin |
334 |
|
CheckWritable; |
335 |
< |
LocalBuffer := PChar(@Buffer); |
335 |
> |
LocalBuffer := PByte(@Buffer); |
336 |
|
Result := 0; |
337 |
|
if Count = 0 then Exit; |
338 |
|
|