ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/fbintf/client/3.0/FB30Blob.pas
Revision: 47
Committed: Mon Jan 9 15:31:51 2017 UTC (7 years, 3 months ago) by tony
Content type: text/x-pascal
File size: 10956 byte(s)
Log Message:
Committing updates for Release R2-0-1

File Contents

# User Rev Content
1 tony 45 (*
2     * Firebird Interface (fbintf). The fbintf components provide a set of
3     * Pascal language bindings for the Firebird API.
4     *
5     * The contents of this file are subject to the Initial Developer's
6     * Public License Version 1.0 (the "License"); you may not use this
7     * file except in compliance with the License. You may obtain a copy
8     * of the License here:
9     *
10     * http://www.firebirdsql.org/index.php?op=doc&id=idpl
11     *
12     * Software distributed under the License is distributed on an "AS
13     * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14     * implied. See the License for the specific language governing rights
15     * and limitations under the License.
16     *
17     * The Initial Developer of the Original Code is Tony Whyman.
18     *
19     * The Original Code is (C) 2016 Tony Whyman, MWA Software
20     * (http://www.mwasoftware.co.uk).
21     *
22     * All Rights Reserved.
23     *
24     * Contributor(s): ______________________________________.
25     *
26     *)
27     unit FB30Blob;
28    
29     {$IFDEF FPC}
30     {$mode objfpc}{$H+}
31     {$interfaces COM}
32     {$ENDIF}
33    
34     interface
35    
36     uses
37     Classes, SysUtils, Firebird, IB, IBHeader, IBExternals, FBClientAPI, FB30ClientAPI, FB30Attachment,
38     FBTransaction, FB30Transaction, FBBlob;
39    
40     type
41    
42     { TFB30BlobMetaData }
43    
44     TFB30BlobMetaData = class(TFBBlobMetaData, IBlobMetaData)
45     private
46     FHasFullMetaData: boolean;
47     FAttachment: TFB30Attachment;
48     FTransaction: TFB30Transaction;
49     protected
50     procedure NeedFullMetadata; override;
51     public
52     constructor Create(Attachment: TFB30Attachment; Transaction: TFB30Transaction;
53     RelationName, ColumnName: string); overload;
54     constructor Create(Attachment: TFB30Attachment; Transaction: TFB30Transaction;
55     RelationName, ColumnName: string; SubType: integer); overload;
56    
57     end;
58    
59    
60     { TFB30Blob }
61    
62     TFB30Blob = class(TFBBlob,IBlob)
63     private
64     FBlobIntf: Firebird.IBlob;
65     FEOB: boolean;
66     protected
67     procedure CheckReadable; override;
68     procedure CheckWritable; override;
69     function GetIntf: IBlob; override;
70     procedure InternalClose(Force: boolean); override;
71     procedure InternalCancel(Force: boolean); override;
72     public
73     constructor Create(Attachment: TFB30Attachment; Transaction: TFB30Transaction;
74     MetaData: IBlobMetaData; BPB: IBPB); overload;
75     constructor Create(Attachment: TFB30Attachment; Transaction: TFB30Transaction;
76     SubType: integer; CharSetID: cardinal; BPB: IBPB); overload;
77     constructor Create(Attachment: TFB30Attachment; Transaction: TFBTransaction;
78     MetaData: IBlobMetaData; BlobID: TISC_QUAD; BPB: IBPB); overload;
79     property BlobIntf: Firebird.IBlob read FBlobIntf;
80    
81     {IBlob}
82     public
83     procedure GetInfo(var NumSegments: Int64; var MaxSegmentSize, TotalSize: Int64;
84     var BlobType: TBlobType); override;
85     function Read(var Buffer; Count: Longint): Longint; override;
86     function Write(const Buffer; Count: Longint): Longint; override;
87     end;
88    
89     implementation
90    
91 tony 47 uses FBMessages, FB30Statement, FBParamBlock, Math;
92 tony 45
93     const
94     sLookupBlobMetaData = 'Select F.RDB$FIELD_SUB_TYPE, F.RDB$SEGMENT_LENGTH, RDB$CHARACTER_SET_ID, F.RDB$FIELD_TYPE '+
95     'From RDB$FIELDS F JOIN RDB$RELATION_FIELDS R On R.RDB$FIELD_SOURCE = F.RDB$FIELD_NAME '+
96     'Where Trim(R.RDB$RELATION_NAME) = Upper(Trim(?)) and Trim(R.RDB$FIELD_NAME) = Upper(Trim(?))';
97    
98     { TFB30BlobMetaData }
99    
100     procedure TFB30BlobMetaData.NeedFullMetadata;
101     var stmt: IStatement;
102     begin
103     if FHasFullMetaData then Exit;
104    
105     FSegmentSize := 80;
106     if (GetColumnName <> '') and (GetRelationName <> '') then
107     begin
108     stmt := TFB30Statement.Create(FAttachment,FTransaction, sLookupBlobMetaData ,FAttachment.SQLDialect);
109     with stmt do
110     begin
111     SQLParams[0].AsString := GetRelationName;
112     SQLParams[1].AsString := GetColumnName;
113     with OpenCursor do
114     if FetchNext then
115     begin
116     if Data[3].AsInteger <> blr_blob then
117     IBError(ibxeInvalidBlobMetaData,[nil]);
118     FSubType := Data[0].AsInteger;
119     FSegmentSize := Data[1].AsInteger;
120 tony 47 if FUnconfirmedCharacterSet then
121     FCharSetID := Data[2].AsInteger;
122 tony 45 end
123     else
124     IBError(ibxeInvalidBlobMetaData,[nil]);
125    
126     end;
127 tony 47 end;
128 tony 45
129 tony 47 if FUnconfirmedCharacterSet and (FCharSetID > 1) and FAttachment.HasDefaultCharSet then
130 tony 45 begin
131     FCharSetID := FAttachment.CharSetID;
132     FUnconfirmedCharacterSet := false;
133     end;
134    
135     FHasFullMetaData := true;
136     FHasSubType := true;
137     end;
138    
139     constructor TFB30BlobMetaData.Create(Attachment: TFB30Attachment;
140     Transaction: TFB30Transaction; RelationName, ColumnName: string);
141     begin
142     inherited Create(Transaction,RelationName,ColumnName);
143     FAttachment := Attachment;
144     FTransaction := Transaction;
145     end;
146    
147     constructor TFB30BlobMetaData.Create(Attachment: TFB30Attachment;
148     Transaction: TFB30Transaction; RelationName, ColumnName: string;
149     SubType: integer);
150     begin
151     Create(Attachment,Transaction,RelationName,ColumnName);
152     FSubType := SubType;
153     FHasSubType := true;
154     end;
155    
156     { TFB30Blob }
157    
158     procedure TFB30Blob.CheckReadable;
159     begin
160     if FCreating or (FBlobIntf = nil) then
161     IBError(ibxeBlobCannotBeRead, [nil]);
162     end;
163    
164     procedure TFB30Blob.CheckWritable;
165     begin
166     if not FCreating or (FBlobIntf = nil) then
167     IBError(ibxeBlobCannotBeWritten, [nil]);
168     end;
169    
170     function TFB30Blob.GetIntf: IBlob;
171     begin
172     Result := self;
173     end;
174    
175     procedure TFB30Blob.InternalClose(Force: boolean);
176     begin
177     if FBlobIntf = nil then
178     Exit;
179     with Firebird30ClientAPI do
180     begin
181     FBlobIntf.close(StatusIntf);
182     if not Force then Check4DataBaseError;
183     end;
184     FBlobIntf.release;
185     FBlobIntf := nil;
186     end;
187    
188     procedure TFB30Blob.InternalCancel(Force: boolean);
189     begin
190     if FBlobIntf = nil then
191     Exit;
192     with Firebird30ClientAPI do
193     begin
194     FBlobIntf.cancel(StatusIntf);
195     if not Force then Check4DataBaseError;
196     end;
197     FBlobIntf.release;
198     FBlobIntf := nil;
199     end;
200    
201     constructor TFB30Blob.Create(Attachment: TFB30Attachment; Transaction: TFB30Transaction;
202     MetaData: IBlobMetaData; BPB: IBPB);
203     begin
204     inherited Create(Attachment,Transaction,MetaData,BPB);
205     with Firebird30ClientAPI do
206     begin
207     if BPB = nil then
208     FBlobIntf := Attachment.AttachmentIntf.createBlob(StatusIntf,Transaction.TransactionIntf,
209     @FBlobID,0,nil)
210     else
211     with BPB as TBPB do
212     FBlobIntf := Attachment.AttachmentIntf.createBlob(StatusIntf,Transaction.TransactionIntf,
213     @FBlobID,getDataLength, BytePtr(getBuffer));
214     Check4DataBaseError;
215     end;
216     end;
217    
218     constructor TFB30Blob.Create(Attachment: TFB30Attachment;
219     Transaction: TFB30Transaction; SubType: integer; CharSetID: cardinal;
220     BPB: IBPB);
221     var MetaData: TFB30BlobMetaData;
222     begin
223     MetaData := TFB30BlobMetaData.Create(Attachment,Transaction,'','',SubType);
224     MetaData.FCharSetID := CharSetID;
225     MetaData.FHasFullMetaData := true;
226     inherited Create(Attachment,Transaction,MetaData,BPB);
227     with Firebird30ClientAPI do
228     begin
229     if BPB = nil then
230     FBlobIntf := Attachment.AttachmentIntf.createBlob(StatusIntf,Transaction.TransactionIntf,
231     @FBlobID,0,nil)
232     else
233     with BPB as TBPB do
234     FBlobIntf := Attachment.AttachmentIntf.createBlob(StatusIntf,Transaction.TransactionIntf,
235     @FBlobID,getDataLength, BytePtr(getBuffer));
236     Check4DataBaseError;
237     end;
238     end;
239    
240     constructor TFB30Blob.Create(Attachment: TFB30Attachment;
241     Transaction: TFBTransaction; MetaData: IBlobMetaData; BlobID: TISC_QUAD; BPB: IBPB);
242     begin
243     inherited Create(Attachment,Transaction,MetaData,BlobID,BPB);
244     if (BlobID.gds_quad_high = 0) and (BlobID.gds_quad_low = 0) then
245     Exit;
246    
247     with Firebird30ClientAPI do
248     begin
249     if BPB = nil then
250     FBlobIntf := Attachment.AttachmentIntf.openBlob(StatusIntf,(Transaction as TFB30Transaction).TransactionIntf,
251     @FBlobID, 0, nil)
252     else
253     with BPB as TBPB do
254     FBlobIntf := Attachment.AttachmentIntf.openBlob(StatusIntf,(Transaction as TFB30Transaction).TransactionIntf,
255     @FBlobID, getDataLength, BytePtr(getBuffer));
256     Check4DataBaseError;
257     end;
258     end;
259    
260     procedure TFB30Blob.GetInfo(var NumSegments: Int64; var MaxSegmentSize,
261     TotalSize: Int64; var BlobType: TBlobType);
262     var
263     items: array[0..3] of Char;
264     results: array[0..99] of Char;
265     i, item_length: Integer;
266     item: Integer;
267     begin
268     if FBlobIntf = nil then
269     IBError(ibxeBlobNotOpen,[nil]);
270    
271     items[0] := Char(isc_info_blob_num_segments);
272     items[1] := Char(isc_info_blob_max_segment);
273     items[2] := Char(isc_info_blob_total_length);
274     items[3] := Char(isc_info_blob_type);
275    
276     with Firebird30ClientAPI do
277     begin
278     FBlobIntf.getInfo(StatusIntf,4,@items[0],SizeOf(results),@results[0]);
279     Check4DataBaseError;
280     SignalActivity;
281     i := 0;
282     while (i < SizeOf(results)) and (results[i] <> Char(isc_info_end)) do
283     begin
284     item := Integer(results[i]); Inc(i);
285     item_length := DecodeInteger(@results[i], 2); Inc(i, 2);
286     case item of
287     isc_info_blob_num_segments:
288     NumSegments := DecodeInteger(@results[i], item_length);
289     isc_info_blob_max_segment:
290     MaxSegmentSize := DecodeInteger(@results[i], item_length);
291     isc_info_blob_total_length:
292     TotalSize := DecodeInteger(@results[i], item_length);
293     isc_info_blob_type:
294     if DecodeInteger(@results[i], item_length) = 0 then
295     BlobType := btSegmented
296     else
297     BlobType := btStream;
298     end;
299     Inc(i, item_length);
300     end;
301     end;
302     end;
303    
304     function TFB30Blob.Read(var Buffer; Count: Longint): Longint;
305     var
306     BytesRead : cardinal;
307     LocalBuffer: PChar;
308     returnCode: integer;
309     localCount: uShort;
310     begin
311     CheckReadable;
312     Result := 0;
313     if FEOB then
314     Exit;
315    
316     LocalBuffer := PChar(@Buffer);
317     repeat
318 tony 47 localCount := Min(Count,MaxuShort);
319 tony 45 with Firebird30ClientAPI do
320     returnCode := FBlobIntf.getSegment(StatusIntf,localCount, LocalBuffer, @BytesRead);
321     SignalActivity;
322     Inc(LocalBuffer,BytesRead);
323     Inc(Result,BytesRead);
324     Dec(Count,BytesRead);
325     until ((returncode <> Firebird.IStatus.Result_OK) and (returnCode <> Firebird.IStatus.Result_SEGMENT)) or (Count = 0);
326    
327     FEOB := returnCode = Firebird.IStatus.RESULT_NO_DATA;
328     ClearStringCache;
329     if (returnCode <> Firebird.IStatus.Result_OK) and
330     (returnCode <> Firebird.IStatus.Result_SEGMENT) and
331     (returnCode <> Firebird.IStatus.RESULT_NO_DATA) then
332     Firebird30ClientAPI.IBDataBaseError
333     end;
334    
335     function TFB30Blob.Write(const Buffer; Count: Longint): Longint;
336 tony 47 var
337     LocalBuffer: PChar;
338     localCount: uShort;
339 tony 45 begin
340     CheckWritable;
341     Result := 0;
342     if Count = 0 then Exit;
343    
344 tony 47 LocalBuffer := PChar(@Buffer);
345     repeat
346     localCount := Min(Count,MaxuShort);
347     with Firebird30ClientAPI do
348     begin
349     FBlobIntf.putSegment(StatusIntf,localCount,LocalBuffer);
350     Check4DataBaseError;
351     end;
352     Inc(LocalBuffer,localCount);
353     Inc(Result,localCount);
354     Dec(Count,localCount);
355     until Count = 0;
356 tony 45 ClearStringCache;
357     SignalActivity;
358     end;
359    
360     end.
361