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, 1 month ago) by tony
Content type: text/x-pascal
File size: 10003 byte(s)
Log Message:
Committing updates for Trunk

File Contents

# Content
1 (*
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 {$IFDEF MSWINDOWS}
29 {$DEFINE WINDOWS}
30 {$ENDIF}
31
32 {$IFDEF FPC}
33 {$mode delphi}
34 {$interfaces COM}
35 {$ENDIF}
36
37 interface
38
39 uses
40 Classes, SysUtils, Firebird, IB, IBHeader, IBExternals, FBClientAPI, FB30ClientAPI, FB30Attachment,
41 FBTransaction, FB30Transaction, FBBlob, FBOutputBlock;
42
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 RelationName, ColumnName: AnsiString); overload;
57 constructor Create(Attachment: TFB30Attachment; Transaction: TFB30Transaction;
58 RelationName, ColumnName: AnsiString; SubType: integer); overload;
59
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 procedure GetInfo(Request: array of byte; Response: IBlobInfo); override;
74 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 uses FBMessages, FB30Statement, FBParamBlock, Math;
94
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 if FUnconfirmedCharacterSet then
123 FCharSetID := Data[2].AsInteger;
124 end
125 else
126 IBError(ibxeInvalidBlobMetaData,[nil]);
127
128 end;
129 end;
130
131 if FUnconfirmedCharacterSet and (FCharSetID > 1) and FAttachment.HasDefaultCharSet then
132 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 Transaction: TFB30Transaction; RelationName, ColumnName: AnsiString);
143 begin
144 inherited Create(Transaction,RelationName,ColumnName);
145 FAttachment := Attachment;
146 FTransaction := Transaction;
147 end;
148
149 constructor TFB30BlobMetaData.Create(Attachment: TFB30Attachment;
150 Transaction: TFB30Transaction; RelationName, ColumnName: AnsiString;
151 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 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 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 LocalBuffer: PAnsiChar;
280 returnCode: integer;
281 localCount: uShort;
282 begin
283 CheckReadable;
284 Result := 0;
285 if FEOB then
286 Exit;
287
288 LocalBuffer := PAnsiChar(@Buffer);
289 repeat
290 localCount := Min(Count,MaxuShort);
291 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 var
309 LocalBuffer: PAnsiChar;
310 localCount: uShort;
311 begin
312 CheckWritable;
313 Result := 0;
314 if Count = 0 then Exit;
315
316 LocalBuffer := PAnsiChar(@Buffer);
317 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 ClearStringCache;
329 SignalActivity;
330 end;
331
332 end.
333