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: 56
Committed: Mon Mar 6 10:20:02 2017 UTC (7 years, 8 months ago) by tony
Content type: text/x-pascal
File size: 10003 byte(s)
Log Message:
Committing updates for Trunk

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 tony 56 {$IFDEF MSWINDOWS}
29     {$DEFINE WINDOWS}
30     {$ENDIF}
31 tony 45
32     {$IFDEF FPC}
33 tony 56 {$mode delphi}
34 tony 45 {$interfaces COM}
35     {$ENDIF}
36    
37     interface
38    
39     uses
40     Classes, SysUtils, Firebird, IB, IBHeader, IBExternals, FBClientAPI, FB30ClientAPI, FB30Attachment,
41 tony 56 FBTransaction, FB30Transaction, FBBlob, FBOutputBlock;
42 tony 45
43     type
44    
45     { TFB30BlobMetaData }
46    
47     TFB30BlobMetaData = class(TFBBlobMetaData, IBlobMetaData)
48     private
49     FHasFullMetaData: boolean;
50     FAttachment: TFB30Attachment;
51     FTransaction: TFB30Transaction;
52     protected
53     procedure NeedFullMetadata; override;
54     public
55     constructor Create(Attachment: TFB30Attachment; Transaction: TFB30Transaction;
56 tony 56 RelationName, ColumnName: AnsiString); overload;
57 tony 45 constructor Create(Attachment: TFB30Attachment; Transaction: TFB30Transaction;
58 tony 56 RelationName, ColumnName: AnsiString; SubType: integer); overload;
59 tony 45
60     end;
61    
62    
63     { TFB30Blob }
64    
65     TFB30Blob = class(TFBBlob,IBlob)
66     private
67     FBlobIntf: Firebird.IBlob;
68     FEOB: boolean;
69     protected
70     procedure CheckReadable; override;
71     procedure CheckWritable; override;
72     function GetIntf: IBlob; override;
73 tony 56 procedure GetInfo(Request: array of byte; Response: IBlobInfo); override;
74 tony 45 procedure InternalClose(Force: boolean); override;
75     procedure InternalCancel(Force: boolean); override;
76     public
77     constructor Create(Attachment: TFB30Attachment; Transaction: TFB30Transaction;
78     MetaData: IBlobMetaData; BPB: IBPB); overload;
79     constructor Create(Attachment: TFB30Attachment; Transaction: TFB30Transaction;
80     SubType: integer; CharSetID: cardinal; BPB: IBPB); overload;
81     constructor Create(Attachment: TFB30Attachment; Transaction: TFBTransaction;
82     MetaData: IBlobMetaData; BlobID: TISC_QUAD; BPB: IBPB); overload;
83     property BlobIntf: Firebird.IBlob read FBlobIntf;
84    
85     {IBlob}
86     public
87     function Read(var Buffer; Count: Longint): Longint; override;
88     function Write(const Buffer; Count: Longint): Longint; override;
89     end;
90    
91     implementation
92    
93 tony 47 uses FBMessages, FB30Statement, FBParamBlock, Math;
94 tony 45
95     const
96     sLookupBlobMetaData = 'Select F.RDB$FIELD_SUB_TYPE, F.RDB$SEGMENT_LENGTH, RDB$CHARACTER_SET_ID, F.RDB$FIELD_TYPE '+
97     'From RDB$FIELDS F JOIN RDB$RELATION_FIELDS R On R.RDB$FIELD_SOURCE = F.RDB$FIELD_NAME '+
98     'Where Trim(R.RDB$RELATION_NAME) = Upper(Trim(?)) and Trim(R.RDB$FIELD_NAME) = Upper(Trim(?))';
99    
100     { TFB30BlobMetaData }
101    
102     procedure TFB30BlobMetaData.NeedFullMetadata;
103     var stmt: IStatement;
104     begin
105     if FHasFullMetaData then Exit;
106    
107     FSegmentSize := 80;
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 tony 47 if FUnconfirmedCharacterSet then
123     FCharSetID := Data[2].AsInteger;
124 tony 45 end
125     else
126     IBError(ibxeInvalidBlobMetaData,[nil]);
127    
128     end;
129 tony 47 end;
130 tony 45
131 tony 47 if FUnconfirmedCharacterSet and (FCharSetID > 1) and FAttachment.HasDefaultCharSet then
132 tony 45 begin
133     FCharSetID := FAttachment.CharSetID;
134     FUnconfirmedCharacterSet := false;
135     end;
136    
137     FHasFullMetaData := true;
138     FHasSubType := true;
139     end;
140    
141     constructor TFB30BlobMetaData.Create(Attachment: TFB30Attachment;
142 tony 56 Transaction: TFB30Transaction; RelationName, ColumnName: AnsiString);
143 tony 45 begin
144     inherited Create(Transaction,RelationName,ColumnName);
145     FAttachment := Attachment;
146     FTransaction := Transaction;
147     end;
148    
149     constructor TFB30BlobMetaData.Create(Attachment: TFB30Attachment;
150 tony 56 Transaction: TFB30Transaction; RelationName, ColumnName: AnsiString;
151 tony 45 SubType: integer);
152     begin
153     Create(Attachment,Transaction,RelationName,ColumnName);
154     FSubType := SubType;
155     FHasSubType := true;
156     end;
157    
158     { TFB30Blob }
159    
160     procedure TFB30Blob.CheckReadable;
161     begin
162     if FCreating or (FBlobIntf = nil) then
163     IBError(ibxeBlobCannotBeRead, [nil]);
164     end;
165    
166     procedure TFB30Blob.CheckWritable;
167     begin
168     if not FCreating or (FBlobIntf = nil) then
169     IBError(ibxeBlobCannotBeWritten, [nil]);
170     end;
171    
172     function TFB30Blob.GetIntf: IBlob;
173     begin
174     Result := self;
175     end;
176    
177 tony 56 procedure TFB30Blob.GetInfo(Request: array of byte; Response: IBlobInfo);
178     begin
179     if FBlobIntf = nil then
180     IBError(ibxeBlobNotOpen,[nil]);
181    
182     with Firebird30ClientAPI, Response as TBlobInfo do
183     begin
184     FBlobIntf.getInfo(StatusIntf,Length(Request),BytePtr(@Request),
185     GetBufSize, BytePtr(Buffer));
186     Check4DataBaseError;
187     SignalActivity;
188     end;
189     end;
190    
191 tony 45 procedure TFB30Blob.InternalClose(Force: boolean);
192     begin
193     if FBlobIntf = nil then
194     Exit;
195     with Firebird30ClientAPI do
196     begin
197     FBlobIntf.close(StatusIntf);
198     if not Force then Check4DataBaseError;
199     end;
200     FBlobIntf.release;
201     FBlobIntf := nil;
202     end;
203    
204     procedure TFB30Blob.InternalCancel(Force: boolean);
205     begin
206     if FBlobIntf = nil then
207     Exit;
208     with Firebird30ClientAPI do
209     begin
210     FBlobIntf.cancel(StatusIntf);
211     if not Force then Check4DataBaseError;
212     end;
213     FBlobIntf.release;
214     FBlobIntf := nil;
215     end;
216    
217     constructor TFB30Blob.Create(Attachment: TFB30Attachment; Transaction: TFB30Transaction;
218     MetaData: IBlobMetaData; BPB: IBPB);
219     begin
220     inherited Create(Attachment,Transaction,MetaData,BPB);
221     with Firebird30ClientAPI do
222     begin
223     if BPB = nil then
224     FBlobIntf := Attachment.AttachmentIntf.createBlob(StatusIntf,Transaction.TransactionIntf,
225     @FBlobID,0,nil)
226     else
227     with BPB as TBPB do
228     FBlobIntf := Attachment.AttachmentIntf.createBlob(StatusIntf,Transaction.TransactionIntf,
229     @FBlobID,getDataLength, BytePtr(getBuffer));
230     Check4DataBaseError;
231     end;
232     end;
233    
234     constructor TFB30Blob.Create(Attachment: TFB30Attachment;
235     Transaction: TFB30Transaction; SubType: integer; CharSetID: cardinal;
236     BPB: IBPB);
237     var MetaData: TFB30BlobMetaData;
238     begin
239     MetaData := TFB30BlobMetaData.Create(Attachment,Transaction,'','',SubType);
240     MetaData.FCharSetID := CharSetID;
241     MetaData.FHasFullMetaData := true;
242     inherited Create(Attachment,Transaction,MetaData,BPB);
243     with Firebird30ClientAPI do
244     begin
245     if BPB = nil then
246     FBlobIntf := Attachment.AttachmentIntf.createBlob(StatusIntf,Transaction.TransactionIntf,
247     @FBlobID,0,nil)
248     else
249     with BPB as TBPB do
250     FBlobIntf := Attachment.AttachmentIntf.createBlob(StatusIntf,Transaction.TransactionIntf,
251     @FBlobID,getDataLength, BytePtr(getBuffer));
252     Check4DataBaseError;
253     end;
254     end;
255    
256     constructor TFB30Blob.Create(Attachment: TFB30Attachment;
257     Transaction: TFBTransaction; MetaData: IBlobMetaData; BlobID: TISC_QUAD; BPB: IBPB);
258     begin
259     inherited Create(Attachment,Transaction,MetaData,BlobID,BPB);
260     if (BlobID.gds_quad_high = 0) and (BlobID.gds_quad_low = 0) then
261     Exit;
262    
263     with Firebird30ClientAPI do
264     begin
265     if BPB = nil then
266     FBlobIntf := Attachment.AttachmentIntf.openBlob(StatusIntf,(Transaction as TFB30Transaction).TransactionIntf,
267     @FBlobID, 0, nil)
268     else
269     with BPB as TBPB do
270     FBlobIntf := Attachment.AttachmentIntf.openBlob(StatusIntf,(Transaction as TFB30Transaction).TransactionIntf,
271     @FBlobID, getDataLength, BytePtr(getBuffer));
272     Check4DataBaseError;
273     end;
274     end;
275    
276     function TFB30Blob.Read(var Buffer; Count: Longint): Longint;
277     var
278     BytesRead : cardinal;
279 tony 56 LocalBuffer: PAnsiChar;
280 tony 45 returnCode: integer;
281     localCount: uShort;
282     begin
283     CheckReadable;
284     Result := 0;
285     if FEOB then
286     Exit;
287    
288 tony 56 LocalBuffer := PAnsiChar(@Buffer);
289 tony 45 repeat
290 tony 47 localCount := Min(Count,MaxuShort);
291 tony 45 with Firebird30ClientAPI do
292     returnCode := FBlobIntf.getSegment(StatusIntf,localCount, LocalBuffer, @BytesRead);
293     SignalActivity;
294     Inc(LocalBuffer,BytesRead);
295     Inc(Result,BytesRead);
296     Dec(Count,BytesRead);
297     until ((returncode <> Firebird.IStatus.Result_OK) and (returnCode <> Firebird.IStatus.Result_SEGMENT)) or (Count = 0);
298    
299     FEOB := returnCode = Firebird.IStatus.RESULT_NO_DATA;
300     ClearStringCache;
301     if (returnCode <> Firebird.IStatus.Result_OK) and
302     (returnCode <> Firebird.IStatus.Result_SEGMENT) and
303     (returnCode <> Firebird.IStatus.RESULT_NO_DATA) then
304     Firebird30ClientAPI.IBDataBaseError
305     end;
306    
307     function TFB30Blob.Write(const Buffer; Count: Longint): Longint;
308 tony 47 var
309 tony 56 LocalBuffer: PAnsiChar;
310 tony 47 localCount: uShort;
311 tony 45 begin
312     CheckWritable;
313     Result := 0;
314     if Count = 0 then Exit;
315    
316 tony 56 LocalBuffer := PAnsiChar(@Buffer);
317 tony 47 repeat
318     localCount := Min(Count,MaxuShort);
319     with Firebird30ClientAPI do
320     begin
321     FBlobIntf.putSegment(StatusIntf,localCount,LocalBuffer);
322     Check4DataBaseError;
323     end;
324     Inc(LocalBuffer,localCount);
325     Inc(Result,localCount);
326     Dec(Count,localCount);
327     until Count = 0;
328 tony 45 ClearStringCache;
329     SignalActivity;
330     end;
331    
332     end.
333