Mercurial > hg > monetdb-java
comparison src/main/java/org/monetdb/jdbc/MonetConnection.java @ 535:c9d88af06d35 onclient
Javadoc and some minor changes
author | Joeri van Ruth <joeri.van.ruth@monetdbsolutions.com> |
---|---|
date | Fri, 27 Aug 2021 16:13:54 +0200 (2021-08-27) |
parents | 6060ca8c5c1a |
children | 5d524783f7b0 |
comparison
equal
deleted
inserted
replaced
534:b437529144f1 | 535:c9d88af06d35 |
---|---|
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 MonetUploadHandler uploader; | 155 private MonetUploadHandler uploadHandler; |
156 private MonetDownloadHandler downloader; | 156 private MonetDownloadHandler downloadHandler; |
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 |
1196 public void setTypeMap(final Map<String, Class<?>> map) { | 1196 public void setTypeMap(final Map<String, Class<?>> map) { |
1197 typeMap = map; | 1197 typeMap = map; |
1198 } | 1198 } |
1199 | 1199 |
1200 /** | 1200 /** |
1201 * Registers a MonetUploader to support for example COPY ON CLIENT | 1201 * Registers a {@link MonetUploadHandler} to support for example COPY ON CLIENT |
1202 * | 1202 * |
1203 * @param uploadHandler the handler to register, or null to deregister | 1203 * @param uploadHandler the handler to register, or null to deregister |
1204 */ | 1204 */ |
1205 public void setUploadHandler(MonetUploadHandler uploadHandler) { | 1205 public void setUploadHandler(MonetUploadHandler uploadHandler) { |
1206 this.uploader = uploadHandler; | 1206 this.uploadHandler = uploadHandler; |
1207 } | 1207 } |
1208 | 1208 |
1209 /** | 1209 /** |
1210 * Returns the currently registerered MonetUploader, or null | 1210 * Returns the currently registerered {@link MonetUploadHandler}, or null |
1211 */ | 1211 */ |
1212 public MonetUploadHandler getUploadHandler() { | 1212 public MonetUploadHandler getUploadHandler() { |
1213 return uploader; | 1213 return uploadHandler; |
1214 } | 1214 } |
1215 /** | 1215 /** |
1216 * Registers a MonetDownloader to support for example COPY ON CLIENT | 1216 * Registers a {@link MonetDownloadHandler} to support for example COPY ON CLIENT |
1217 * | 1217 * |
1218 * @param downloadHandler the handler to register, or null to deregister | 1218 * @param downloadHandler the handler to register, or null to deregister |
1219 */ | 1219 */ |
1220 public void setDownloadHandler(MonetDownloadHandler downloadHandler) { | 1220 public void setDownloadHandler(MonetDownloadHandler downloadHandler) { |
1221 this.downloader = downloadHandler; | 1221 this.downloadHandler = downloadHandler; |
1222 } | 1222 } |
1223 | 1223 |
1224 /** | 1224 /** |
1225 * Returns the currently registerered MonetDownloadHandler handler, or null | 1225 * Returns the currently registerered {@link MonetDownloadHandler} handler, or null |
1226 */ | 1226 */ |
1227 public MonetDownloadHandler getDownloadHandler() { | 1227 public MonetDownloadHandler getDownloadHandler() { |
1228 return downloader; | 1228 return downloadHandler; |
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. |
1233 * | 1233 * |
3225 return "JDBC does not support this file transfer yet: " + transferCommand; | 3225 return "JDBC does not support this file transfer yet: " + transferCommand; |
3226 } | 3226 } |
3227 } | 3227 } |
3228 | 3228 |
3229 private String handleUpload(String path, boolean textMode, int offset) throws IOException { | 3229 private String handleUpload(String path, boolean textMode, int offset) throws IOException { |
3230 if (uploader == null) { | 3230 if (uploadHandler == null) { |
3231 return "No file upload handler has been registered with the JDBC driver"; | 3231 return "No file upload handler has been registered with the JDBC driver"; |
3232 } | 3232 } |
3233 | 3233 |
3234 Upload handle = new Upload(server); | 3234 Upload handle = new Upload(server); |
3235 boolean wasFaking = server.setInsertFakePrompts(false); | 3235 boolean wasFaking = server.setInsertFakePrompts(false); |
3236 try { | 3236 try { |
3237 uploader.handleUpload(handle, path, textMode, offset); | 3237 uploadHandler.handleUpload(handle, path, textMode, offset); |
3238 if (!handle.hasBeenUsed()) { | 3238 if (!handle.hasBeenUsed()) { |
3239 String message = String.format("Call to %s.handleUpload for path '%s' sent neither data nor an error message", | 3239 String message = String.format("Call to %s.handleUpload for path '%s' sent neither data nor an error message", |
3240 uploader.getClass().getCanonicalName(), path); | 3240 uploadHandler.getClass().getCanonicalName(), path); |
3241 throw new IOException(message); | 3241 throw new IOException(message); |
3242 } | 3242 } |
3243 handle.close(); | 3243 handle.close(); |
3244 } finally { | 3244 } finally { |
3245 server.setInsertFakePrompts(wasFaking); | 3245 server.setInsertFakePrompts(wasFaking); |
3246 } | 3246 } |
3247 return handle.getError(); | 3247 return handle.getError(); |
3248 } | 3248 } |
3249 | 3249 |
3250 private String handleDownload(String path) throws IOException { | 3250 private String handleDownload(String path) throws IOException { |
3251 if (downloader == null) { | 3251 if (downloadHandler == null) { |
3252 return "No file download handler has been registered with the JDBC driver"; | 3252 return "No file download handler has been registered with the JDBC driver"; |
3253 } | 3253 } |
3254 | 3254 |
3255 Download handle = new Download(server); | 3255 Download handle = new Download(server); |
3256 downloader.handleDownload(handle, path, true); | 3256 downloadHandler.handleDownload(handle, path, true); |
3257 if (!handle.hasBeenUsed()) { | 3257 if (!handle.hasBeenUsed()) { |
3258 String message = String.format("Call to %s.handleDownload for path '%s' sent neither data nor an error message", | 3258 String message = String.format("Call to %s.handleDownload for path '%s' sent neither data nor an error message", |
3259 downloader.getClass().getCanonicalName(), path); | 3259 downloadHandler.getClass().getCanonicalName(), path); |
3260 throw new IOException(message); | 3260 throw new IOException(message); |
3261 } | 3261 } |
3262 handle.close(); | 3262 handle.close(); |
3263 return handle.getError(); | 3263 return handle.getError(); |
3264 } | 3264 } |
3265 | 3265 |
3266 /** | |
3267 * Handle passed to {@link MonetUploadHandler} to allow communication with the server | |
3268 */ | |
3266 public static class Upload { | 3269 public static class Upload { |
3267 private final MapiSocket server; | 3270 private final MapiSocket server; |
3268 private PrintStream print = null; | 3271 private PrintStream print = null; |
3269 private String error = null; | 3272 private String error = null; |
3270 private int customChunkSize = -1; | 3273 private int customChunkSize = -1; |
3271 | 3274 |
3272 Upload(MapiSocket server) { | 3275 Upload(MapiSocket server) { |
3273 this.server = server; | 3276 this.server = server; |
3274 } | 3277 } |
3275 | 3278 |
3279 /** | |
3280 * Send an error message to the server | |
3281 * | |
3282 * The server will generally let the currently executing statement fail | |
3283 * with this error message. The connection will remain usable. | |
3284 * | |
3285 * This method can only be sent if no data has been sent to the server | |
3286 * yet. After data has been sent, you can still throw an | |
3287 * {@link IOException} but this will terminate the connection. | |
3288 * @param errorMessage | |
3289 * @throws IOException | |
3290 */ | |
3276 public void sendError(String errorMessage) throws IOException { | 3291 public void sendError(String errorMessage) throws IOException { |
3277 if (error != null) { | 3292 if (error != null) { |
3278 throw new IOException("another error has already been sent: " + error); | 3293 throw new IOException("another error has already been sent: " + error); |
3279 } | 3294 } |
3280 error = errorMessage; | 3295 error = errorMessage; |
3281 } | 3296 } |
3282 | 3297 |
3298 /** | |
3299 * After every {@code chunkSize} bytes, the server gets the opportunity to | |
3300 * terminate the upload. | |
3301 * @param chunkSize | |
3302 */ | |
3283 public void setChunkSize(int chunkSize) { | 3303 public void setChunkSize(int chunkSize) { |
3284 this.customChunkSize = chunkSize; | 3304 this.customChunkSize = chunkSize; |
3285 } | 3305 } |
3286 | 3306 |
3307 /** | |
3308 * Get a {@link PrintStream} to write data to. | |
3309 * | |
3310 * For text mode uploads, the data MUST be validly UTF-8 encoded. | |
3311 * @return | |
3312 * @throws IOException | |
3313 */ | |
3287 public PrintStream getStream() throws IOException { | 3314 public PrintStream getStream() throws IOException { |
3288 if (error != null) { | 3315 if (error != null) { |
3289 throw new IOException("Cannot send data after an error has been sent"); | 3316 throw new IOException("Cannot send data after an error has been sent"); |
3290 } | 3317 } |
3291 if (print == null) { | 3318 if (print == null) { |
3298 } | 3325 } |
3299 } | 3326 } |
3300 return print; | 3327 return print; |
3301 } | 3328 } |
3302 | 3329 |
3330 /** | |
3331 * Returns true if data or an error has been sent. | |
3332 * @return | |
3333 */ | |
3303 public boolean hasBeenUsed() { | 3334 public boolean hasBeenUsed() { |
3304 return print != null || error != null; | 3335 return print != null || error != null; |
3305 } | 3336 } |
3306 | 3337 |
3338 /** | |
3339 * Get the error that was sent, if any | |
3340 * @return | |
3341 */ | |
3307 public String getError() { | 3342 public String getError() { |
3308 return error; | 3343 return error; |
3309 } | 3344 } |
3310 | 3345 |
3346 /** | |
3347 * Read from the given input stream and write it to the server. | |
3348 * | |
3349 * For text mode uploads, the data MUST be validly UTF-8 encoded. | |
3350 * @param inputStream | |
3351 * @throws IOException | |
3352 */ | |
3311 public void uploadFrom(InputStream inputStream) throws IOException { | 3353 public void uploadFrom(InputStream inputStream) throws IOException { |
3312 OutputStream s = getStream(); | 3354 OutputStream s = getStream(); |
3313 byte[] buffer = new byte[64 * 1024]; | 3355 byte[] buffer = new byte[64 * 1024]; |
3314 while (true) { | 3356 while (true) { |
3315 int nread = inputStream.read(buffer); | 3357 int nread = inputStream.read(buffer); |
3318 } | 3360 } |
3319 s.write(buffer, 0, nread); | 3361 s.write(buffer, 0, nread); |
3320 } | 3362 } |
3321 } | 3363 } |
3322 | 3364 |
3365 /** | |
3366 * Read data from the given buffered reader and send it to the server | |
3367 * @param reader reader to read from | |
3368 * @param offset start uploading at line {@code offset}. Value 0 and 1 | |
3369 * both mean upload the whole file, value 2 means skip the first line, etc.q | |
3370 * @throws IOException | |
3371 */ | |
3323 public void uploadFrom(BufferedReader reader, int offset) throws IOException { | 3372 public void uploadFrom(BufferedReader reader, int offset) throws IOException { |
3324 // we're 1-based but also accept 0 | 3373 // we're 1-based but also accept 0 |
3325 if (offset > 0) { | 3374 if (offset > 0) { |
3326 offset -= 1; | 3375 offset -= 1; |
3327 } | 3376 } |
3334 } | 3383 } |
3335 | 3384 |
3336 uploadFrom(reader); | 3385 uploadFrom(reader); |
3337 } | 3386 } |
3338 | 3387 |
3388 | |
3389 /** | |
3390 * Read data from the given buffered reader and send it to the server | |
3391 * @param reader reader to read from | |
3392 * @throws IOException | |
3393 */ | |
3339 public void uploadFrom(Reader reader) throws IOException { | 3394 public void uploadFrom(Reader reader) throws IOException { |
3340 OutputStream s = getStream(); | 3395 OutputStream s = getStream(); |
3341 OutputStreamWriter writer = new OutputStreamWriter(s, StandardCharsets.UTF_8); | 3396 OutputStreamWriter writer = new OutputStreamWriter(s, StandardCharsets.UTF_8); |
3342 char[] buffer = new char[64 * 1024]; | 3397 char[] buffer = new char[64 * 1024]; |
3343 while (true) { | 3398 while (true) { |
3355 print.close(); | 3410 print.close(); |
3356 } | 3411 } |
3357 } | 3412 } |
3358 } | 3413 } |
3359 | 3414 |
3415 /** | |
3416 * Handle passed to {@link MonetDownloadHandler} to allow communication with the server | |
3417 */ | |
3360 public static class Download { | 3418 public static class Download { |
3361 private final MapiSocket server; | 3419 private final MapiSocket server; |
3362 private MapiSocket.DownloadStream stream = null; | 3420 private MapiSocket.DownloadStream stream = null; |
3363 private String error = null; | 3421 private String error = null; |
3364 | 3422 |
3366 | 3424 |
3367 Download(MapiSocket server) { | 3425 Download(MapiSocket server) { |
3368 this.server = server; | 3426 this.server = server; |
3369 } | 3427 } |
3370 | 3428 |
3429 /** | |
3430 * Send an error message to the server | |
3431 * | |
3432 * The server will generally let the currently executing statement fail | |
3433 * with this error message. The connection will remain usable. | |
3434 * | |
3435 * This method can only be sent if no data has been received from the server | |
3436 * yet. After data has been received, you can still throw an | |
3437 * {@link IOException} but this will terminate the connection. | |
3438 * | |
3439 * Note: as of MonetDB version Jul2021 the server always terminates the connection | |
3440 * when this error is used. This will probably change in the future. | |
3441 * @param errorMessage | |
3442 * @throws IOException | |
3443 */ | |
3371 public void sendError(String errorMessage) throws IOException { | 3444 public void sendError(String errorMessage) throws IOException { |
3372 if (error != null) { | 3445 if (error != null) { |
3373 throw new IOException("another error has already been sent: " + error); | 3446 throw new IOException("another error has already been sent: " + error); |
3374 } | 3447 } |
3375 error = errorMessage; | 3448 error = errorMessage; |
3376 } | 3449 } |
3377 | 3450 |
3451 /** | |
3452 * Get an {@link InputStream} to read data from. | |
3453 * | |
3454 * Textual data is UTF-8 encoded. | |
3455 * @return | |
3456 * @throws IOException | |
3457 */ | |
3378 public InputStream getStream() throws IOException { | 3458 public InputStream getStream() throws IOException { |
3379 if (error != null) { | 3459 if (error != null) { |
3380 throw new IOException("cannot receive data after error has been sent"); | 3460 throw new IOException("cannot receive data after error has been sent"); |
3381 } | 3461 } |
3382 if (stream == null) { | 3462 if (stream == null) { |
3384 server.getOutputStream().flush(); | 3464 server.getOutputStream().flush(); |
3385 } | 3465 } |
3386 return stream; | 3466 return stream; |
3387 } | 3467 } |
3388 | 3468 |
3469 /** | |
3470 * Write the data from the server to the given {@link OutputStream}. | |
3471 * @param stream | |
3472 * @throws IOException | |
3473 */ | |
3389 public void downloadTo(OutputStream stream) throws IOException { | 3474 public void downloadTo(OutputStream stream) throws IOException { |
3390 InputStream s = getStream(); | 3475 InputStream s = getStream(); |
3391 byte[] buffer = new byte[65536]; | 3476 byte[] buffer = new byte[65536]; |
3392 while (true) { | 3477 while (true) { |
3393 int nread = s.read(buffer); | 3478 int nread = s.read(buffer); |
3395 break; | 3480 break; |
3396 stream.write(buffer, 0, nread); | 3481 stream.write(buffer, 0, nread); |
3397 } | 3482 } |
3398 } | 3483 } |
3399 | 3484 |
3485 /** | |
3486 * Returns true if data has been received or an error has been sent. | |
3487 * @return | |
3488 */ | |
3489 | |
3400 public boolean hasBeenUsed() { | 3490 public boolean hasBeenUsed() { |
3401 return error != null || stream != null; | 3491 return error != null || stream != null; |
3402 } | 3492 } |
3493 | |
3494 /** | |
3495 * Get the error that was sent, if any | |
3496 * @return | |
3497 */ | |
3403 | 3498 |
3404 public String getError() { | 3499 public String getError() { |
3405 return error; | 3500 return error; |
3406 } | 3501 } |
3407 public void close() throws IOException { | 3502 public void close() throws IOException { |
3411 if (stream != null) { | 3506 if (stream != null) { |
3412 stream.close(); | 3507 stream.close(); |
3413 } | 3508 } |
3414 closed = true; | 3509 closed = true; |
3415 } | 3510 } |
3416 | |
3417 } | 3511 } |
3418 } | 3512 } |