ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/runtime/IBBlob.pas
(Generate patch)

Comparing ibx/trunk/runtime/IBBlob.pas (file contents):
Revision 40 by tony, Tue Jan 26 14:38:47 2016 UTC vs.
Revision 41 by tony, Sat Jul 16 12:25:48 2016 UTC

# Line 32 | Line 32
32  
33   unit IBBlob;
34  
35 < {$Mode Delphi}
35 > {$mode Delphi}
36  
37   interface
38  
# Line 41 | Line 41 | uses
41  
42  
43   const
44 <  DefaultBlobSegmentSize = 16 * 1024;
44 >  DefaultBlobSegmentSize = 16 * 1024;
45  
46   type
47 +  TIBBlobStates = (bsUninitialised, bsDataPending, bsData, bsModified);
48 +
49    { TIBBlobStream }
50    TIBBlobStream = class(TStream)
51    private
# Line 54 | Line 56 | type
56      FBlobSize: Int64;
57      FBlobType: Short;  { 0 = segmented, 1 = streamed }
58      FBuffer: PChar;
57    FBlobInitialized: Boolean;
59      FHandle: TISC_BLOB_HANDLE;
60      FMode: TBlobStreamMode;
60    FModified: Boolean;
61      FPosition: Int64;
62 +    FBlobState: TIBBlobStates;
63 +    function GetModified: Boolean;
64    protected
65      procedure CloseBlob;
66      procedure CreateBlob;
67      procedure EnsureBlobInitialized;
68 +    procedure EnsureLoaded;
69      procedure GetBlobInfo;
70 +    function  GetSize: Int64; override;
71      function GetDatabase: TIBDatabase;
72      function GetDBHandle: PISC_DB_HANDLE;
73      function GetTransaction: TIBTransaction;
# Line 72 | Line 76 | type
76      procedure SetBlobID(Value: TISC_QUAD);
77      procedure SetDatabase(Value: TIBDatabase);
78      procedure SetMode(Value: TBlobStreamMode);
79 +    procedure SetState(aValue: TIBBlobStates);
80      procedure SetTransaction(Value: TIBTransaction);
81    public
82      constructor Create;
# Line 94 | Line 99 | type
99      property BlobID: TISC_QUAD read FBlobID write SetBlobID;
100      property BlobMaxSegmentSize: Int64 read FBlobMaxSegmentSize;
101      property BlobNumSegments: Int64 read FBlobNumSegments;
102 <    property BlobSize: Int64 read FBlobSize;
102 >    property BlobSize: Int64 read GetSize;
103      property BlobType: Short read FBlobType;
104      property Database: TIBDatabase read GetDatabase write SetDatabase;
105      property DBHandle: PISC_DB_HANDLE read GetDBHandle;
106      property Mode: TBlobStreamMode read FMode write SetMode;
107 <    property Modified: Boolean read FModified;
107 >    property Modified: Boolean read GetModified;
108      property Transaction: TIBTransaction read GetTransaction write SetTransaction;
109      property TRHandle: PISC_TR_HANDLE read GetTRHandle;
110    end;
# Line 213 | Line 218 | begin
218    FBase := TIBBase.Create(Self);
219    FBuffer := nil;
220    FBlobSize := 0;
221 +  FBlobState := bsUninitialised;
222   end;
223  
224   destructor TIBBlobStream.Destroy;
225   begin
226 <  if (FHandle <> nil) and
221 <     (Call(isc_close_blob(StatusVector, @FHandle), False) > 0) then
222 <    IBDataBaseError;
226 >  SetState(bsUninitialised);
227    FBase.Free;
228    SetSize(0);
229    inherited Destroy;
# Line 244 | Line 248 | begin
248    if FMode = bmRead then IBError(ibxeBlobCannotBeWritten, [nil]);
249   end;
250  
251 + function TIBBlobStream.GetModified: Boolean;
252 + begin
253 +  Result := FBlobState = bsModified;
254 + end;
255 +
256   procedure TIBBlobStream.CloseBlob;
257   begin
258    Finalize;
259 <  if (FHandle <> nil) and
251 <     (Call(isc_close_blob(StatusVector, @FHandle), False) > 0) then
252 <    IBDataBaseError;
259 >  SetState(bsUninitialised);
260   end;
261  
262   procedure TIBBlobStream.CreateBlob;
# Line 257 | Line 264 | begin
264    CheckWritable;
265    FBlobID.gds_quad_high := 0;
266    FBlobID.gds_quad_low := 0;
267 <  Truncate;
267 >  SetState(bsData);
268 >  SetSize(0);
269   end;
270  
271   procedure TIBBlobStream.EnsureBlobInitialized;
272   begin
273 <  if not FBlobInitialized then
273 >  if FBlobState = bsUninitialised then
274      case FMode of
275        bmWrite:
276          CreateBlob;
# Line 276 | Line 284 | begin
284        else
285          OpenBlob;
286      end;
287 <  FBlobInitialized := True;
287 > end;
288 >
289 > procedure TIBBlobStream.EnsureLoaded;
290 > begin
291 >  EnsureBlobInitialized;
292 >  if FBlobState = bsDataPending then
293 >  begin
294 >    SetSize(FBlobSize);
295 >    try
296 >      IBBlob.ReadBlob(@FHandle, FBuffer, FBlobSize);
297 >    except
298 >      Call(isc_close_blob(StatusVector, @FHandle), False);
299 >      raise;
300 >    end;
301 >    SetState(bsData);
302 >  end;
303   end;
304  
305   procedure TIBBlobStream.Finalize;
306   begin
307 <  if (not FBlobInitialized) or (FMode = bmRead) or (not FModified) then
307 >  if FBlobState <> bsModified then
308      exit;
309 <  { need to start writing to a blob, create one }
310 <  Call(isc_create_blob2(StatusVector, DBHandle, TRHandle, @FHandle, @FBlobID,
311 <                       0, nil), True);
312 <  IBBlob.WriteBlob(@FHandle, FBuffer, FBlobSize);
313 <  Call(isc_close_blob(StatusVector, @FHandle), True);
314 <  FModified := False;
309 >  if FBlobSize > 0 then
310 >  begin
311 >    { need to start writing to a blob, create one }
312 >    Call(isc_create_blob2(StatusVector, DBHandle, TRHandle, @FHandle, @FBlobID,
313 >                         0, nil), True);
314 >    IBBlob.WriteBlob(@FHandle, FBuffer, FBlobSize);
315 >    Call(isc_close_blob(StatusVector, @FHandle), True);
316 >  end
317 >  else
318 >  begin
319 >    FBlobID.gds_quad_high := 0;
320 >    FBlobID.gds_quad_low := 0;
321 >  end;
322 >  SetState(bsData);
323   end;
324  
325   procedure TIBBlobStream.GetBlobInfo;
# Line 300 | Line 331 | begin
331    SetSize(iBlobSize);
332   end;
333  
334 + function TIBBlobStream.GetSize: Int64;
335 + begin
336 +  EnsureBlobInitialized;
337 +  Result := FBlobSize;
338 + end;
339 +
340   function TIBBlobStream.GetDatabase: TIBDatabase;
341   begin
342    result := FBase.Database;
# Line 340 | Line 377 | begin
377    SetSize(Stream.Size);
378    if FBlobSize <> 0 then
379      Stream.ReadBuffer(FBuffer^, FBlobSize);
380 <  FModified := True;
380 >  SetState(bsModified);
381   end;
382  
383   procedure TIBBlobStream.OpenBlob;
# Line 350 | Line 387 | begin
387                       @FBlobID, 0, nil), True);
388    try
389      GetBlobInfo;
390 <    SetSize(FBlobSize);
354 <    IBBlob.ReadBlob(@FHandle, FBuffer, FBlobSize);
390 >    {Defer reading in blob until read method called}
391    except
392      Call(isc_close_blob(StatusVector, @FHandle), False);
393      raise;
394    end;
395 <  Call(isc_close_blob(StatusVector, @FHandle), True);
395 >  SetState(bsDataPending);
396   end;
397  
398   function TIBBlobStream.Read(var Buffer; Count: Longint): Longint;
399   begin
400    CheckReadable;
401 <  EnsureBlobInitialized;
401 >  EnsureLoaded;
402    if (Count <= 0) then
403    begin
404      result := 0;
# Line 391 | Line 427 | end;
427   procedure TIBBlobStream.SaveToStream(Stream: TStream);
428   begin
429    CheckReadable;
430 <  EnsureBlobInitialized;
430 >  EnsureLoaded;
431    if FBlobSize <> 0 then
432    begin
433      Seek(0, soFromBeginning);
# Line 413 | Line 449 | end;
449   procedure TIBBlobStream.SetBlobID(Value: TISC_QUAD);
450   begin
451    System.Move(Value, FBlobID, SizeOf(TISC_QUAD));
452 <  FBlobInitialized := False;
452 >  SetState(bsUninitialised);
453   end;
454  
455   procedure TIBBlobStream.SetDatabase(Value: TIBDatabase);
456   begin
457    FBase.Database := Value;
458 <  FBlobInitialized := False;
458 >  SetState(bsUninitialised);
459   end;
460  
461   procedure TIBBlobStream.SetMode(Value: TBlobStreamMode);
462   begin
463    FMode := Value;
464 <  FBlobInitialized := False;
464 >  SetState(bsUninitialised);
465 > end;
466 >
467 > procedure TIBBlobStream.SetState(aValue: TIBBlobStates);
468 > begin
469 >  if FBlobState = aValue then Exit;
470 >
471 >  if FBlobState = bsDataPending then
472 >    Call(isc_close_blob(StatusVector, @FHandle), True);
473 >
474 >  FBlobState := aValue;
475   end;
476  
477   procedure TIBBlobStream.SetSize(const NewSize: Int64);
# Line 447 | Line 493 | end;
493   procedure TIBBlobStream.SetTransaction(Value: TIBTransaction);
494   begin
495    FBase.Transaction := Value;
496 <  FBlobInitialized := False;
496 >  SetState(bsUninitialised);
497   end;
498  
499   procedure TIBBlobStream.Truncate;
500   begin
501    SetSize(0);
502 +  SetState(bsModified);
503   end;
504  
505   function TIBBlobStream.Write(const Buffer; Count: Longint): Longint;
506   begin
507    CheckWritable;
508 <  EnsureBlobInitialized;
508 >  EnsureLoaded;  {Could be an untruncated bmReadWrite Blob}
509    result := Count;
510    if Count <= 0 then
511      exit;
# Line 466 | Line 513 | begin
513      SetSize(FPosition + Count);
514    Move(Buffer, FBuffer[FPosition], Count);
515    Inc(FPosition, Count);
516 <  FModified := True;
516 >  SetState(bsModified);
517   end;
518  
519   end.

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines