88
99import org .firebirdsql .gds .JaybirdErrorCodes ;
1010import org .firebirdsql .gds .ng .FbExceptionBuilder ;
11+ import org .firebirdsql .jaybird .util .ByteArrayHelper ;
1112import org .firebirdsql .util .InternalApi ;
1213import org .jspecify .annotations .NullMarked ;
1314
@@ -47,8 +48,7 @@ public FBCachedBlob(byte[] data) {
4748
4849 @ Override
4950 public FirebirdBlob detach () throws SQLException {
50- checkOpen ();
51- return new FBCachedBlob (blobData );
51+ return new FBCachedBlob (requireBlobData ());
5252 }
5353
5454 /**
@@ -70,32 +70,31 @@ public boolean isSegmented() throws SQLException {
7070 */
7171 @ Override
7272 public long length () throws SQLException {
73- checkOpen ();
74- return blobData .length ;
73+ return requireBlobData ().length ;
7574 }
7675
7776 @ Override
7877 public byte [] getBytes (long pos , int length ) throws SQLException {
7978 if (pos < 1 ) {
8079 throw new SQLException ("Expected value of pos > 0, got " + pos ,
8180 SQLStateConstants .SQL_STATE_INVALID_STRING_LENGTH );
82- }
83- if (length < 0 ) {
81+ } else if (length < 0 ) {
8482 throw new SQLException ("Expected value of length >= 0, got " + length ,
8583 SQLStateConstants .SQL_STATE_INVALID_STRING_LENGTH );
8684 }
87- checkOpen ();
85+ byte [] blobData = requireBlobData ();
86+
87+ if (pos > blobData .length ) return ByteArrayHelper .emptyByteArray ();
88+ length = (int ) Math .min (length , blobData .length - pos + 1L );
8889
89- // TODO What if pos or length are beyond blobData
9090 byte [] result = new byte [length ];
9191 System .arraycopy (blobData , (int ) pos - 1 , result , 0 , length );
9292 return result ;
9393 }
9494
9595 @ Override
9696 public byte [] getBytes () throws SQLException {
97- checkOpen ();
98- return blobData .clone ();
97+ return requireBlobData ().clone ();
9998 }
10099
101100 /**
@@ -122,8 +121,7 @@ public long position(Blob pattern, long start) throws SQLException {
122121
123122 @ Override
124123 public InputStream getBinaryStream () throws SQLException {
125- checkOpen ();
126- return new ByteArrayInputStream (blobData );
124+ return new ByteArrayInputStream (requireBlobData ());
127125 }
128126
129127 @ Override
@@ -180,9 +178,25 @@ public void free() throws SQLException {
180178 blobData = FREED_MARKER ;
181179 }
182180
181+ /**
182+ * Checks if the blob is open (not freed).
183+ * <p>
184+ * If a method needs access to the blob data, use {@link #requireBlobData()} instead.
185+ * </p>
186+ *
187+ * @see #requireBlobData()
188+ */
183189 private void checkOpen () throws SQLException {
184190 if (blobData == FREED_MARKER ) {
185191 throw FbExceptionBuilder .toException (JaybirdErrorCodes .jb_blobClosed );
186192 }
187193 }
194+
195+ private byte [] requireBlobData () throws SQLException {
196+ byte [] blobData = this .blobData ;
197+ if (blobData == FREED_MARKER ) {
198+ throw FbExceptionBuilder .toException (JaybirdErrorCodes .jb_blobClosed );
199+ }
200+ return blobData ;
201+ }
188202}
0 commit comments