Changeset: 8368cbc670bf for monetdb-java URL: https://dev.monetdb.org/hg/monetdb-java?cmd=changeset;node=8368cbc670bf Added Files: src/main/java/org/monetdb/mcl/net/HandshakeOptions.java Modified Files: src/main/java/org/monetdb/jdbc/MonetConnection.java src/main/java/org/monetdb/mcl/net/MapiSocket.java Branch: default Log Message:
Send reply size and time zone during initial handshake diffs (233 lines): 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 @@ -35,6 +35,7 @@ import java.util.concurrent.Executor; import org.monetdb.mcl.io.BufferedMCLReader; import org.monetdb.mcl.io.BufferedMCLWriter; +import org.monetdb.mcl.net.HandshakeOptions; import org.monetdb.mcl.net.MapiSocket; import org.monetdb.mcl.parser.HeaderLineParser; import org.monetdb.mcl.parser.MCLParseException; @@ -257,6 +258,14 @@ public class MonetConnection server.setDatabase(database); server.setLanguage(language); + HandshakeOptions handshakeOptions = new HandshakeOptions(); + final Calendar cal = Calendar.getInstance(); + int offsetMillis = cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET); + int offsetSeconds = offsetMillis / 1000; + handshakeOptions.setTimeZone(offsetSeconds); + handshakeOptions.setReplySize(DEF_FETCHSIZE); + server.setHandshakeOptions(handshakeOptions); + // we're debugging here... uhm, should be off in real life if (debug) { try { @@ -336,20 +345,27 @@ public class MonetConnection lang = LANG_UNKNOWN; } + if (!handshakeOptions.mustSendReplySize()) { + // Initially, it had to be sent. If it no more needs to be sent now, + // it must have been sent during the auth challenge/response. + // Record the value it was set to. + this.curReplySize = handshakeOptions.getReplySize(); + } + // the following initialisers are only valid when the language is SQL... if (lang == LANG_SQL) { // enable auto commit setAutoCommit(true); - // set our time zone on the server - final Calendar cal = Calendar.getInstance(); - int offset = cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET); - offset /= (60 * 1000); // milliseconds to minutes - String tz = offset < 0 ? "-" : "+"; - tz += (Math.abs(offset) / 60 < 10 ? "0" : "") + (Math.abs(offset) / 60) + ":"; - offset -= (offset / 60) * 60; - tz += (offset < 10 ? "0" : "") + offset; - sendIndependentCommand("SET TIME ZONE INTERVAL '" + tz + "' HOUR TO MINUTE"); + // set our time zone on the server, if we haven't already + if (handshakeOptions.mustSendTimeZone()) { + int offsetMinutes = handshakeOptions.getTimeZone() / 60; + String tz = offsetMinutes < 0 ? "-" : "+"; + tz += (Math.abs(offsetMinutes) / 60 < 10 ? "0" : "") + (Math.abs(offsetMinutes) / 60) + ":"; + offsetMinutes -= (offsetMinutes / 60) * 60; + tz += (offsetMinutes < 10 ? "0" : "") + offsetMinutes; + sendIndependentCommand("SET TIME ZONE INTERVAL '" + tz + "' HOUR TO MINUTE"); + } } // we're absolutely not closed, since we're brand new diff --git a/src/main/java/org/monetdb/mcl/net/HandshakeOptions.java b/src/main/java/org/monetdb/mcl/net/HandshakeOptions.java new file mode 100644 --- /dev/null +++ b/src/main/java/org/monetdb/mcl/net/HandshakeOptions.java @@ -0,0 +1,98 @@ +package org.monetdb.mcl.net; + +/** Keep track of MAPI handshake options. + * + * Recent server versions allow you to send configuration information during + * the authentication handshake so no additional round trips are necessary + * when that has completed. + * + * This class keeps track of the options to send, and whether they have already + * been sent. + */ +public class HandshakeOptions { + + // public Boolean autoCommit; + int replySize; + // public Integer replySize; + // public Integer ColumnarProtocol; + int timeZone; + + boolean mustSendReplySize; + boolean mustSendTimeZone; + + public int getReplySize() { + return replySize; + } + + public void setReplySize(int replySize) { + this.replySize = replySize; + this.mustSendReplySize = true; + } + + public boolean mustSendReplySize() { + return mustSendReplySize; + } + + public void mustSendReplySize(boolean mustSendReplySize) { + this.mustSendReplySize = mustSendReplySize; + } + + public int getTimeZone() { + return timeZone; + } + + public void setTimeZone(int timeZone) { + this.timeZone = timeZone; + this.mustSendTimeZone = true; + } + + public boolean mustSendTimeZone() { + return mustSendTimeZone; + } + + public void mustSendTimeZone(boolean mustSendTimeZone) { + this.mustSendTimeZone = mustSendTimeZone; + } + + public String formatResponse(int serverLevel) { + StringBuilder opts = new StringBuilder(100); + if (mustSendReplySize()) { + formatOption(opts, Level.ReplySize, serverLevel, replySize); + mustSendReplySize(false); + } + if (mustSendTimeZone()) { + formatOption(opts, Level.TimeZone, serverLevel, timeZone); + mustSendTimeZone(false); + } + + return opts.toString(); + } + + private void formatOption(StringBuilder opts, Level level, int serverLevel, int value) { + if (!level.isSupported(serverLevel)) + return; + if (opts.length() > 0) { + opts.append(","); + } + opts.append(level.field); + opts.append("="); + opts.append(value); + } + + public enum Level { + ReplySize("reply_size", 2), + TimeZone("time_zone", 5); + + private final int level; + private final String field; + + Level(String field, int level) { + this.field = field; + this.level = level; + } + + public boolean isSupported(int serverLevel) { + return this.level < serverLevel; + } + } +} 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 @@ -122,6 +122,9 @@ public class MapiSocket { /* cannot (yet /** A short in two bytes for holding the block size in bytes */ private final byte[] blklen = new byte[2]; + /** Options that can be sent during the auth handshake if the server supports it */ + private HandshakeOptions handshakeOptions; + /** * Constructs a new MapiSocket. */ @@ -533,11 +536,33 @@ public class MapiSocket { /* cannot (yet } // compose and return response - return "BIG:" // JVM byte-order is big-endian - + username + ":" - + pwhash + ":" - + language + ":" - + (database == null ? "" : database) + ":"; + String response = "BIG:" // JVM byte-order is big-endian + + username + ":" + + pwhash + ":" + + language + ":" + + (database == null ? "" : database) + ":"; + if (chaltok.length > 6) { + // this ':' delimits the FILETRANS field, currently empty because we don't support it. + response += ":"; + + // if supported, send handshake options + for (String part : chaltok[6].split(",")) { + if (part.startsWith("sql=") && handshakeOptions != null) { + int level; + try { + level = Integer.parseInt(chaltok[6].substring(4)); + } catch (NumberFormatException e) { + throw new MCLParseException("Invalid handshake level: " + chaltok[6]); + } + response += handshakeOptions.formatResponse(level); + break; + } + } + // this ':' delimits the handshake options field. + response += ":"; + + } + return response; default: throw new MCLException("Unsupported protocol version: " + version); } @@ -687,6 +712,14 @@ public class MapiSocket { /* cannot (yet log.flush(); } + public void setHandshakeOptions(HandshakeOptions handshakeOptions) { + this.handshakeOptions = handshakeOptions; + } + + public HandshakeOptions getHandshakeOptions() { + return handshakeOptions; + } + /** * Inner class that is used to write data on a normal stream as a * blocked stream. A call to the flush() method will write a _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list