@@ -215,6 +215,8 @@ class Blob final : public RefCntIface<IBlobImpl<Blob, CheckStatusWrapper> >
215
215
void freeClientData (CheckStatusWrapper* status, bool force = false );
216
216
void internalCancel (CheckStatusWrapper* status);
217
217
void internalClose (CheckStatusWrapper* status);
218
+ // seek in cached blob
219
+ int seekCached (int mode, int offset);
218
220
219
221
Rbl* blob;
220
222
};
@@ -6863,36 +6865,7 @@ int Blob::seek(CheckStatusWrapper* status, int mode, int offset)
6863
6865
CHECK_HANDLE (blob, isc_bad_segstr_handle);
6864
6866
6865
6867
if (blob->isCached ())
6866
- {
6867
- // Segmented blobs does not support seek
6868
- if (blob->rbl_info .blob_type == 0 )
6869
- Arg::Gds (isc_bad_segstr_type).raise ();
6870
-
6871
- if (mode == 1 ) // seek from current position
6872
- offset += blob->rbl_offset ;
6873
- else if (mode == 2 ) // seek from end of blob
6874
- offset = blob->rbl_info .total_length + offset;
6875
-
6876
- if (offset < 0 )
6877
- offset = 0 ;
6878
-
6879
- if (offset > blob->rbl_info .total_length )
6880
- offset = blob->rbl_info .total_length ;
6881
-
6882
- // Assume stream blob with single segment in buffer
6883
- fb_assert (blob->rbl_info .num_segments <= 1 );
6884
- fb_assert (blob->rbl_info .total_length <= MAX_USHORT);
6885
-
6886
- blob->rbl_offset = offset;
6887
- if (!blob->rbl_data .isEmpty ())
6888
- {
6889
- blob->rbl_ptr = blob->rbl_buffer + offset + 2 ;
6890
- blob->rbl_length = blob->rbl_data .end () - blob->rbl_ptr ;
6891
- blob->rbl_fragment_length = blob->rbl_length ;
6892
- }
6893
- blob->rbl_flags &= ~(Rbl::EOF_SET | Rbl::SEGMENT);
6894
- return blob->rbl_offset ;
6895
- }
6868
+ return seekCached (mode, offset);
6896
6869
6897
6870
Rdb* rdb = blob->rbl_rdb ;
6898
6871
CHECK_HANDLE (rdb, isc_bad_db_handle);
@@ -6929,6 +6902,57 @@ int Blob::seek(CheckStatusWrapper* status, int mode, int offset)
6929
6902
}
6930
6903
6931
6904
6905
+ int Blob::seekCached (int mode, int offset)
6906
+ {
6907
+ // Segmented blobs does not support seek
6908
+ if (blob->rbl_info .blob_type == 0 )
6909
+ Arg::Gds (isc_bad_segstr_type).raise ();
6910
+
6911
+ if (mode == 1 ) // seek from current position
6912
+ offset += blob->rbl_offset ;
6913
+ else if (mode == 2 ) // seek from end of blob
6914
+ offset = blob->rbl_info .total_length + offset;
6915
+
6916
+ if (offset < 0 )
6917
+ offset = 0 ;
6918
+
6919
+ // Engine allows to set seek position to the total length of the blob,
6920
+ // but it's not documented and seems to be wrong. See blb::BLB_lseek().
6921
+ // Here this behavior is supported for compatibility with the engine.
6922
+ if (offset > blob->rbl_info .total_length )
6923
+ offset = blob->rbl_info .total_length ;
6924
+
6925
+ fb_assert (blob->rbl_info .total_length <= MAX_USHORT);
6926
+
6927
+ blob->rbl_offset = offset;
6928
+ if (!blob->rbl_data .isEmpty ())
6929
+ {
6930
+ if (offset == blob->rbl_info .total_length )
6931
+ {
6932
+ blob->rbl_ptr = blob->rbl_data .end ();
6933
+ blob->rbl_fragment_length = blob->rbl_length = 0 ;
6934
+ }
6935
+ else
6936
+ {
6937
+ const auto seg = offset / blob->rbl_info .max_segment + 1 ;
6938
+ fb_assert (seg <= blob->rbl_info .num_segments );
6939
+
6940
+ blob->rbl_ptr = blob->rbl_buffer + offset + 2 * seg;
6941
+ fb_assert (blob->rbl_ptr < blob->rbl_data .end ());
6942
+
6943
+ blob->rbl_length = blob->rbl_data .end () - blob->rbl_ptr ;
6944
+
6945
+ if (seg < blob->rbl_info .num_segments )
6946
+ blob->rbl_fragment_length = blob->rbl_info .max_segment - offset % blob->rbl_info .max_segment ;
6947
+ else
6948
+ blob->rbl_fragment_length = blob->rbl_length ;
6949
+ }
6950
+ }
6951
+
6952
+ blob->rbl_flags &= ~(Rbl::EOF_SET | Rbl::SEGMENT);
6953
+ return blob->rbl_offset ;
6954
+ }
6955
+
6932
6956
void Request::send (CheckStatusWrapper* status, int level, unsigned int msg_type,
6933
6957
unsigned int /* length*/ , const void * msg)
6934
6958
{
0 commit comments