comparison src/main/java/org/monetdb/jdbc/MonetConnection.java @ 514:443780d71bae onclient

More renaming. user registers MonetUploadHandler which is handed an Upload
author Joeri van Ruth <joeri.van.ruth@monetdbsolutions.com>
date Mon, 23 Aug 2021 09:42:58 +0200 (2021-08-23)
parents bd860e850fe1
children 7bbcff2c775b
comparison
equal deleted inserted replaced
513:d771bfdd5288 514:443780d71bae
6 * Copyright 1997 - July 2008 CWI, August 2008 - 2021 MonetDB B.V. 6 * Copyright 1997 - July 2008 CWI, August 2008 - 2021 MonetDB B.V.
7 */ 7 */
8 8
9 package org.monetdb.jdbc; 9 package org.monetdb.jdbc;
10 10
11 import java.io.File; 11 import java.io.*;
12 import java.io.IOException;
13 import java.net.SocketException; 12 import java.net.SocketException;
14 import java.net.SocketTimeoutException; 13 import java.net.SocketTimeoutException;
14 import java.nio.charset.StandardCharsets;
15 import java.sql.CallableStatement; 15 import java.sql.CallableStatement;
16 import java.sql.Connection; 16 import java.sql.Connection;
17 import java.sql.DatabaseMetaData; 17 import java.sql.DatabaseMetaData;
18 import java.sql.PreparedStatement; 18 import java.sql.PreparedStatement;
19 import java.sql.ResultSet; 19 import java.sql.ResultSet;
150 150
151 /** A cache to reduce the number of DatabaseMetaData objects created by getMetaData() to maximum 1 per connection */ 151 /** A cache to reduce the number of DatabaseMetaData objects created by getMetaData() to maximum 1 per connection */
152 private DatabaseMetaData dbmd; 152 private DatabaseMetaData dbmd;
153 153
154 /** Handlers for ON CLIENT requests */ 154 /** Handlers for ON CLIENT requests */
155 private MonetUploader uploader; 155 private MonetUploadHandler uploader;
156 private MonetDownloader downloader; 156 private MonetDownloadHandler downloader;
157 157
158 /** 158 /**
159 * Constructor of a Connection for MonetDB. At this moment the 159 * Constructor of a Connection for MonetDB. At this moment the
160 * current implementation limits itself to storing the given host, 160 * current implementation limits itself to storing the given host,
161 * database, username and password for later use by the 161 * database, username and password for later use by the
1198 } 1198 }
1199 1199
1200 /** 1200 /**
1201 * Registers a MonetUploader to support for example COPY ON CLIENT 1201 * Registers a MonetUploader to support for example COPY ON CLIENT
1202 * 1202 *
1203 * @param uploader the handler to register, or null to deregister 1203 * @param uploadHandler the handler to register, or null to deregister
1204 */ 1204 */
1205 public void setUploader(MonetUploader uploader) { 1205 public void setUploadHandler(MonetUploadHandler uploadHandler) {
1206 this.uploader = uploader; 1206 this.uploader = uploadHandler;
1207 } 1207 }
1208 1208
1209 /** 1209 /**
1210 * Returns the currently registerered MonetUploader, or null 1210 * Returns the currently registerered MonetUploader, or null
1211 */ 1211 */
1212 public MonetUploader getUploader() { 1212 public MonetUploadHandler getUploadHandler() {
1213 return uploader; 1213 return uploader;
1214 } 1214 }
1215 /** 1215 /**
1216 * Registers a MonetDownloader to support for example COPY ON CLIENT 1216 * Registers a MonetDownloader to support for example COPY ON CLIENT
1217 * 1217 *
1218 * @param downloader the handler to register, or null to deregister 1218 * @param downloadHandler the handler to register, or null to deregister
1219 */ 1219 */
1220 public void setDownloader(MonetDownloader downloader) { 1220 public void setDownloadHandler(MonetDownloadHandler downloadHandler) {
1221 this.downloader = downloader; 1221 this.downloader = downloadHandler;
1222 } 1222 }
1223 1223
1224 /** 1224 /**
1225 * Returns the currently registerered MonetDownloadHandler handler, or null 1225 * Returns the currently registerered MonetDownloadHandler handler, or null
1226 */ 1226 */
1227 public MonetDownloader getDownloader() { 1227 public MonetDownloadHandler getDownloadHandler() {
1228 return downloader; 1228 return downloader;
1229 } 1229 }
1230 1230
1231 /** 1231 /**
1232 * Returns a string identifying this Connection to the MonetDB server. 1232 * Returns a string identifying this Connection to the MonetDB server.
3230 private String handleUpload(String path, boolean textMode, int offset) throws IOException { 3230 private String handleUpload(String path, boolean textMode, int offset) throws IOException {
3231 if (uploader == null) { 3231 if (uploader == null) {
3232 return "No file upload handler has been registered with the JDBC driver"; 3232 return "No file upload handler has been registered with the JDBC driver";
3233 } 3233 }
3234 3234
3235 MonetUploadHandle handle = new MonetUploadHandle(server); 3235 Upload handle = new Upload(server);
3236 boolean wasFaking = server.setInsertFakePrompts(false); 3236 boolean wasFaking = server.setInsertFakePrompts(false);
3237 try { 3237 try {
3238 uploader.handleUpload(handle, path, textMode, offset); 3238 uploader.handleUpload(handle, path, textMode, offset);
3239 if (!handle.hasBeenUsed()) { 3239 if (!handle.hasBeenUsed()) {
3240 String message = String.format("Call to %s.handleUpload for path '%s' sent neither data nor an error message", 3240 String message = String.format("Call to %s.handleUpload for path '%s' sent neither data nor an error message",
3251 private String handleDownload(String path) throws IOException { 3251 private String handleDownload(String path) throws IOException {
3252 if (downloader == null) { 3252 if (downloader == null) {
3253 return "No file download handler has been registered with the JDBC driver"; 3253 return "No file download handler has been registered with the JDBC driver";
3254 } 3254 }
3255 3255
3256 MonetDownloadHandle handle = new MonetDownloadHandle(server); 3256 Download handle = new Download(server);
3257 downloader.handleDownload(handle, path, true); 3257 downloader.handleDownload(handle, path, true);
3258 if (!handle.hasBeenUsed()) { 3258 if (!handle.hasBeenUsed()) {
3259 String message = String.format("Call to %s.handleDownload for path '%s' sent neither data nor an error message", 3259 String message = String.format("Call to %s.handleDownload for path '%s' sent neither data nor an error message",
3260 downloader.getClass().getCanonicalName(), path); 3260 downloader.getClass().getCanonicalName(), path);
3261 throw new IOException(message); 3261 throw new IOException(message);
3262 } 3262 }
3263 handle.close(); 3263 handle.close();
3264 return handle.getError(); 3264 return handle.getError();
3265 } 3265 }
3266
3267 public static class Upload {
3268 private final MapiSocket server;
3269 private PrintStream print = null;
3270 private String error = null;
3271
3272 Upload(MapiSocket server) {
3273 this.server = server;
3274 }
3275
3276 public void sendError(String errorMessage) throws IOException {
3277 if (error != null) {
3278 throw new IOException("another error has already been sent: " + error);
3279 }
3280 error = errorMessage;
3281 }
3282
3283 public PrintStream getStream() throws IOException {
3284 if (error != null) {
3285 throw new IOException("Cannot send data after an error has been sent");
3286 }
3287 if (print == null) {
3288 try {
3289 MapiSocket.UploadStream up = server.uploadStream();
3290 print = new PrintStream(up, false, "UTF-8");
3291 up.write('\n');
3292 } catch (UnsupportedEncodingException e) {
3293 throw new RuntimeException("The system is guaranteed to support the UTF-8 encoding but apparently it doesn't", e);
3294 }
3295 }
3296 return print;
3297 }
3298
3299 public boolean hasBeenUsed() {
3300 return print != null || error != null;
3301 }
3302
3303 public String getError() {
3304 return error;
3305 }
3306
3307 public void uploadFrom(InputStream inputStream) throws IOException {
3308 OutputStream s = getStream();
3309 byte[] buffer = new byte[64 * 1024];
3310 while (true) {
3311 int nread = inputStream.read(buffer);
3312 if (nread < 0) {
3313 break;
3314 }
3315 s.write(buffer, 0, nread);
3316 }
3317 }
3318
3319 public void uploadFrom(BufferedReader reader, int offset) throws IOException {
3320 // we're 1-based but also accept 0
3321 if (offset > 0) {
3322 offset -= 1;
3323 }
3324
3325 for (int i = 0; i < offset; i++) {
3326 String line = reader.readLine();
3327 if (line == null) {
3328 return;
3329 }
3330 }
3331
3332 uploadFrom(reader);
3333 }
3334
3335 public void uploadFrom(BufferedReader reader) throws IOException {
3336 OutputStream s = getStream();
3337 OutputStreamWriter writer = new OutputStreamWriter(s, StandardCharsets.UTF_8);
3338 char[] buffer = new char[64 * 1024];
3339 while (true) {
3340 int nread = reader.read(buffer, 0, buffer.length);
3341 if (nread < 0) {
3342 break;
3343 }
3344 writer.write(buffer, 0, nread);
3345 writer.close();
3346 }
3347 }
3348
3349 public void close() {
3350 if (print != null) {
3351 print.close();
3352 }
3353 }
3354 }
3355
3356 public static class Download {
3357 private final MapiSocket server;
3358 private MapiSocket.DownloadStream stream = null;
3359 private String error = null;
3360
3361 boolean closed = false;
3362
3363 Download(MapiSocket server) {
3364 this.server = server;
3365 }
3366
3367 public void sendError(String errorMessage) throws IOException {
3368 if (error != null) {
3369 throw new IOException("another error has already been sent: " + error);
3370 }
3371 error = errorMessage;
3372 }
3373
3374 public InputStream getStream() throws IOException {
3375 if (error != null) {
3376 throw new IOException("cannot receive data after error has been sent");
3377 }
3378 if (stream == null) {
3379 stream = server.downloadStream();
3380 server.getOutputStream().flush();
3381 }
3382 return stream;
3383 }
3384 public boolean hasBeenUsed() {
3385 return error != null || stream != null;
3386 }
3387
3388 public String getError() {
3389 return error;
3390 }
3391 public void close() throws IOException {
3392 if (closed) {
3393 return;
3394 }
3395 if (stream != null) {
3396 stream.close();
3397 }
3398 closed = true;
3399 }
3400
3401 }
3266 } 3402 }