Mercurial > hg > monetdb-java
changeset 517:130bb2e18d3f onclient
Add example code
author | Joeri van Ruth <joeri.van.ruth@monetdbsolutions.com> |
---|---|
date | Wed, 25 Aug 2021 10:00:28 +0200 (2021-08-25) |
parents | 704a11b93e6b |
children | e84b3cbd8b57 |
files | src/main/java/OnClientExample.java |
diffstat | 1 files changed, 160 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/src/main/java/OnClientExample.java @@ -0,0 +1,160 @@ +import org.monetdb.jdbc.MonetConnection; +import org.monetdb.jdbc.MonetUploadHandler; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintStream; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.sql.*; + +public class OnClientExample { + + public static void main(String[] args) { + int status = 0; + try { + // Ideally this would not be hardcoded.. + final String dbUrl = "jdbc:monetdb://localhost:55000/banana"; + final String uploadDir = "/home/jvr/mydata"; + final boolean filesAreUtf8 = false; + final String userName = "monetdb"; + final String password = "monetdb"; + + status = run(dbUrl, userName, password, uploadDir, filesAreUtf8); + + } catch (Exception e) { + status = 1; + e.printStackTrace(); + } + System.exit(status); + } + + private static int run(String dbUrl, String userName, String password, String uploadDir, boolean filesAreUtf8) throws ClassNotFoundException, SQLException { + int status = 0; + + // Connect + Class.forName("org.monetdb.jdbc.MonetDriver"); + Connection conn = DriverManager.getConnection(dbUrl, userName, password); + + // Register upload handler + MyUploader handler = new MyUploader(uploadDir, filesAreUtf8); + conn.unwrap(MonetConnection.class).setUploadHandler(handler); + + // Run some SQL statements involving ON CLIENT + String[] queries = { + "DROP TABLE IF EXISTS bar", + "CREATE TABLE bar(i INT, t TEXT)", + "COPY INTO bar FROM 'generated.csv' ON CLIENT", + "COPY INTO bar FROM 'file.csv' ON CLIENT", + // following statement will run even if file.csv does not exist + "SELECT COUNT(*) FROM bar", + }; + Statement stmt = conn.createStatement(); + for (String q : queries) { + System.out.println(q); + try { + stmt.execute(q); + ResultSet rs = stmt.getResultSet(); + if (rs == null) { + System.out.printf(" OK, %d rows updated%n", stmt.getUpdateCount()); + } else { + long count = 0; + while (rs.next()) { + count++; + } + System.out.printf(" OK, returned %d rows%n", count); + } + } catch (SQLNonTransientException e) { + throw e; + } catch (SQLException e) { + System.out.println(" => SQL ERROR " + e.getMessage()); + status = 1; + } + } + + return status; + } + + + private static class MyUploader implements MonetUploadHandler { + private final Path uploadDir; + private final boolean filesAreUtf8; + + public MyUploader(String uploadDir, boolean filesAreUtf8) { + this.uploadDir = FileSystems.getDefault().getPath(uploadDir).normalize(); + this.filesAreUtf8 = filesAreUtf8; + } + + @Override + public void handleUpload(MonetConnection.Upload handle, String name, boolean textMode, int offset) throws IOException { + + // COPY OFFSET line numbers are 1-based but 0 is also allowed. + // Compute the number of lines to skip + long toSkip = offset <= 1 ? 0 : offset - 1; + + // We can upload data read from the file system but also make up our own data + if (name.equals("generated.csv")) { + uploadGenerated(handle, toSkip); + return; + } + + // Validate the path, demonstrating two ways of dealing with errors + Path path = securityCheck(name); + if (path == null || !Files.exists(path)) { + // This makes the COPY command fail but keeps the connection alive. + // Can only be used if we haven't sent any data yet + handle.sendError("Invalid path"); + return; + } + if (!Files.isReadable(path)) { + // As opposed to handle.sendError(), throwing an IOException ends the whole connection. + throw new IOException("Unreadable: " + path); + } + + boolean binary = !textMode; + if (binary) { + uploadBinary(handle, path); + } else if (toSkip == 0 && filesAreUtf8) { + // Avoid unnecessary character set conversions by pretending it's binary + uploadBinary(handle, path); + } else { + // Charset and skip handling really necessary + uploadTextFile(handle, path, toSkip); + } + } + + private Path securityCheck(String name) { + Path p = uploadDir.resolve(name).normalize(); + if (p.startsWith(uploadDir)) { + return p; + } else { + return null; + } + } + + private void uploadGenerated(MonetConnection.Upload handle, long toSkip) throws IOException { + PrintStream stream = handle.getStream(); + for (long i = toSkip + 1; i <= 100; i++) { + stream.printf("%d|the number is %d%n", i, i); + } + stream.close(); + } + + private void uploadTextFile(MonetConnection.Upload handle, Path path, long toSkip) throws IOException { + BufferedReader reader = Files.newBufferedReader(path);// Converts from system encoding to Java text + for (long i = 0; i < toSkip; i++) { + reader.readLine(); + } + handle.uploadFrom(reader); // Converts from Java text to UTF-8 as required by MonetDB + } + + private void uploadBinary(MonetConnection.Upload handle, Path path) throws IOException { + // No charset conversion whatsoever.. + // Use this for binary data or when you are certain the file is UTF-8 encoded. + InputStream stream = Files.newInputStream(path); + handle.uploadFrom(stream); + } + } +}