Changeset: 5aa19bbed0d6 for monetdb-java URL: https://dev.monetdb.org/hg/monetdb-java/rev/5aa19bbed0d6 Modified Files: src/main/java/org/monetdb/client/JdbcClient.java src/main/java/org/monetdb/jdbc/MonetConnection.java src/main/java/org/monetdb/jdbc/MonetDriver.java src/main/java/org/monetdb/mcl/net/MapiSocket.java src/main/java/org/monetdb/mcl/net/MonetUrlParser.java src/main/java/org/monetdb/mcl/net/Parameter.java src/main/java/org/monetdb/mcl/net/ParameterType.java src/main/java/org/monetdb/mcl/net/SecureSocket.java src/main/java/org/monetdb/mcl/net/Target.java src/main/java/org/monetdb/mcl/net/ValidationError.java tests/TLSTester.java tests/UrlTester.java Branch: monetdbs Log Message:
Comments and formatting diffs (truncated from 4329 to 300 lines): diff --git a/src/main/java/org/monetdb/client/JdbcClient.java b/src/main/java/org/monetdb/client/JdbcClient.java --- a/src/main/java/org/monetdb/client/JdbcClient.java +++ b/src/main/java/org/monetdb/client/JdbcClient.java @@ -192,9 +192,6 @@ public final class JdbcClient { "statements read. Batching can greatly speedup the " + "process of restoring a database dump."); -// This file can contain defaults for the flags user, password, language, -// database, save_history, format, host, port, and width. For example, an - copts.addIgnored("save_history"); copts.addIgnored("format"); copts.addIgnored("width"); diff --git a/src/main/java/org/monetdb/jdbc/MonetConnection.java b/src/main/java/org/monetdb/jdbc/MonetConnection.java --- a/src/main/java/org/monetdb/jdbc/MonetConnection.java +++ b/src/main/java/org/monetdb/jdbc/MonetConnection.java @@ -75,7 +75,7 @@ public class MonetConnection extends MonetWrapper implements Connection, AutoCloseable { - /** All connection parameters */ + /* All connection parameters */ Target target; /** A connection to mserver5 using a TCP socket */ private final MapiSocket server; @@ -139,13 +139,11 @@ public class MonetConnection private DatabaseMetaData dbmd; /** - * Constructor of a Connection for MonetDB. At this moment the - * current implementation limits itself to storing the given host, - * database, username and password for later use by the - * createStatement() call. This constructor is only accessible to + * Constructor of a Connection for MonetDB. + * This constructor is only accessible to * classes from the jdbc package. * - * @param target a Target object holding the connection parameters + * @param target a {@link Target} object containing all connection parameters * @throws SQLException if a database error occurs * @throws IllegalArgumentException is one of the arguments is null or empty */ @@ -184,20 +182,20 @@ public class MonetConnection switch (target.getLanguage()) { case "sql": lang = LANG_SQL; - queryTempl[0] = "s"; // pre - queryTempl[1] = "\n;"; // post - queryTempl[2] = "\n;\n"; // separator - commandTempl[0] = "X"; // pre - commandTempl[1] = ""; // post + queryTempl[0] = "s"; // pre + queryTempl[1] = "\n;"; // post + queryTempl[2] = "\n;\n"; // separator + commandTempl[0] = "X"; // pre + commandTempl[1] = ""; // post callback = new SqlOptionsCallback(); break; case "mal": lang = LANG_MAL; - queryTempl[0] = ""; // pre - queryTempl[1] = ";\n"; // post - queryTempl[2] = ";\n"; // separator - commandTempl[0] = ""; // pre - commandTempl[1] = ""; // post + queryTempl[0] = ""; // pre + queryTempl[1] = ";\n"; // post + queryTempl[2] = ";\n"; // separator + commandTempl[0] = ""; // pre + commandTempl[1] = ""; // post break; default: lang = LANG_UNKNOWN; @@ -1248,6 +1246,15 @@ public class MonetConnection return isValid; } + /** + * Construct a Properties object holding all connection parameters such + * as host, port, TLS configuration, autocommit, etc. + * Passing this to {@link DriverManager.getConnection()} together + * with the URL "jdbc:monetdb:" will create a new connection identical to + * the current one. + * @return + */ + public Properties getConnectionProperties() { return target.getProperties(); } @@ -3747,7 +3754,8 @@ public class MonetConnection } } - public static enum SqlOption { + /* encode knowledge of currently available handshake options as an enum. */ + enum SqlOption { Autocommit(1, "auto_commit"), ReplySize(2, "reply_size"), SizeHeader(3, "size_header"), @@ -3766,6 +3774,7 @@ public class MonetConnection private class SqlOptionsCallback extends MapiSocket.OptionsCallback { private int level; + @Override public void addOptions(String lang, int level) { if (!lang.equals("sql")) @@ -3784,7 +3793,7 @@ public class MonetConnection } private boolean contribute(SqlOption opt, int value) { - if (this.level <= opt.level) + if (opt.level >= this.level) return false; contribute(opt.field, value); return true; diff --git a/src/main/java/org/monetdb/jdbc/MonetDriver.java b/src/main/java/org/monetdb/jdbc/MonetDriver.java --- a/src/main/java/org/monetdb/jdbc/MonetDriver.java +++ b/src/main/java/org/monetdb/jdbc/MonetDriver.java @@ -8,19 +8,11 @@ package org.monetdb.jdbc; -import org.monetdb.mcl.net.MonetUrlParser; -import org.monetdb.mcl.net.Parameter; import org.monetdb.mcl.net.Target; import org.monetdb.mcl.net.ValidationError; import java.net.URISyntaxException; -import java.sql.Connection; -import java.sql.Driver; -import java.sql.DriverManager; -import java.sql.DriverPropertyInfo; -import java.sql.SQLException; -import java.sql.SQLFeatureNotSupportedException; -import java.sql.Types; +import java.sql.*; import java.util.Map.Entry; import java.util.Properties; @@ -70,11 +62,9 @@ public final class MonetDriver implement */ @Override public boolean acceptsURL(final String url) { - if (url == null) + if (url == null) return false; - if (url.startsWith("jdbc:monetdb:") || url.startsWith("jdbc:monetdbs:")) - return true; - return false; + return url.startsWith("jdbc:monetdb:") || url.startsWith("jdbc:monetdbs:"); } /** diff --git a/src/main/java/org/monetdb/mcl/net/MapiSocket.java b/src/main/java/org/monetdb/mcl/net/MapiSocket.java --- a/src/main/java/org/monetdb/mcl/net/MapiSocket.java +++ b/src/main/java/org/monetdb/mcl/net/MapiSocket.java @@ -22,7 +22,6 @@ import java.nio.charset.StandardCharsets import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.*; -import java.util.stream.Collectors; import org.monetdb.mcl.MCLException; import org.monetdb.mcl.io.BufferedMCLReader; @@ -81,7 +80,12 @@ import org.monetdb.mcl.parser.MCLParseEx * @see org.monetdb.mcl.io.BufferedMCLWriter */ public final class MapiSocket { - public static final byte[] NUL_BYTES = new byte[]{ 0, 0, 0, 0, 0, 0, 0, 0, }; + /* an even number of NUL bytes used during the handshake */ + private static final byte[] NUL_BYTES = new byte[]{ 0, 0, 0, 0, 0, 0, 0, 0, }; + + /* A mapping between hash algorithm names as used in the MAPI + * protocol, and the names by which the Java runtime knows them. + */ private static final String[][] KNOWN_ALGORITHMS = new String[][] { {"SHA512", "SHA-512"}, {"SHA384", "SHA-384"}, @@ -262,6 +266,26 @@ public final class MapiSocket { return connect(new Target(url, props), null); } + /** + * Connect according to the settings in the 'target' parameter. + * If followRedirect is false, a RedirectionException is + * thrown when a redirect is encountered. + * + * Some settings, such as the initial reply size, can already be configured + * during the handshake, saving a command round-trip later on. + * To do so, create and pass a subclass of {@link MapiSocket.OptionsCallback}. + * + * @param target the connection settings + * @param callback will be called if the server allows options to be set during the + * initial handshake + * @return A List with informational (warning) messages. If this + * list is empty; then there are no warnings. + * @throws IOException if an I/O error occurs when creating the socket + * @throws SocketException - if there is an error in the underlying protocol, such as a TCP error. + * @throws UnknownHostException if the IP address of the host could not be determined + * @throws MCLParseException if bogus data is received + * @throws MCLException if an MCL related error occurs + */ public List<String> connect(Target target, OptionsCallback callback) throws MCLException, MCLParseException, IOException { // get rid of any earlier connection state, including the existing target close(); @@ -521,7 +545,7 @@ public final class MapiSocket { } return digest; } - String algoNames = algos.stream().collect(Collectors.joining()); + String algoNames = String.join(",", algos); throw new MCLException("No supported hash algorithm: " + algoNames); } @@ -1448,9 +1472,35 @@ public final class MapiSocket { } } + /** + * Callback used during the initial MAPI handshake. + * + * Newer MonetDB versions allow setting some options during the handshake. + * The options are language-specific and each has a 'level'. The server + * advertises up to which level options are supported for a given language + * and for each language/option combination, {@link addOptions} will be invoked. + * It should call {@link contribute} for each option it wants to set. + * + * At the time of writing, only the 'sql' language supports options, + * they are listed in enum mapi_handshake_options_levels in mapi.h. + */ public static abstract class OptionsCallback { private StringBuilder buffer; + /** + * Callback called for each language/level combination supported by the + * server. May call {@link contribute} for options with a level STRICTLY + * LOWER than the level passed as a parameter. + * @param lang language advertised by the server + * @param level one higher than the maximum supported option + */ + public abstract void addOptions(String lang, int level); + + /** + * Pass option=value during the handshake + * @param field + * @param value + */ protected void contribute(String field, int value) { if (buffer.length() > 0) buffer.append(','); @@ -1459,7 +1509,6 @@ public final class MapiSocket { buffer.append(value); } - public abstract void addOptions(String lang, int level); void setBuffer(StringBuilder buf) { buffer = buf; diff --git a/src/main/java/org/monetdb/mcl/net/MonetUrlParser.java b/src/main/java/org/monetdb/mcl/net/MonetUrlParser.java --- a/src/main/java/org/monetdb/mcl/net/MonetUrlParser.java +++ b/src/main/java/org/monetdb/mcl/net/MonetUrlParser.java @@ -6,270 +6,275 @@ import java.net.URISyntaxException; import java.net.URLDecoder; import java.net.URLEncoder; +/** + * Helper class to keep the URL parsing code separate from the rest of + * the {@link Target} class. + */ public class MonetUrlParser { - private final Target target; - private final String urlText; - private final URI url; + private final Target target; + private final String urlText; + private final URI url; - public MonetUrlParser(Target target, String url) throws URISyntaxException { - this.target = target; - this.urlText = url; - // we want to accept monetdb:// but the Java URI parser rejects that. - switch (url) { - case "monetdb:-": - case "monetdbs:-": - throw new URISyntaxException(url, "invalid MonetDB URL"); - case "monetdb://": - case "monetdbs://": - url += "-"; - break; - } - this.url = new URI(url); - } + private MonetUrlParser(Target target, String url) throws URISyntaxException { + this.target = target; + this.urlText = url; + // we want to accept monetdb:// but the Java URI parser rejects that. + switch (url) { + case "monetdb:-": + case "monetdbs:-": _______________________________________________ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org