Skip to content

Commit 7e09784

Browse files
committed
refactor(jdbc): extract LibsqlBlob and LibsqlClob
Move the two read-only Blob and Clob implementations out of LibsqlResultSet into package-private top-level classes. Constructors become package-private so getBlob and getClob can still build them. Pure move: messages, checks, stream encodings, and free() semantics are unchanged. Also drops the four imports that only the moved code used (OutputStream, Writer, StandardCharsets, Arrays).
1 parent 9ee30e6 commit 7e09784

3 files changed

Lines changed: 226 additions & 209 deletions

File tree

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package com.github.magnusp.libsql.jdbc;
2+
3+
import java.io.ByteArrayInputStream;
4+
import java.io.InputStream;
5+
import java.io.OutputStream;
6+
import java.sql.Blob;
7+
import java.sql.SQLException;
8+
import java.sql.SQLFeatureNotSupportedException;
9+
import java.util.Arrays;
10+
11+
/** Read-only {@link Blob} over the materialized bytes of one result column. */
12+
final class LibsqlBlob implements Blob {
13+
14+
private byte[] bytes;
15+
private boolean freed;
16+
17+
LibsqlBlob(byte[] bytes) {
18+
this.bytes = bytes;
19+
}
20+
21+
private byte[] data() throws SQLException {
22+
if (freed) {
23+
throw new SQLException("Blob has been freed");
24+
}
25+
return bytes;
26+
}
27+
28+
@Override
29+
public long length() throws SQLException {
30+
return data().length;
31+
}
32+
33+
@Override
34+
public byte[] getBytes(long pos, int length) throws SQLException {
35+
byte[] data = data();
36+
if (pos < 1) {
37+
throw new SQLException("Invalid position: " + pos);
38+
}
39+
if (length < 0) {
40+
throw new SQLException("Invalid length: " + length);
41+
}
42+
int start = (int) Math.min(pos - 1, data.length);
43+
int end = Math.min(start + length, data.length);
44+
return Arrays.copyOfRange(data, start, end);
45+
}
46+
47+
@Override
48+
public InputStream getBinaryStream() throws SQLException {
49+
return new ByteArrayInputStream(data());
50+
}
51+
52+
@Override
53+
public long position(byte[] pattern, long start) throws SQLException {
54+
if (start < 1) {
55+
throw new SQLException("Invalid position: " + start);
56+
}
57+
byte[] data = data();
58+
int from = (int) Math.min(start - 1, data.length);
59+
for (int i = from; i + pattern.length <= data.length; i++) {
60+
boolean match = true;
61+
for (int j = 0; j < pattern.length; j++) {
62+
if (data[i + j] != pattern[j]) {
63+
match = false;
64+
break;
65+
}
66+
}
67+
if (match) {
68+
return i + 1L;
69+
}
70+
}
71+
return -1;
72+
}
73+
74+
@Override
75+
public long position(Blob pattern, long start) throws SQLException {
76+
return position(pattern.getBytes(1, (int) pattern.length()), start);
77+
}
78+
79+
@Override
80+
public int setBytes(long pos, byte[] bytes) throws SQLException {
81+
throw new SQLFeatureNotSupportedException("Blob is read-only");
82+
}
83+
84+
@Override
85+
public int setBytes(long pos, byte[] bytes, int offset, int len) throws SQLException {
86+
throw new SQLFeatureNotSupportedException("Blob is read-only");
87+
}
88+
89+
@Override
90+
public OutputStream setBinaryStream(long pos) throws SQLException {
91+
throw new SQLFeatureNotSupportedException("Blob is read-only");
92+
}
93+
94+
@Override
95+
public void truncate(long len) throws SQLException {
96+
throw new SQLFeatureNotSupportedException("Blob is read-only");
97+
}
98+
99+
@Override
100+
public void free() throws SQLException {
101+
freed = true;
102+
bytes = null;
103+
}
104+
105+
@Override
106+
public InputStream getBinaryStream(long pos, long length) throws SQLException {
107+
if (length < 0) {
108+
throw new SQLException("Invalid length: " + length);
109+
}
110+
return new ByteArrayInputStream(getBytes(pos, (int) Math.min(length, Integer.MAX_VALUE)));
111+
}
112+
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package com.github.magnusp.libsql.jdbc;
2+
3+
import java.io.ByteArrayInputStream;
4+
import java.io.InputStream;
5+
import java.io.OutputStream;
6+
import java.io.Reader;
7+
import java.io.StringReader;
8+
import java.io.Writer;
9+
import java.nio.charset.StandardCharsets;
10+
import java.sql.Clob;
11+
import java.sql.SQLException;
12+
import java.sql.SQLFeatureNotSupportedException;
13+
14+
/** Read-only {@link Clob} over the materialized text of one result column. */
15+
final class LibsqlClob implements Clob {
16+
17+
private String text;
18+
private boolean freed;
19+
20+
LibsqlClob(String text) {
21+
this.text = text;
22+
}
23+
24+
private String data() throws SQLException {
25+
if (freed) {
26+
throw new SQLException("Clob has been freed");
27+
}
28+
return text;
29+
}
30+
31+
@Override
32+
public long length() throws SQLException {
33+
return data().length();
34+
}
35+
36+
@Override
37+
public String getSubString(long pos, int length) throws SQLException {
38+
String data = data();
39+
if (pos < 1) {
40+
throw new SQLException("Invalid position: " + pos);
41+
}
42+
if (length < 0) {
43+
throw new SQLException("Invalid length: " + length);
44+
}
45+
int start = (int) Math.min(pos - 1, data.length());
46+
int end = Math.min(start + length, data.length());
47+
return data.substring(start, end);
48+
}
49+
50+
@Override
51+
public Reader getCharacterStream() throws SQLException {
52+
return new StringReader(data());
53+
}
54+
55+
@Override
56+
public InputStream getAsciiStream() throws SQLException {
57+
return new ByteArrayInputStream(data().getBytes(StandardCharsets.US_ASCII));
58+
}
59+
60+
@Override
61+
public long position(String searchstr, long start) throws SQLException {
62+
if (start < 1) {
63+
throw new SQLException("Invalid position: " + start);
64+
}
65+
String data = data();
66+
int from = (int) Math.min(start - 1, data.length());
67+
int index = data.indexOf(searchstr, from);
68+
return index < 0 ? -1 : index + 1L;
69+
}
70+
71+
@Override
72+
public long position(Clob searchstr, long start) throws SQLException {
73+
return position(searchstr.getSubString(1, (int) searchstr.length()), start);
74+
}
75+
76+
@Override
77+
public int setString(long pos, String str) throws SQLException {
78+
throw new SQLFeatureNotSupportedException("Clob is read-only");
79+
}
80+
81+
@Override
82+
public int setString(long pos, String str, int offset, int len) throws SQLException {
83+
throw new SQLFeatureNotSupportedException("Clob is read-only");
84+
}
85+
86+
@Override
87+
public OutputStream setAsciiStream(long pos) throws SQLException {
88+
throw new SQLFeatureNotSupportedException("Clob is read-only");
89+
}
90+
91+
@Override
92+
public Writer setCharacterStream(long pos) throws SQLException {
93+
throw new SQLFeatureNotSupportedException("Clob is read-only");
94+
}
95+
96+
@Override
97+
public void truncate(long len) throws SQLException {
98+
throw new SQLFeatureNotSupportedException("Clob is read-only");
99+
}
100+
101+
@Override
102+
public void free() throws SQLException {
103+
freed = true;
104+
text = null;
105+
}
106+
107+
@Override
108+
public Reader getCharacterStream(long pos, long length) throws SQLException {
109+
if (length < 0) {
110+
throw new SQLException("Invalid length: " + length);
111+
}
112+
return new StringReader(getSubString(pos, (int) Math.min(length, Integer.MAX_VALUE)));
113+
}
114+
}

0 commit comments

Comments
 (0)