ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/runtime/IBBlob.pas
Revision: 35
Committed: Tue Jan 26 14:38:47 2016 UTC (8 years, 9 months ago) by tony
Content type: text/x-pascal
File size: 13870 byte(s)
Log Message:
Committing updates for Release R1-3-2

File Contents

# User Rev Content
1 tony 33 {************************************************************************}
2     { }
3     { Borland Delphi Visual Component Library }
4     { InterBase Express core components }
5     { }
6     { Copyright (c) 1998-2000 Inprise Corporation }
7     { }
8     { InterBase Express is based in part on the product }
9     { Free IB Components, written by Gregory H. Deatz for }
10     { Hoagland, Longo, Moran, Dunst & Doukas Company. }
11     { Free IB Components is used under license. }
12     { }
13     { The contents of this file are subject to the InterBase }
14     { Public License Version 1.0 (the "License"); you may not }
15     { use this file except in compliance with the License. You }
16     { may obtain a copy of the License at http://www.Inprise.com/IPL.html }
17     { Software distributed under the License is distributed on }
18     { an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either }
19     { express or implied. See the License for the specific language }
20     { governing rights and limitations under the License. }
21     { The Original Code was created by InterBase Software Corporation }
22     { and its successors. }
23     { Portions created by Inprise Corporation are Copyright (C) Inprise }
24     { Corporation. All Rights Reserved. }
25     { Contributor(s): Jeff Overcash }
26     { }
27     { IBX For Lazarus (Firebird Express) }
28     { Contributor: Tony Whyman, MWA Software http://www.mwasoftware.co.uk }
29     { Portions created by MWA Software are copyright McCallum Whyman }
30     { Associates Ltd 2011 }
31     {************************************************************************}
32    
33     unit IBBlob;
34    
35     {$Mode Delphi}
36    
37     interface
38    
39     uses
40     SysUtils, Classes, IBHeader, IBErrorCodes, IBExternals, DB, IB, IBDatabase;
41    
42    
43     const
44     DefaultBlobSegmentSize = 16 * 1024;
45    
46     type
47     { TIBBlobStream }
48     TIBBlobStream = class(TStream)
49     private
50     FBase: TIBBase;
51     FBlobID: TISC_QUAD;
52     FBlobMaxSegmentSize: Int64;
53     FBlobNumSegments: Int64;
54     FBlobSize: Int64;
55     FBlobType: Short; { 0 = segmented, 1 = streamed }
56     FBuffer: PChar;
57     FBlobInitialized: Boolean;
58     FHandle: TISC_BLOB_HANDLE;
59     FMode: TBlobStreamMode;
60     FModified: Boolean;
61     FPosition: Int64;
62     protected
63     procedure CloseBlob;
64     procedure CreateBlob;
65     procedure EnsureBlobInitialized;
66     procedure GetBlobInfo;
67     function GetDatabase: TIBDatabase;
68     function GetDBHandle: PISC_DB_HANDLE;
69     function GetTransaction: TIBTransaction;
70     function GetTRHandle: PISC_TR_HANDLE;
71     procedure OpenBlob;
72     procedure SetBlobID(Value: TISC_QUAD);
73     procedure SetDatabase(Value: TIBDatabase);
74     procedure SetMode(Value: TBlobStreamMode);
75     procedure SetTransaction(Value: TIBTransaction);
76     public
77     constructor Create;
78     destructor Destroy; override;
79     function Call(ErrCode: ISC_STATUS; RaiseError: Boolean): ISC_STATUS;
80     procedure CheckReadable;
81     procedure CheckWritable;
82     procedure Finalize;
83     procedure LoadFromFile(Filename: string);
84     procedure LoadFromStream(Stream: TStream);
85     function Read(var Buffer; Count: Longint): Longint; override;
86     procedure SaveToFile(Filename: string);
87     procedure SaveToStream(Stream: TStream);
88     function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;
89     procedure SetSize(const NewSize: Int64); override;
90     procedure SetSize(NewSize: Longint); override;
91     procedure Truncate;
92     function Write(const Buffer; Count: Longint): Longint; override;
93     property Handle: TISC_BLOB_HANDLE read FHandle;
94     property BlobID: TISC_QUAD read FBlobID write SetBlobID;
95     property BlobMaxSegmentSize: Int64 read FBlobMaxSegmentSize;
96     property BlobNumSegments: Int64 read FBlobNumSegments;
97     property BlobSize: Int64 read FBlobSize;
98     property BlobType: Short read FBlobType;
99     property Database: TIBDatabase read GetDatabase write SetDatabase;
100     property DBHandle: PISC_DB_HANDLE read GetDBHandle;
101     property Mode: TBlobStreamMode read FMode write SetMode;
102     property Modified: Boolean read FModified;
103     property Transaction: TIBTransaction read GetTransaction write SetTransaction;
104     property TRHandle: PISC_TR_HANDLE read GetTRHandle;
105     end;
106    
107     procedure GetBlobInfo(hBlobHandle: PISC_BLOB_HANDLE; var NumSegments: Int64; var MaxSegmentSize,
108     TotalSize: Int64; var BlobType: Short);
109 tony 35 function GetBlobCharSetID(hDB_Handle: TISC_DB_HANDLE; hTR_Handle: TISC_TR_HANDLE;
110     tableName, columnName: PChar): short;
111 tony 33 procedure ReadBlob(hBlobHandle: PISC_BLOB_HANDLE; Buffer: PChar; BlobSize: Int64);
112     procedure WriteBlob(hBlobHandle: PISC_BLOB_HANDLE; Buffer: PChar; BlobSize: Int64);
113    
114     implementation
115    
116     uses IBIntf;
117    
118     procedure GetBlobInfo(hBlobHandle: PISC_BLOB_HANDLE; var NumSegments: Int64; var MaxSegmentSize,
119     TotalSize: Int64; var BlobType: Short);
120     var
121     items: array[0..3] of Char;
122     results: array[0..99] of Char;
123     i, item_length: Integer;
124     item: Integer;
125     begin
126     items[0] := Char(isc_info_blob_num_segments);
127     items[1] := Char(isc_info_blob_max_segment);
128     items[2] := Char(isc_info_blob_total_length);
129     items[3] := Char(isc_info_blob_type);
130    
131     if isc_blob_info(StatusVector, hBlobHandle, 4, @items[0], SizeOf(results),
132     @results[0]) > 0 then
133     IBDatabaseError;
134    
135     i := 0;
136     while (i < SizeOf(results)) and (results[i] <> Char(isc_info_end)) do
137     begin
138     item := Integer(results[i]); Inc(i);
139     item_length := isc_vax_integer(@results[i], 2); Inc(i, 2);
140     case item of
141     isc_info_blob_num_segments:
142     NumSegments := isc_portable_integer(@results[i], item_length);
143     isc_info_blob_max_segment:
144     MaxSegmentSize := isc_portable_integer(@results[i], item_length);
145     isc_info_blob_total_length:
146     TotalSize := isc_portable_integer(@results[i], item_length);
147     isc_info_blob_type:
148     BlobType := isc_portable_integer(@results[i], item_length);
149     end;
150     Inc(i, item_length);
151     end;
152     end;
153    
154 tony 35 function GetBlobCharSetID(hDB_Handle: TISC_DB_HANDLE;
155     hTR_Handle: TISC_TR_HANDLE; tableName, columnName: PChar): short;
156     var desc: TISC_BLOB_DESC;
157     uGlobal: array [0..31] of char;
158     begin
159     if isc_blob_lookup_desc(StatusVector,@hDB_Handle,@hTR_Handle,
160     tableName,columnName,@desc,@uGlobal) > 0 then
161     IBDatabaseError;
162    
163     Result := desc.blob_desc_charset;
164     end;
165    
166 tony 33 procedure ReadBlob(hBlobHandle: PISC_BLOB_HANDLE; Buffer: PChar; BlobSize: Int64);
167     var
168     CurPos: Int64;
169     BytesRead, SegLen: UShort;
170     LocalBuffer: PChar;
171     begin
172     CurPos := 0;
173     LocalBuffer := Buffer;
174     SegLen := UShort(DefaultBlobSegmentSize);
175     while (CurPos < BlobSize) do
176     begin
177     if (CurPos + SegLen > BlobSize) then
178     SegLen := BlobSize - CurPos;
179     if not ((isc_get_segment(StatusVector, hBlobHandle, @BytesRead, SegLen,
180     LocalBuffer) = 0) or
181     (StatusVectorArray[1] = isc_segment)) then
182     IBDatabaseError;
183     Inc(LocalBuffer, BytesRead);
184     Inc(CurPos, BytesRead);
185     BytesRead := 0;
186     end;
187     end;
188    
189     procedure WriteBlob(hBlobHandle: PISC_BLOB_HANDLE; Buffer: PChar;
190     BlobSize: Int64);
191     var
192     CurPos: Int64;
193     SegLen: Long;
194     begin
195     CurPos := 0;
196     SegLen := DefaultBlobSegmentSize;
197     while (CurPos < BlobSize) do
198     begin
199     if (CurPos + SegLen > BlobSize) then
200     SegLen := BlobSize - CurPos;
201     if isc_put_segment(StatusVector, hBlobHandle, SegLen,
202     PChar(@Buffer[CurPos])) > 0 then
203     IBDatabaseError;
204     Inc(CurPos, SegLen);
205     end;
206     end;
207    
208    
209     { TIBBlobStream }
210     constructor TIBBlobStream.Create;
211     begin
212     inherited Create;
213     FBase := TIBBase.Create(Self);
214     FBuffer := nil;
215     FBlobSize := 0;
216     end;
217    
218     destructor TIBBlobStream.Destroy;
219     begin
220     if (FHandle <> nil) and
221     (Call(isc_close_blob(StatusVector, @FHandle), False) > 0) then
222     IBDataBaseError;
223     FBase.Free;
224     SetSize(0);
225     inherited Destroy;
226     end;
227    
228     function TIBBlobStream.Call(ErrCode: ISC_STATUS; RaiseError: Boolean): ISC_STATUS;
229     begin
230     result := 0;
231     if Transaction <> nil then
232     result := Transaction.Call(ErrCode, RaiseError)
233     else if RaiseError and (ErrCode > 0) then
234     IBDataBaseError;
235     end;
236    
237     procedure TIBBlobStream.CheckReadable;
238     begin
239     if FMode = bmWrite then IBError(ibxeBlobCannotBeRead, [nil]);
240     end;
241    
242     procedure TIBBlobStream.CheckWritable;
243     begin
244     if FMode = bmRead then IBError(ibxeBlobCannotBeWritten, [nil]);
245     end;
246    
247     procedure TIBBlobStream.CloseBlob;
248     begin
249     Finalize;
250     if (FHandle <> nil) and
251     (Call(isc_close_blob(StatusVector, @FHandle), False) > 0) then
252     IBDataBaseError;
253     end;
254    
255     procedure TIBBlobStream.CreateBlob;
256     begin
257     CheckWritable;
258     FBlobID.gds_quad_high := 0;
259     FBlobID.gds_quad_low := 0;
260     Truncate;
261     end;
262    
263     procedure TIBBlobStream.EnsureBlobInitialized;
264     begin
265     if not FBlobInitialized then
266     case FMode of
267     bmWrite:
268     CreateBlob;
269     bmReadWrite: begin
270     if (FBlobID.gds_quad_high = 0) and
271     (FBlobID.gds_quad_low = 0) then
272     CreateBlob
273     else
274     OpenBlob;
275     end;
276     else
277     OpenBlob;
278     end;
279     FBlobInitialized := True;
280     end;
281    
282     procedure TIBBlobStream.Finalize;
283     begin
284     if (not FBlobInitialized) or (FMode = bmRead) or (not FModified) then
285     exit;
286     { need to start writing to a blob, create one }
287     Call(isc_create_blob2(StatusVector, DBHandle, TRHandle, @FHandle, @FBlobID,
288     0, nil), True);
289     IBBlob.WriteBlob(@FHandle, FBuffer, FBlobSize);
290     Call(isc_close_blob(StatusVector, @FHandle), True);
291     FModified := False;
292     end;
293    
294     procedure TIBBlobStream.GetBlobInfo;
295     var
296     iBlobSize: Int64;
297     begin
298     IBBlob.GetBlobInfo(@FHandle, FBlobNumSegments, FBlobMaxSegmentSize,
299     iBlobSize, FBlobType);
300     SetSize(iBlobSize);
301     end;
302    
303     function TIBBlobStream.GetDatabase: TIBDatabase;
304     begin
305     result := FBase.Database;
306     end;
307    
308     function TIBBlobStream.GetDBHandle: PISC_DB_HANDLE;
309     begin
310     result := FBase.DBHandle;
311     end;
312    
313     function TIBBlobStream.GetTransaction: TIBTransaction;
314     begin
315     result := FBase.Transaction;
316     end;
317    
318     function TIBBlobStream.GetTRHandle: PISC_TR_HANDLE;
319     begin
320     result := FBase.TRHandle;
321     end;
322    
323     procedure TIBBlobStream.LoadFromFile(Filename: string);
324     var
325     Stream: TStream;
326     begin
327     Stream := TFileStream.Create(FileName, fmOpenRead);
328     try
329     LoadFromStream(Stream);
330     finally
331     Stream.Free;
332     end;
333     end;
334    
335     procedure TIBBlobStream.LoadFromStream(Stream: TStream);
336     begin
337     CheckWritable;
338     EnsureBlobInitialized;
339     Stream.Position := 0;
340     SetSize(Stream.Size);
341     if FBlobSize <> 0 then
342     Stream.ReadBuffer(FBuffer^, FBlobSize);
343     FModified := True;
344     end;
345    
346     procedure TIBBlobStream.OpenBlob;
347     begin
348     CheckReadable;
349     Call(isc_open_blob2(StatusVector, DBHandle, TRHandle, @FHandle,
350     @FBlobID, 0, nil), True);
351     try
352     GetBlobInfo;
353     SetSize(FBlobSize);
354     IBBlob.ReadBlob(@FHandle, FBuffer, FBlobSize);
355     except
356     Call(isc_close_blob(StatusVector, @FHandle), False);
357     raise;
358     end;
359     Call(isc_close_blob(StatusVector, @FHandle), True);
360     end;
361    
362     function TIBBlobStream.Read(var Buffer; Count: Longint): Longint;
363     begin
364     CheckReadable;
365     EnsureBlobInitialized;
366     if (Count <= 0) then
367     begin
368     result := 0;
369     exit;
370     end;
371     if (FPosition + Count > FBlobSize) then
372     result := FBlobSize - FPosition
373     else
374     result := Count;
375     Move(FBuffer[FPosition], Buffer, result);
376     Inc(FPosition, Result);
377     end;
378    
379     procedure TIBBlobStream.SaveToFile(Filename: string);
380     var
381     Stream: TStream;
382     begin
383     Stream := TFileStream.Create(FileName, fmCreate);
384     try
385     SaveToStream(Stream);
386     finally
387     Stream.Free;
388     end;
389     end;
390    
391     procedure TIBBlobStream.SaveToStream(Stream: TStream);
392     begin
393     CheckReadable;
394     EnsureBlobInitialized;
395     if FBlobSize <> 0 then
396     begin
397     Seek(0, soFromBeginning);
398     Stream.WriteBuffer(FBuffer^, FBlobSize);
399     end;
400     end;
401    
402     function TIBBlobStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
403     begin
404     EnsureBlobInitialized;
405     case Origin of
406     soBeginning : FPosition := Offset;
407     soCurrent : Inc(FPosition, Offset);
408     soEnd : FPosition := FBlobSize + Offset;
409     end;
410     result := FPosition;
411     end;
412    
413     procedure TIBBlobStream.SetBlobID(Value: TISC_QUAD);
414     begin
415     System.Move(Value, FBlobID, SizeOf(TISC_QUAD));
416     FBlobInitialized := False;
417     end;
418    
419     procedure TIBBlobStream.SetDatabase(Value: TIBDatabase);
420     begin
421     FBase.Database := Value;
422     FBlobInitialized := False;
423     end;
424    
425     procedure TIBBlobStream.SetMode(Value: TBlobStreamMode);
426     begin
427     FMode := Value;
428     FBlobInitialized := False;
429     end;
430    
431     procedure TIBBlobStream.SetSize(const NewSize: Int64);
432     begin
433     if (NewSize <> FBlobSize) then
434     begin
435     ReallocMem(FBuffer, NewSize);
436     FBlobSize := NewSize;
437     if NewSize = 0 then
438     FBuffer := nil;
439     end;
440     end;
441    
442     procedure TIBBlobStream.SetSize(NewSize: Longint);
443     begin
444     SetSize(Int64(NewSize));
445     end;
446    
447     procedure TIBBlobStream.SetTransaction(Value: TIBTransaction);
448     begin
449     FBase.Transaction := Value;
450     FBlobInitialized := False;
451     end;
452    
453     procedure TIBBlobStream.Truncate;
454     begin
455     SetSize(0);
456     end;
457    
458     function TIBBlobStream.Write(const Buffer; Count: Longint): Longint;
459     begin
460     CheckWritable;
461     EnsureBlobInitialized;
462     result := Count;
463     if Count <= 0 then
464     exit;
465     if (FPosition + Count > FBlobSize) then
466     SetSize(FPosition + Count);
467     Move(Buffer, FBuffer[FPosition], Count);
468     Inc(FPosition, Count);
469     FModified := True;
470     end;
471    
472     end.