Mercurial > hg > monetdb-java
comparison src/main/java/org/monetdb/jdbc/MonetConnection.java @ 671:fade6c6960cc
Refactor Handshake options
It was not clear and there were obscure bugs.
author | Joeri van Ruth <joeri.van.ruth@monetdbsolutions.com> |
---|---|
date | Fri, 28 Oct 2022 16:16:00 +0200 (2022-10-28) |
parents | 2448ce017593 |
children | 8464a17caedf |
comparison
equal
deleted
inserted
replaced
670:3034312c1eda | 671:fade6c6960cc |
---|---|
34 import java.util.concurrent.Executor; | 34 import java.util.concurrent.Executor; |
35 | 35 |
36 import org.monetdb.mcl.io.BufferedMCLReader; | 36 import org.monetdb.mcl.io.BufferedMCLReader; |
37 import org.monetdb.mcl.io.BufferedMCLWriter; | 37 import org.monetdb.mcl.io.BufferedMCLWriter; |
38 import org.monetdb.mcl.io.LineType; | 38 import org.monetdb.mcl.io.LineType; |
39 import org.monetdb.mcl.net.HandshakeOptions; | 39 import org.monetdb.mcl.net.HandshakeOption; |
40 import org.monetdb.mcl.net.HandshakeOptions.Setting; | |
41 import org.monetdb.mcl.net.MapiSocket; | 40 import org.monetdb.mcl.net.MapiSocket; |
42 import org.monetdb.mcl.parser.HeaderLineParser; | 41 import org.monetdb.mcl.parser.HeaderLineParser; |
43 import org.monetdb.mcl.parser.MCLParseException; | 42 import org.monetdb.mcl.parser.MCLParseException; |
44 import org.monetdb.mcl.parser.StartOfHeaderParser; | 43 import org.monetdb.mcl.parser.StartOfHeaderParser; |
45 | 44 |
164 * @throws IllegalArgumentException is one of the arguments is null or empty | 163 * @throws IllegalArgumentException is one of the arguments is null or empty |
165 */ | 164 */ |
166 MonetConnection(final Properties props) | 165 MonetConnection(final Properties props) |
167 throws SQLException, IllegalArgumentException | 166 throws SQLException, IllegalArgumentException |
168 { | 167 { |
169 // for debug: System.out.println("New connection object. Received properties are: " + props.toString()); | 168 HandshakeOption.AutoCommit autoCommitSetting = new HandshakeOption.AutoCommit(true); |
169 HandshakeOption.ReplySize replySizeSetting = new HandshakeOption.ReplySize(DEF_FETCHSIZE); | |
170 HandshakeOption.SizeHeader sizeHeaderSetting = new HandshakeOption.SizeHeader(true); | |
171 HandshakeOption.TimeZone timeZoneSetting = new HandshakeOption.TimeZone(0); | |
172 | |
173 // for debug: System.out.println("New connection object. Received properties are: " + props.toString()); | |
170 // get supported property values from the props argument. | 174 // get supported property values from the props argument. |
171 // When a value is found add it to the internal conn_props list for use by getClientInfo(). | 175 // When a value is found add it to the internal conn_props list for use by getClientInfo(). |
172 this.hostname = props.getProperty("host"); | 176 this.hostname = props.getProperty("host"); |
173 if (this.hostname != null) | 177 if (this.hostname != null) |
174 conn_props.setProperty("host", this.hostname); | 178 conn_props.setProperty("host", this.hostname); |
209 final String hash = props.getProperty("hash"); | 213 final String hash = props.getProperty("hash"); |
210 if (hash != null) | 214 if (hash != null) |
211 conn_props.setProperty("hash", hash); | 215 conn_props.setProperty("hash", hash); |
212 | 216 |
213 String autocommit_prop = props.getProperty("autocommit"); | 217 String autocommit_prop = props.getProperty("autocommit"); |
214 boolean initial_autocommit = true; | |
215 if (autocommit_prop != null) { | 218 if (autocommit_prop != null) { |
216 initial_autocommit = Boolean.parseBoolean(autocommit_prop); | 219 boolean ac = Boolean.parseBoolean(autocommit_prop); |
217 conn_props.setProperty("autocommit", Boolean.toString(initial_autocommit)); | 220 autoCommitSetting.set(ac); |
221 conn_props.setProperty("autocommit", Boolean.toString(ac)); | |
218 } | 222 } |
219 | 223 |
220 final String fetchsize_prop = props.getProperty("fetchsize"); | 224 final String fetchsize_prop = props.getProperty("fetchsize"); |
221 if (fetchsize_prop != null) { | 225 if (fetchsize_prop != null) { |
222 try { | 226 try { |
223 int fetchsize = Integer.parseInt(fetchsize_prop); | 227 int fetchsize = Integer.parseInt(fetchsize_prop); |
224 if (fetchsize > 0 || fetchsize == -1) { | 228 if (fetchsize > 0 || fetchsize == -1) { |
225 this.defaultFetchSize = fetchsize; | 229 replySizeSetting.set(fetchsize); |
226 conn_props.setProperty("fetchsize", fetchsize_prop); | 230 conn_props.setProperty("fetchsize", fetchsize_prop); |
227 } else { | 231 } else { |
228 addWarning("Fetch size must either be positive or -1. Value " + fetchsize + " ignored", "M1M05"); | 232 addWarning("Fetch size must either be positive or -1. Value " + fetchsize + " ignored", "M1M05"); |
229 } | 233 } |
230 } catch (NumberFormatException e) { | 234 } catch (NumberFormatException e) { |
289 server.setHash(hash); | 293 server.setHash(hash); |
290 if (database != null) | 294 if (database != null) |
291 server.setDatabase(database); | 295 server.setDatabase(database); |
292 server.setLanguage(language); | 296 server.setLanguage(language); |
293 | 297 |
298 // calculate our time zone offset | |
294 final Calendar cal = Calendar.getInstance(); | 299 final Calendar cal = Calendar.getInstance(); |
295 int offsetMillis = cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET); | 300 int offsetMillis = cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET); |
296 int offsetSeconds = offsetMillis / 1000; | 301 int offsetSeconds = offsetMillis / 1000; |
297 final HandshakeOptions handshakeOptions = new HandshakeOptions(); | 302 timeZoneSetting.set(offsetSeconds); |
298 handshakeOptions.set(Setting.AutoCommit, initial_autocommit ? 1 : 0); | 303 |
299 handshakeOptions.set(Setting.TimeZone, offsetSeconds); | 304 server.setHandshakeOptions(new HandshakeOption[] { |
300 handshakeOptions.set(Setting.ReplySize, defaultFetchSize); | 305 autoCommitSetting, |
301 // handshakeOptions.set(Setting.SizeHeader, 1); | 306 replySizeSetting, |
302 server.setHandshakeOptions(handshakeOptions); | 307 sizeHeaderSetting, |
303 autoCommit = initial_autocommit; | 308 timeZoneSetting, |
309 }); | |
304 | 310 |
305 // we're debugging here... uhm, should be off in real life | 311 // we're debugging here... uhm, should be off in real life |
306 if (debug) { | 312 if (debug) { |
307 try { | 313 try { |
308 final String fname = props.getProperty("logfile", "monet_" + System.currentTimeMillis() + ".log"); | 314 final String fname = props.getProperty("logfile", "monet_" + System.currentTimeMillis() + ".log"); |
379 //commandTempl[2] = ""; // separator (is not used) | 385 //commandTempl[2] = ""; // separator (is not used) |
380 } else { | 386 } else { |
381 lang = LANG_UNKNOWN; | 387 lang = LANG_UNKNOWN; |
382 } | 388 } |
383 | 389 |
384 // The reply size is checked before every query and adjusted if | 390 // Now take care of any handshake options not handled during the handshake |
385 // necessary. Update our current belief of what the server is set to. | 391 if (replySizeSetting.isSent()) { |
386 if (handshakeOptions.wasSentInHandshake(HandshakeOptions.Setting.ReplySize)) { | 392 this.curReplySize = replySizeSetting.get(); |
387 this.curReplySize = handshakeOptions.get(HandshakeOptions.Setting.ReplySize); | 393 } |
388 } | 394 this.defaultFetchSize = replySizeSetting.get(); |
389 | |
390 for (Setting setting : new Setting[] { Setting.SizeHeader }) { | |
391 if (handshakeOptions.mustSend(setting)) { | |
392 Integer value = handshakeOptions.get(setting); // guaranteed by mustSend to be non-null | |
393 String command = String.format("%s %d", setting.getXCommand(), value); | |
394 sendControlCommand(command); | |
395 } | |
396 } | |
397 | |
398 // the following initialisers are only valid when the language is SQL... | |
399 if (lang == LANG_SQL) { | 395 if (lang == LANG_SQL) { |
400 if (handshakeOptions.mustSend(Setting.AutoCommit)) { | 396 if (autoCommitSetting.mustSend(autoCommit)) { |
401 setAutoCommit(handshakeOptions.get(Setting.AutoCommit) != 0); | 397 setAutoCommit(autoCommitSetting.get()); |
402 } | 398 } |
403 | 399 if (sizeHeaderSetting.mustSend(false)) { |
404 // set our time zone on the server, if we haven't already | 400 sendControlCommand("sizeheader 1"); |
405 if (handshakeOptions.mustSend(Setting.TimeZone)) { | 401 } |
406 final StringBuilder tz = new StringBuilder(64); | 402 if (timeZoneSetting.mustSend(0)) { |
407 tz.append("SET TIME ZONE INTERVAL '"); | 403 setTimezone(timeZoneSetting.get()); |
408 int offsetMinutes = handshakeOptions.get(Setting.TimeZone) / 60; | 404 } |
409 if (offsetMinutes < 0) { | |
410 tz.append('-'); | |
411 offsetMinutes = -offsetMinutes; // make it positive | |
412 } else { | |
413 tz.append('+'); | |
414 } | |
415 int offsetHours = offsetMinutes / 60; | |
416 if (offsetHours < 10) | |
417 tz.append('0'); | |
418 tz.append(offsetHours).append(':'); | |
419 offsetMinutes -= offsetHours * 60; | |
420 if (offsetMinutes < 10) | |
421 tz.append('0'); | |
422 tz.append(offsetMinutes).append("' HOUR TO MINUTE"); | |
423 sendIndependentCommand(tz.toString()); | |
424 } | |
425 | |
426 // set sizeheader to 1 to enable sending "typesizes" info by the server (see mapi_set_size_header() in mapi.c) | |
427 sendControlCommand("sizeheader 1"); | |
428 } | 405 } |
429 | 406 |
430 // we're absolutely not closed, since we're brand new | 407 // we're absolutely not closed, since we're brand new |
431 closed = false; | 408 closed = false; |
432 } | 409 } |
1735 /** | 1712 /** |
1736 * @return the currently registerered {@link DownloadHandler} handler, or null | 1713 * @return the currently registerered {@link DownloadHandler} handler, or null |
1737 */ | 1714 */ |
1738 public DownloadHandler getDownloadHandler() { | 1715 public DownloadHandler getDownloadHandler() { |
1739 return downloadHandler; | 1716 return downloadHandler; |
1717 } | |
1718 | |
1719 public void setTimezone(int offsetSeconds) throws SQLException { | |
1720 final StringBuilder tz = new StringBuilder(64); | |
1721 tz.append("SET TIME ZONE INTERVAL '"); | |
1722 int offsetMinutes = offsetSeconds / 60; | |
1723 if (offsetMinutes < 0) { | |
1724 tz.append('-'); | |
1725 offsetMinutes = -offsetMinutes; // make it positive | |
1726 } else { | |
1727 tz.append('+'); | |
1728 } | |
1729 int offsetHours = offsetMinutes / 60; | |
1730 if (offsetHours < 10) | |
1731 tz.append('0'); | |
1732 tz.append(offsetHours).append(':'); | |
1733 offsetMinutes -= offsetHours * 60; | |
1734 if (offsetMinutes < 10) | |
1735 tz.append('0'); | |
1736 tz.append(offsetMinutes).append("' HOUR TO MINUTE"); | |
1737 sendIndependentCommand(tz.toString()); | |
1740 } | 1738 } |
1741 | 1739 |
1742 /** | 1740 /** |
1743 * Local helper method to test whether the Connection object is closed | 1741 * Local helper method to test whether the Connection object is closed |
1744 * When closed it throws an SQLException | 1742 * When closed it throws an SQLException |