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: 45
Committed: Tue Dec 6 10:33:46 2016 UTC (7 years, 4 months ago) by tony
Content type: text/x-pascal
File size: 10726 byte(s)
Log Message:
Committing updates for Release R2-0-0

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     uses FBMessages, FB30Statement, FBParamBlock;
92    
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     FCharSetID := 0;
106     FSegmentSize := 80;
107     FUnconfirmedCharacterSet := false;
108     if (GetColumnName <> '') and (GetRelationName <> '') then
109     begin
110     stmt := TFB30Statement.Create(FAttachment,FTransaction, sLookupBlobMetaData ,FAttachment.SQLDialect);
111     with stmt do
112     begin
113     SQLParams[0].AsString := GetRelationName;
114     SQLParams[1].AsString := GetColumnName;
115     with OpenCursor do
116     if FetchNext then
117     begin
118     if Data[3].AsInteger <> blr_blob then
119     IBError(ibxeInvalidBlobMetaData,[nil]);
120     FSubType := Data[0].AsInteger;
121     FSegmentSize := Data[1].AsInteger;
122     FCharSetID := Data[2].AsInteger;
123     end
124     else
125     IBError(ibxeInvalidBlobMetaData,[nil]);
126    
127     end;
128     end
129     else
130     FUnconfirmedCharacterSet := true;
131    
132     if (FCharSetID > 1) and FAttachment.HasDefaultCharSet then
133     begin
134     FCharSetID := FAttachment.CharSetID;
135     FUnconfirmedCharacterSet := false;
136     end;
137    
138     FHasFullMetaData := true;
139     FHasSubType := true;
140     end;
141    
142     constructor TFB30BlobMetaData.Create(Attachment: TFB30Attachment;
143     Transaction: TFB30Transaction; RelationName, ColumnName: string);
144     begin
145     inherited Create(Transaction,RelationName,ColumnName);
146     FAttachment := Attachment;
147     FTransaction := Transaction;
148     end;
149    
150     constructor TFB30BlobMetaData.Create(Attachment: TFB30Attachment;
151     Transaction: TFB30Transaction; RelationName, ColumnName: string;
152     SubType: integer);
153     begin
154     Create(Attachment,Transaction,RelationName,ColumnName);
155     FSubType := SubType;
156     FHasSubType := true;
157     end;
158    
159     { TFB30Blob }
160    
161     procedure TFB30Blob.CheckReadable;
162     begin
163     if FCreating or (FBlobIntf = nil) then
164     IBError(ibxeBlobCannotBeRead, [nil]);
165     end;
166    
167     procedure TFB30Blob.CheckWritable;
168     begin
169     if not FCreating or (FBlobIntf = nil) then
170     IBError(ibxeBlobCannotBeWritten, [nil]);
171     end;
172    
173     function TFB30Blob.GetIntf: IBlob;
174     begin
175     Result := self;
176     end;
177    
178     procedure TFB30Blob.InternalClose(Force: boolean);
179     begin
180     if FBlobIntf = nil then
181     Exit;
182     with Firebird30ClientAPI do
183     begin
184     FBlobIntf.close(StatusIntf);
185     if not Force then Check4DataBaseError;
186     end;
187     FBlobIntf.release;
188     FBlobIntf := nil;
189     end;
190    
191     procedure TFB30Blob.InternalCancel(Force: boolean);
192     begin
193     if FBlobIntf = nil then
194     Exit;
195     with Firebird30ClientAPI do
196     begin
197     FBlobIntf.cancel(StatusIntf);
198     if not Force then Check4DataBaseError;
199     end;
200     FBlobIntf.release;
201     FBlobIntf := nil;
202     end;
203    
204     constructor TFB30Blob.Create(Attachment: TFB30Attachment; Transaction: TFB30Transaction;
205     MetaData: IBlobMetaData; BPB: IBPB);
206     begin
207     inherited Create(Attachment,Transaction,MetaData,BPB);
208     with Firebird30ClientAPI do
209     begin
210     if BPB = nil then
211     FBlobIntf := Attachment.AttachmentIntf.createBlob(StatusIntf,Transaction.TransactionIntf,
212     @FBlobID,0,nil)
213     else
214     with BPB as TBPB do
215     FBlobIntf := Attachment.AttachmentIntf.createBlob(StatusIntf,Transaction.TransactionIntf,
216     @FBlobID,getDataLength, BytePtr(getBuffer));
217     Check4DataBaseError;
218     end;
219     end;
220    
221     constructor TFB30Blob.Create(Attachment: TFB30Attachment;
222     Transaction: TFB30Transaction; SubType: integer; CharSetID: cardinal;
223     BPB: IBPB);
224     var MetaData: TFB30BlobMetaData;
225     begin
226     MetaData := TFB30BlobMetaData.Create(Attachment,Transaction,'','',SubType);
227     MetaData.FCharSetID := CharSetID;
228     MetaData.FHasFullMetaData := true;
229     inherited Create(Attachment,Transaction,MetaData,BPB);
230     with Firebird30ClientAPI do
231     begin
232     if BPB = nil then
233     FBlobIntf := Attachment.AttachmentIntf.createBlob(StatusIntf,Transaction.TransactionIntf,
234     @FBlobID,0,nil)
235     else
236     with BPB as TBPB do
237     FBlobIntf := Attachment.AttachmentIntf.createBlob(StatusIntf,Transaction.TransactionIntf,
238     @FBlobID,getDataLength, BytePtr(getBuffer));
239     Check4DataBaseError;
240     end;
241     end;
242    
243     constructor TFB30Blob.Create(Attachment: TFB30Attachment;
244     Transaction: TFBTransaction; MetaData: IBlobMetaData; BlobID: TISC_QUAD; BPB: IBPB);
245     begin
246     inherited Create(Attachment,Transaction,MetaData,BlobID,BPB);
247     if (BlobID.gds_quad_high = 0) and (BlobID.gds_quad_low = 0) then
248     Exit;
249    
250     with Firebird30ClientAPI do
251     begin
252     if BPB = nil then
253     FBlobIntf := Attachment.AttachmentIntf.openBlob(StatusIntf,(Transaction as TFB30Transaction).TransactionIntf,
254     @FBlobID, 0, nil)
255     else
256     with BPB as TBPB do
257     FBlobIntf := Attachment.AttachmentIntf.openBlob(StatusIntf,(Transaction as TFB30Transaction).TransactionIntf,
258     @FBlobID, getDataLength, BytePtr(getBuffer));
259     Check4DataBaseError;
260     end;
261     end;
262    
263     procedure TFB30Blob.GetInfo(var NumSegments: Int64; var MaxSegmentSize,
264     TotalSize: Int64; var BlobType: TBlobType);
265     var
266     items: array[0..3] of Char;
267     results: array[0..99] of Char;
268     i, item_length: Integer;
269     item: Integer;
270     begin
271     if FBlobIntf = nil then
272     IBError(ibxeBlobNotOpen,[nil]);
273    
274     items[0] := Char(isc_info_blob_num_segments);
275     items[1] := Char(isc_info_blob_max_segment);
276     items[2] := Char(isc_info_blob_total_length);
277     items[3] := Char(isc_info_blob_type);
278    
279     with Firebird30ClientAPI do
280     begin
281     FBlobIntf.getInfo(StatusIntf,4,@items[0],SizeOf(results),@results[0]);
282     Check4DataBaseError;
283     SignalActivity;
284     i := 0;
285     while (i < SizeOf(results)) and (results[i] <> Char(isc_info_end)) do
286     begin
287     item := Integer(results[i]); Inc(i);
288     item_length := DecodeInteger(@results[i], 2); Inc(i, 2);
289     case item of
290     isc_info_blob_num_segments:
291     NumSegments := DecodeInteger(@results[i], item_length);
292     isc_info_blob_max_segment:
293     MaxSegmentSize := DecodeInteger(@results[i], item_length);
294     isc_info_blob_total_length:
295     TotalSize := DecodeInteger(@results[i], item_length);
296     isc_info_blob_type:
297     if DecodeInteger(@results[i], item_length) = 0 then
298     BlobType := btSegmented
299     else
300     BlobType := btStream;
301     end;
302     Inc(i, item_length);
303     end;
304     end;
305     end;
306    
307     function TFB30Blob.Read(var Buffer; Count: Longint): Longint;
308     var
309     BytesRead : cardinal;
310     LocalBuffer: PChar;
311     returnCode: integer;
312     localCount: uShort;
313     begin
314     CheckReadable;
315     Result := 0;
316     if FEOB then
317     Exit;
318    
319     LocalBuffer := PChar(@Buffer);
320     repeat
321     localCount := Count;
322     with Firebird30ClientAPI do
323     returnCode := FBlobIntf.getSegment(StatusIntf,localCount, LocalBuffer, @BytesRead);
324     SignalActivity;
325     Inc(LocalBuffer,BytesRead);
326     Inc(Result,BytesRead);
327     Dec(Count,BytesRead);
328     until ((returncode <> Firebird.IStatus.Result_OK) and (returnCode <> Firebird.IStatus.Result_SEGMENT)) or (Count = 0);
329    
330     FEOB := returnCode = Firebird.IStatus.RESULT_NO_DATA;
331     ClearStringCache;
332     if (returnCode <> Firebird.IStatus.Result_OK) and
333     (returnCode <> Firebird.IStatus.Result_SEGMENT) and
334     (returnCode <> Firebird.IStatus.RESULT_NO_DATA) then
335     Firebird30ClientAPI.IBDataBaseError
336     end;
337    
338     function TFB30Blob.Write(const Buffer; Count: Longint): Longint;
339     begin
340     CheckWritable;
341     Result := 0;
342     if Count = 0 then Exit;
343    
344     with Firebird30ClientAPI do
345     begin
346     FBlobIntf.putSegment(StatusIntf,Count,@Buffer);
347     Check4DataBaseError;
348     end;
349     ClearStringCache;
350     SignalActivity;
351     Result := Count;
352     end;
353    
354     end.
355