changeset 656:c6fe5dfecafc

Refactor HandshakeOptions
author Joeri van Ruth <joeri.van.ruth@monetdbsolutions.com>
date Fri, 09 Sep 2022 12:25:23 +0200 (2022-09-09)
parents 2ded26c5a679
children 8476d6f4378f
files src/main/java/org/monetdb/jdbc/MonetConnection.java src/main/java/org/monetdb/mcl/net/HandshakeOptions.java src/main/java/org/monetdb/mcl/net/MapiSocket.java
diffstat 3 files changed, 75 insertions(+), 69 deletions(-) [+]
line wrap: on
line diff
--- a/src/main/java/org/monetdb/jdbc/MonetConnection.java
+++ b/src/main/java/org/monetdb/jdbc/MonetConnection.java
@@ -37,6 +37,7 @@ import org.monetdb.mcl.io.BufferedMCLRea
 import org.monetdb.mcl.io.BufferedMCLWriter;
 import org.monetdb.mcl.io.LineType;
 import org.monetdb.mcl.net.HandshakeOptions;
+import org.monetdb.mcl.net.HandshakeOptions.Setting;
 import org.monetdb.mcl.net.MapiSocket;
 import org.monetdb.mcl.parser.HeaderLineParser;
 import org.monetdb.mcl.parser.MCLParseException;
@@ -287,8 +288,8 @@ public class MonetConnection
 		int offsetMillis = cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET);
 		int offsetSeconds = offsetMillis / 1000;
 		final HandshakeOptions handshakeOptions = new HandshakeOptions();
-		handshakeOptions.setTimeZone(offsetSeconds);
-		handshakeOptions.setReplySize(defaultFetchSize);
+		handshakeOptions.set(Setting.TimeZone, offsetSeconds);
+		handshakeOptions.set(Setting.ReplySize, defaultFetchSize);
 		server.setHandshakeOptions(handshakeOptions);
 
 		// we're debugging here... uhm, should be off in real life
@@ -370,11 +371,18 @@ 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 reply size is checked before every query and adjusted if
+		// necessary. Update our current belief of what the server is set to.
+		if (handshakeOptions.wasSentInHandshake(HandshakeOptions.Setting.ReplySize)) {
+			this.curReplySize = handshakeOptions.get(HandshakeOptions.Setting.ReplySize);
+		}
+
+		for (Setting setting : new Setting[] { Setting.SizeHeader }) {
+			if (handshakeOptions.mustSend(setting)) {
+				Integer value = handshakeOptions.get(setting); // guaranteed by mustSend to be non-null
+				String command = String.format("%s %d", setting.getXCommand(), value);
+				sendControlCommand(command);
+			}
 		}
 
 		// the following initialisers are only valid when the language is SQL...
@@ -383,10 +391,10 @@ public class MonetConnection
 			setAutoCommit(true);
 
 			// set our time zone on the server, if we haven't already
-			if (handshakeOptions.mustSendTimeZone()) {
+			if (handshakeOptions.mustSend(Setting.TimeZone)) {
 				final StringBuilder tz = new StringBuilder(64);
 				tz.append("SET TIME ZONE INTERVAL '");
-				int offsetMinutes = handshakeOptions.getTimeZone() / 60;
+				int offsetMinutes = handshakeOptions.get(Setting.TimeZone) / 60;
 				if (offsetMinutes < 0) {
 					tz.append('-');
 					offsetMinutes = -offsetMinutes; // make it positive
--- a/src/main/java/org/monetdb/mcl/net/HandshakeOptions.java
+++ b/src/main/java/org/monetdb/mcl/net/HandshakeOptions.java
@@ -8,98 +8,96 @@
 
 package org.monetdb.mcl.net;
 
+import java.util.HashMap;
+import java.util.Map;
+
 /** Keep track of MAPI handshake options.
  *
  * Recent server versions (from 2021) 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.
+ * This class keeps track of the values themselves, and also of whether or not they should still be sent.
  */
 final public class HandshakeOptions {
-
-	// public Boolean autoCommit;
-	int replySize;
-	// public Integer ColumnarProtocol;
-	int timeZone;
+	HashMap<Setting,Integer> options = new HashMap<>();
+	int handshakeLevel = 0;
 
-	boolean mustSendReplySize;
-	boolean mustSendTimeZone;
-
-	public int getReplySize() {
-		return replySize;
+	public void set(Setting setting, int value) {
+		options.put(setting, value);
 	}
 
-	public void setReplySize(int replySize) {
-		this.replySize = replySize;
-		this.mustSendReplySize = true;
+	public Integer get(Setting setting) {
+		return options.get(setting);
 	}
 
-	public boolean mustSendReplySize() {
-		return mustSendReplySize;
+	public boolean wasSentInHandshake(Setting setting) {
+		return setting.isSupported(this.handshakeLevel);
 	}
 
-	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 mustSend(Setting setting) {
+		if (wasSentInHandshake(setting)) {
+			return false;
+		}
+		Integer value = options.get(setting);
+		return value != null && value != setting.defaultValue;
 	}
 
-	public boolean mustSendTimeZone() {
-		return mustSendTimeZone;
-	}
-
-	public void mustSendTimeZone(boolean mustSendTimeZone) {
-		this.mustSendTimeZone = mustSendTimeZone;
-	}
+	public String formatHandshakeResponse(int serverLevel) {
+		StringBuilder opts = new StringBuilder(100);
 
-	public String formatResponse(int serverLevel) {
-		StringBuilder opts = new StringBuilder(100);
-		if (mustSendReplySize()) {
-			formatOption(opts, Level.ReplySize, serverLevel, replySize);
-			mustSendReplySize(false);
+		for (Map.Entry<Setting, Integer> entry: options.entrySet()) {
+			Setting setting = entry.getKey();
+			Integer value = entry.getValue();
+			if (setting.isSupported(serverLevel)) {
+				if (opts.length() > 0) {
+					opts.append(",");
+				}
+				opts.append(setting.field);
+				opts.append("=");
+				opts.append(value);
+			}
 		}
-		if (mustSendTimeZone()) {
-			formatOption(opts, Level.TimeZone, serverLevel, timeZone);
-			mustSendTimeZone(false);
-		}
+
+		this.handshakeLevel = serverLevel;
 
 		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);
+	public enum Setting {
+		AutoCommit("auto_commit", 1, 1),
+		ReplySize("reply_size", 2, 100),
+		SizeHeader("size_header", "sizeheader", 3, 0),
+		// ColumnarProtocol("columnar_protocol", 4),
+		TimeZone("time_zone", 5, 0),
+		;
 
 		private final int level;
 		private final String field;
+		private final String xcommand;
+		private final int defaultValue;
 
-		Level(String field, int level) {
+		Setting(String field, int level, int defaultValue) {
+			this(field, field, level, defaultValue);
+		}
+
+		Setting(String field, String xcommand, int level, int defaultValue) {
 			this.field = field;
+			this.xcommand = xcommand;
 			this.level = level;
+			this.defaultValue = defaultValue;
 		}
 
 		public boolean isSupported(int serverLevel) {
 			return this.level < serverLevel;
 		}
+
+		public String getXCommand() {
+			return xcommand;
+		}
+
+		public Integer getDefaultValue() {
+			return defaultValue;
+		}
 	}
 }
--- a/src/main/java/org/monetdb/mcl/net/MapiSocket.java
+++ b/src/main/java/org/monetdb/mcl/net/MapiSocket.java
@@ -562,7 +562,7 @@ public class MapiSocket {	/* cannot (yet
 							} catch (NumberFormatException e) {
 								throw new MCLParseException("Invalid handshake level: " + chaltok[6]);
 							}
-							response += handshakeOptions.formatResponse(level);
+							response += handshakeOptions.formatHandshakeResponse(level);
 							break;
 						}
 					}