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: 60
Committed: Mon Mar 27 15:21:02 2017 UTC (7 years, 8 months ago) by tony
Content type: text/x-pascal
File size: 10141 byte(s)
Log Message:

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