Skip to content

Commit 718db9d

Browse files
committed
Support PreparedStatement stream parameters
Add capability to set streams as a parameter of ASCII or UNICODE text as well as SCALAR binary data. Tarantool does not support a data streaming via IPPROTO so it leads the driver materializes the streams in proper data in advance and sends prepared data as ordinary text or raw bytes. Closes: #190
1 parent 27c7650 commit 718db9d

File tree

3 files changed

+258
-28
lines changed

3 files changed

+258
-28
lines changed

src/main/java/org/tarantool/jdbc/SQLPreparedStatement.java

Lines changed: 91 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22

33
import org.tarantool.util.SQLStates;
44

5+
import java.io.ByteArrayOutputStream;
6+
import java.io.IOException;
57
import java.io.InputStream;
68
import java.io.Reader;
9+
import java.io.UnsupportedEncodingException;
710
import java.math.BigDecimal;
811
import java.net.URL;
912
import java.sql.Array;
@@ -31,6 +34,7 @@
3134
public class SQLPreparedStatement extends SQLStatement implements PreparedStatement {
3235

3336
private static final String INVALID_CALL_MESSAGE = "The method cannot be called on a PreparedStatement.";
37+
private static final int STREAM_WRITE_CHUNK_SIZE = 4096;
3438

3539
private final String sql;
3640
private final Map<Integer, Object> parameters;
@@ -182,37 +186,40 @@ public void setTimestamp(int parameterIndex, Timestamp parameterValue, Calendar
182186

183187
@Override
184188
public void setAsciiStream(int parameterIndex, InputStream parameterValue, int length) throws SQLException {
185-
setParameter(parameterIndex, parameterValue);
189+
setAsciiStream(parameterIndex, parameterValue, (long) length);
186190
}
187191

188192
@Override
189-
public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException {
190-
throw new SQLFeatureNotSupportedException();
193+
public void setAsciiStream(int parameterIndex, InputStream parameterValue) throws SQLException {
194+
setCharStream(parameterIndex, parameterValue, Integer.MAX_VALUE, "ASCII");
191195
}
192196

193197
@Override
194-
public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException {
195-
throw new SQLFeatureNotSupportedException();
198+
public void setAsciiStream(int parameterIndex, InputStream parameterValue, long length) throws SQLException {
199+
ensureLengthLowerBound(length);
200+
setCharStream(parameterIndex, parameterValue, length, "ASCII");
196201
}
197202

198203
@Override
199204
public void setUnicodeStream(int parameterIndex, InputStream parameterValue, int length) throws SQLException {
200-
setParameter(parameterIndex, parameterValue);
205+
ensureLengthLowerBound(length);
206+
setCharStream(parameterIndex, parameterValue, length, "UTF-8");
201207
}
202208

203209
@Override
204210
public void setBinaryStream(int parameterIndex, InputStream parameterValue, int length) throws SQLException {
205-
setParameter(parameterIndex, parameterValue);
211+
setBinaryStream(parameterIndex, parameterValue, (long) length);
206212
}
207213

208214
@Override
209-
public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException {
210-
throw new SQLFeatureNotSupportedException();
215+
public void setBinaryStream(int parameterIndex, InputStream parameterValue, long length) throws SQLException {
216+
ensureLengthLowerBound(length);
217+
setBinStream(parameterIndex, parameterValue, length);
211218
}
212219

213220
@Override
214-
public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException {
215-
throw new SQLFeatureNotSupportedException();
221+
public void setBinaryStream(int parameterIndex, InputStream parameterValue) throws SQLException {
222+
setBinStream(parameterIndex, parameterValue, Integer.MAX_VALUE);
216223
}
217224

218225
@Override
@@ -257,17 +264,18 @@ public boolean execute(String sql) throws SQLException {
257264

258265
@Override
259266
public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException {
260-
throw new SQLFeatureNotSupportedException();
267+
setCharacterStream(parameterIndex, reader, (long) length);
261268
}
262269

263270
@Override
264271
public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException {
265-
throw new SQLFeatureNotSupportedException();
272+
ensureLengthLowerBound(length);
273+
setCharStream(parameterIndex, reader, length);
266274
}
267275

268276
@Override
269277
public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException {
270-
throw new SQLFeatureNotSupportedException();
278+
setCharStream(parameterIndex, reader, Integer.MAX_VALUE);
271279
}
272280

273281
@Override
@@ -343,12 +351,12 @@ public void setNString(int parameterIndex, String parameterValue) throws SQLExce
343351

344352
@Override
345353
public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException {
346-
throw new SQLFeatureNotSupportedException();
354+
setCharacterStream(parameterIndex, value, length);
347355
}
348356

349357
@Override
350358
public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException {
351-
throw new SQLFeatureNotSupportedException();
359+
setCharacterStream(parameterIndex, value);
352360
}
353361

354362
@Override
@@ -417,4 +425,71 @@ private Object[] toParametersList(Map<Integer, Object> parameters) throws SQLExc
417425
return objects;
418426
}
419427

428+
private void ensureLengthLowerBound(long length) throws SQLException {
429+
if (length < 0) {
430+
throw new SQLException("Stream size cannot be negative", SQLStates.INVALID_PARAMETER_VALUE.getSqlState());
431+
}
432+
}
433+
434+
private void ensureLengthUpperBound(long length) throws SQLException {
435+
if (length > Integer.MAX_VALUE) {
436+
throw new SQLException("Stream size is too large", SQLStates.INVALID_PARAMETER_VALUE.getSqlState());
437+
}
438+
}
439+
440+
private void setCharStream(int parameterIndex,
441+
InputStream parameterValue,
442+
long length,
443+
String encoding) throws SQLException {
444+
ensureLengthUpperBound(length);
445+
try {
446+
byte[] bytes = convertToBytes(parameterValue, length);
447+
setParameter(parameterIndex, new String(bytes, 0, bytes.length, encoding));
448+
} catch (UnsupportedEncodingException e) {
449+
throw new SQLException("Unsupported encoding", SQLStates.INVALID_PARAMETER_VALUE.getSqlState(), e);
450+
}
451+
}
452+
453+
private void setCharStream(int parameterIndex, Reader reader, long length) throws SQLException {
454+
ensureLengthUpperBound(length);
455+
try {
456+
StringBuilder value = new StringBuilder(STREAM_WRITE_CHUNK_SIZE);
457+
char[] buffer = new char[STREAM_WRITE_CHUNK_SIZE];
458+
int totalRead = 0;
459+
int charsRead;
460+
while (totalRead < length &&
461+
(charsRead = reader.read(buffer, 0, (int) Math.min(length - totalRead, STREAM_WRITE_CHUNK_SIZE))) != -1) {
462+
value.append(buffer, 0, charsRead);
463+
totalRead += charsRead;
464+
}
465+
setParameter(parameterIndex, value.toString());
466+
} catch (IOException e) {
467+
throw new SQLException("Cannot read from the reader", SQLStates.INVALID_PARAMETER_VALUE.getSqlState(), e);
468+
}
469+
}
470+
471+
private void setBinStream(int parameterIndex,
472+
InputStream parameterValue,
473+
long length) throws SQLException {
474+
ensureLengthUpperBound(length);
475+
setBytes(parameterIndex, convertToBytes(parameterValue, length));
476+
}
477+
478+
private byte[] convertToBytes(InputStream parameterValue, long length) throws SQLException {
479+
try {
480+
int bytesRead;
481+
int totalRead = 0;
482+
byte[] buffer = new byte[STREAM_WRITE_CHUNK_SIZE];
483+
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(STREAM_WRITE_CHUNK_SIZE);
484+
while (totalRead < length &&
485+
(bytesRead = parameterValue.read(buffer, 0, (int) Math.min(length - totalRead, STREAM_WRITE_CHUNK_SIZE))) != -1) {
486+
outputStream.write(buffer, 0, bytesRead);
487+
totalRead += bytesRead;
488+
}
489+
return outputStream.toByteArray();
490+
} catch (IOException e) {
491+
throw new SQLException("Cannot read stream", SQLStates.INVALID_PARAMETER_VALUE.getSqlState(), e);
492+
}
493+
}
494+
420495
}

src/main/java/org/tarantool/jdbc/SQLStatement.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@
1717
import java.util.ArrayList;
1818
import java.util.Collections;
1919
import java.util.List;
20-
import java.util.ArrayList;
21-
import java.util.List;
2220
import java.util.concurrent.TimeUnit;
2321
import java.util.concurrent.atomic.AtomicBoolean;
2422
import java.util.stream.Collectors;
@@ -46,8 +44,6 @@ public class SQLStatement implements TarantoolStatement {
4644

4745
private List<String> batchQueries = new ArrayList<>();
4846

49-
private List<String> batchQueries = new ArrayList<>();
50-
5147
private boolean isCloseOnCompletion;
5248

5349
private final int resultSetType;

0 commit comments

Comments
 (0)