comparison src/main/java/nl/cwi/monetdb/jdbc/MonetConnection.java @ 172:60063c67f9e7 embedded

Merged with default
author Pedro Ferreira <pedro.ferreira@monetdbsolutions.com>
date Tue, 19 Sep 2017 13:49:34 +0200 (2017-09-19)
parents 6c74540a8e6b 89e954e7acbb
children 89c285fc0a49
comparison
equal deleted inserted replaced
171:0f95fee3cf29 172:60063c67f9e7
9 import nl.cwi.monetdb.mcl.protocol.ServerResponses; 9 import nl.cwi.monetdb.mcl.protocol.ServerResponses;
10 import nl.cwi.monetdb.mcl.protocol.StarterHeaders; 10 import nl.cwi.monetdb.mcl.protocol.StarterHeaders;
11 import nl.cwi.monetdb.mcl.responses.*; 11 import nl.cwi.monetdb.mcl.responses.*;
12 12
13 import java.io.IOException; 13 import java.io.IOException;
14 import java.net.SocketException;
14 import java.net.SocketTimeoutException; 15 import java.net.SocketTimeoutException;
15 import java.sql.*; 16 import java.sql.*;
16 import java.util.*; 17 import java.util.*;
17 import java.util.concurrent.Executor; 18 import java.util.concurrent.Executor;
18 19
39 * whole Connection interface. 40 * whole Connection interface.
40 * 41 *
41 * @author Fabian Groffen, Martin van Dinther, Pedro Ferreira 42 * @author Fabian Groffen, Martin van Dinther, Pedro Ferreira
42 * @version 1.3 43 * @version 1.3
43 */ 44 */
44 public abstract class MonetConnection extends MonetWrapper implements Connection { 45 public abstract class MonetConnection extends MonetWrapper implements Connection, AutoCloseable {
45 46
46 /** The sequence counter */ 47 /** The sequence counter */
47 private static int SeqCounter = 0; 48 private static int SeqCounter = 0;
48 49
49 /** 50 /**
50 * Gets the current sequence counter. 51 * Gets the current sequence counter.
51 * 52 *
52 * @return The current sequence counter 53 * @return The current sequence counter
53 */ 54 */
54 public static int getSeqCounter() { 55 public static int getSeqCounter() {
55 return SeqCounter; 56 return SeqCounter;
56 } 57 }
57 58
58 /** The successful processed input properties */ 59 /** The successful processed input properties */
59 protected final Properties conn_props; 60 protected final Properties conn_props;
60 /** The language to connect with */ 61 /** The language to connect with */
61 protected IMonetDBLanguage language; 62 protected IMonetDBLanguage language;
62 /** Authentication hash method */ 63 /** Authentication hash method */
63 protected final String hash; 64 protected final String hash;
64 /** An optional thread that is used for sending large queries */ 65 /** An optional thread that is used for sending large queries */
65 private SenderThread senderThread; 66 private SenderThread senderThread;
66 /** Whether this Connection is closed (and cannot be used anymore) */ 67 /** Whether this Connection is closed (and cannot be used anymore) */
67 private boolean closed; 68 private boolean closed;
68 /** Whether this Connection is in autocommit mode */ 69 /** Whether this Connection is in autocommit mode */
69 private boolean autoCommit = true; 70 private boolean autoCommit = true;
70 /** The stack of warnings for this Connection object */ 71 /** The stack of warnings for this Connection object */
71 private SQLWarning warnings; 72 private SQLWarning warnings;
72 /** The Connection specific mapping of user defined types to Java types */ 73 /** The Connection specific mapping of user defined types to Java types */
73 private Map<String,Class<?>> typeMap = new HashMap<String,Class<?>>() { 74 private Map<String,Class<?>> typeMap = new HashMap<String,Class<?>>() {
74 private static final long serialVersionUID = 1L; { 75 private static final long serialVersionUID = 1L; {
75 put("inet", MonetINET.class); 76 put("inet", MonetINET.class);
76 put("url", MonetURL.class); 77 put("url", MonetURL.class);
77 } 78 }
78 }; 79 };
79 80
80 // See javadoc for documentation about WeakHashMap if you don't know what it does !!!NOW!!! 81 // See javadoc for documentation about WeakHashMap if you don't know what it does !!!NOW!!!
81 // (only when you deal with it of course) 82 // (only when you deal with it of course)
82 /** A Map containing all (active) Statements created from this Connection */ 83 /** A Map containing all (active) Statements created from this Connection */
83 private Map<Statement,?> statements = new WeakHashMap<>(); 84 private Map<Statement,?> statements = new WeakHashMap<>();
84 /** The number of results we receive from the server at once */ 85 /** The number of results we receive from the server at once */
85 private int curReplySize = -1; // the server by default uses -1 (all) 86 private int curReplySize = -1; // the server by default uses -1 (all)
86 /** Whether or not BLOB is mapped to LONGVARBINARY within the driver */ 87 /** Whether or not BLOB is mapped to LONGVARBINARY within the driver */
87 private final boolean blobIsBinary; 88 private final boolean blobIsBinary;
88 /** Whether or not CLOB is mapped to LONGVARCHAR within the driver */ 89 /** Whether or not CLOB is mapped to LONGVARCHAR within the driver */
89 private final boolean clobIsLongChar; 90 private final boolean clobIsLongChar;
90 /** The underlying proticol provided by the connection (MAPI or embedded) */ 91 /** The underlying proticol provided by the connection (MAPI or embedded) */
91 protected AbstractProtocol protocol; 92 protected AbstractProtocol protocol;
92 /** Tells if the connection is embedded or not */ 93 /** Tells if the connection is embedded or not */
93 private final boolean isEmbedded; 94 private final boolean isEmbedded;
94 95
95 /** 96 /**
96 * Constructor of a Connection for MonetDB. At this moment the current implementation limits itself to storing the 97 * Constructor of a Connection for MonetDB. At this moment the current implementation limits itself to storing the
97 * given host, database, username and password for later use by the createStatement() call. This constructor is 98 * given host, database, username and password for later use by the createStatement() call. This constructor is
98 * only accessible to classes from the jdbc package. 99 * only accessible to classes from the jdbc package.
99 * 100 */
100 * @throws IOException if an error occurs 101 public MonetConnection(Properties props, String hash, IMonetDBLanguage language, boolean blobIsBinary,
101 */ 102 boolean clobIsLongChar) {
102 public MonetConnection(Properties props, String hash, IMonetDBLanguage language, boolean blobIsBinary, 103 this.conn_props = props;
103 boolean clobIsLongChar) throws IOException { 104 this.hash = hash;
104 this.conn_props = props; 105 this.language = language;
105 this.hash = hash; 106 this.blobIsBinary = blobIsBinary;
106 this.language = language; 107 this.clobIsLongChar = clobIsLongChar;
107 this.blobIsBinary = blobIsBinary; 108 //"instance of" should be cleanner, but this is faster.
108 this.clobIsLongChar = clobIsLongChar; 109 this.isEmbedded = props.getProperty("embedded", "false").equals("true");
109 //"instance of" should be cleanner, but this is faster. 110 }
110 this.isEmbedded = props.getProperty("embedded", "false").equals("true"); 111
111 } 112 /**
112 113 * Checks if the conection is embedded or not
113 /** 114 *
114 * Checks if the conection is embedded or not 115 * @return If the connection is embedded
115 * 116 */
116 * @return If the connection is embedded 117 public boolean isEmbedded() {
117 */ 118 return isEmbedded;
118 public boolean isEmbedded() { 119 }
119 return isEmbedded; 120
120 } 121 /**
121 122 * Gets the connection's language data.
122 /** 123 *
123 * Gets the connection's language data. 124 * @return The connection's language data
124 * 125 */
125 * @return The connection's language data 126 public IMonetDBLanguage getLanguage() {
126 */ 127 return language;
127 public IMonetDBLanguage getLanguage() { 128 }
128 return language; 129
129 } 130 /**
130 131 * Gets the connection's protocol.
131 /** 132 *
132 * Gets the connection's protocol. 133 * @return The connection's protocol
133 * 134 */
134 * @return The connection's protocol 135 public AbstractProtocol getProtocol() {
135 */ 136 return this.protocol;
136 public AbstractProtocol getProtocol() { 137 }
137 return this.protocol; 138
138 } 139 /**
139 140 * Connects to the server, authenticating the user.
140 /** 141 *
141 * Connects to the server, authenticating the user. 142 * @param user The user name to authenticate
142 * 143 * @param pass The user's password
143 * @param user The user name to authenticate 144 * @return A List with informational (warning) messages. If this list is empty; then there are no warnings.
144 * @param pass The user's password 145 * @throws IOException if an I/O error occurs when creating the socket
145 * @return A List with informational (warning) messages. If this list is empty; then there are no warnings. 146 * @throws ProtocolException if bogus data is received
146 * @throws IOException if an I/O error occurs when creating the socket 147 * @throws MCLException if an MCL related error occurs
147 * @throws ProtocolException if bogus data is received 148 */
148 * @throws MCLException if an MCL related error occurs 149 public abstract List<String> connect(String user, String pass) throws IOException, ProtocolException, MCLException;
149 */ 150
150 public abstract List<String> connect(String user, String pass) throws IOException, ProtocolException, MCLException; 151 /**
151 152 * Gets the underlying connection block size length.
152 /** 153 *
153 * Gets the underlying connection block size length. 154 * @return The block size length
154 * 155 */
155 * @return The block size length 156 public abstract int getBlockSize();
156 */ 157
157 public abstract int getBlockSize(); 158 /**
158 159 * Gets the underlying connection default fetch size for DataBlock responses.
159 /** 160 *
160 * Gets the underlying connection default fetch size for DataBlock responses. 161 * @return The default fetch size
161 * 162 */
162 * @return The default fetch size 163 public abstract int getDefFetchsize();
163 */ 164
164 public abstract int getDefFetchsize(); 165 /**
165 166 * Gets the initial value for the StringBuilder size.
166 /** 167 *
167 * Gets the initial value for the StringBuilder size. 168 * @return The initial value for the StringBuilder size
168 * 169 */
169 * @return The initial value for the StringBuilder size 170 public abstract int initialStringBuilderSize();
170 */ 171
171 public abstract int initialStringBuilderSize(); 172 /**
172 173 * Gets the underlying connection socket timeout.
173 /** 174 *
174 * Gets the underlying connection socket timeout. 175 * @return The underlying connection socket timeout
175 * 176 */
176 * @return The underlying connection socket timeout 177 public abstract int getSoTimeout() throws SocketException;
177 */ 178
178 public abstract int getSoTimeout(); 179 /**
179 180 * Sets the underlying connection socket timeout.
180 /** 181 *
181 * Sets the underlying connection socket timeout. 182 * @param timeout The specified timeout, in milliseconds. A timeout of zero is interpreted as an infinite timeout
182 * 183 */
183 * @param timeout The specified timeout, in milliseconds. A timeout of zero is interpreted as an infinite timeout 184 public abstract void setSoTimeout(int timeout) throws SocketException;
184 */ 185
185 public abstract void setSoTimeout(int timeout); 186 /**
186 187 * Closes the underlying connection implementation.
187 /** 188 *
188 * Closes the underlying connection implementation. 189 * @throws IOException if an I/O error occurs while closing the connection
189 * 190 */
190 * @throws IOException if an I/O error occurs while closing the connection 191 public abstract void closeUnderlyingConnection() throws IOException;
191 */ 192
192 public abstract void closeUnderlyingConnection() throws IOException; 193 /**
193 194 * Gets the underlying connection JDBC String URL.
194 /** 195 *
195 * Gets the underlying connection JDBC String URL. 196 * @return The underlying connection JDBC String URL
196 * 197 */
197 * @return The underlying connection JDBC String URL 198 public abstract String getJDBCURL();
198 */ 199
199 public abstract String getJDBCURL(); 200 /**
200 201 * Sends a control command to the server.
201 /** 202 *
202 * Sends a control command to the server. 203 * @param commandID the command identifier according to {@link ControlCommands} listing
203 * 204 * @param data The integer to send according to the control command
204 * @param commandID the command identifier according to {@link ControlCommands} listing 205 * @throws SQLException if an IO exception or a database error occurs
205 * @param data The integer to send according to the control command 206 */
206 * @throws SQLException if an IO exception or a database error occurs 207 public abstract void sendControlCommand(int commandID, int data) throws SQLException;
207 */ 208
208 public abstract void sendControlCommand(int commandID, int data) throws SQLException; 209 /**
209 210 * Releases this Connection object's database and JDBC resources immediately instead of waiting for them to be
210 /** 211 * automatically released. All Statements created from this Connection will be closed when this method is called.
211 * Releases this Connection object's database and JDBC resources immediately instead of waiting for them to be 212 *
212 * automatically released. All Statements created from this Connection will be closed when this method is called. 213 * Calling the method close on a Connection object that is already closed is a no-op.
213 * 214 */
214 * Calling the method close on a Connection object that is already closed is a no-op. 215 @Override
215 */ 216 public void close() {
216 @Override 217 for (Statement st : statements.keySet()) {
217 public void close() { 218 try {
218 for (Statement st : statements.keySet()) { 219 st.close();
219 try { 220 } catch (SQLException e) {
220 st.close(); 221 // better luck next time!
221 } catch (SQLException e) { 222 }
222 // better luck next time! 223 }
223 } 224 // close the socket or the embedded server
224 } 225 try {
225 // close the socket or the embedded server 226 this.closeUnderlyingConnection();
226 try { 227 } catch (IOException e) {
227 this.closeUnderlyingConnection(); 228 // ignore it
228 } catch (IOException e) { 229 }
229 // ignore it 230 // close active SendThread if any
230 } 231 if (senderThread != null) {
231 // close active SendThread if any 232 senderThread.shutdown();
232 if (senderThread != null) { 233 senderThread = null;
233 senderThread.shutdown(); 234 }
234 senderThread = null; 235 // report ourselves as closed
235 } 236 closed = true;
236 // report ourselves as closed 237 }
237 closed = true; 238
238 } 239 /**
239 240 * Destructor called by garbage collector before destroying this object tries to disconnect the MonetDB connection
240 /** 241 * if it has not been disconnected already.
241 * Destructor called by garbage collector before destroying this object tries to disconnect the MonetDB connection 242 */
242 * if it has not been disconnected already. 243 @Override
243 */ 244 protected void finalize() throws Throwable {
244 @Override 245 this.close();
245 protected void finalize() throws Throwable { 246 super.finalize();
246 this.close(); 247 }
247 super.finalize(); 248
248 } 249 //== methods of interface Connection
249 250
250 //== methods of interface Connection 251 /**
251 252 * Clears all warnings reported for this Connection object. After a call to this method, the method getWarnings
252 /** 253 * returns null until a new warning is reported for this Connection object.
253 * Clears all warnings reported for this Connection object. After a call to this method, the method getWarnings 254 */
254 * returns null until a new warning is reported for this Connection object. 255 @Override
255 */ 256 public void clearWarnings() {
256 @Override 257 warnings = null;
257 public void clearWarnings() { 258 }
258 warnings = null; 259
259 } 260 /**
260 261 * Makes all changes made since the previous commit/rollback permanent and releases any database locks currently
261 private void createResponseList(String query) throws SQLException { 262 * held by this Connection object. This method should be used only when auto-commit mode has been disabled.
262 // create a container for the result 263 *
263 ResponseList l = new ResponseList(0, 0, ResultSet.FETCH_FORWARD, ResultSet.CONCUR_READ_ONLY); 264 * @throws SQLException if a database access error occurs or this Connection object is in auto-commit mode
264 // send commit to the server 265 * @see #setAutoCommit(boolean)
265 try { 266 */
266 l.processQuery(query); 267 @Override
267 } finally { 268 public void commit() throws SQLException {
268 l.close(); 269 // note: can't use sendIndependentCommand here because we need to process the auto_commit state the server gives
269 } 270 this.sendTransactionCommand("COMMIT");
270 } 271 }
271 272
272 /** 273 /**
273 * Makes all changes made since the previous commit/rollback permanent and releases any database locks currently 274 * Creates a Statement object for sending SQL statements to the
274 * held by this Connection object. This method should be used only when auto-commit mode has been disabled. 275 * database. SQL statements without parameters are normally
275 * 276 * executed using Statement objects. If the same SQL statement is
276 * @throws SQLException if a database access error occurs or this Connection object is in auto-commit mode 277 * executed many times, it may be more efficient to use a
277 * @see #setAutoCommit(boolean) 278 * PreparedStatement object.
278 */ 279 *
279 @Override 280 * Result sets created using the returned Statement object will by
280 public void commit() throws SQLException { 281 * default be type TYPE_FORWARD_ONLY and have a concurrency level of
281 // note: can't use sendIndependentCommand here because we need to process the auto_commit state the server gives 282 * CONCUR_READ_ONLY.
282 this.createResponseList("COMMIT"); 283 *
283 } 284 * @return a new default Statement object
284 285 * @throws SQLException if a database access error occurs
285 /** 286 */
286 * Creates a Statement object for sending SQL statements to the database. SQL statements without parameters are 287 @Override
287 * normally executed using Statement objects. If the same SQL statement is executed many times, it may be more 288 public Statement createStatement() throws SQLException {
288 * efficient to use a PreparedStatement object. 289 return createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
289 * 290 }
290 * Result sets created using the returned Statement object will by default be type TYPE_FORWARD_ONLY and have a 291
291 * concurrency level of CONCUR_READ_ONLY. 292 /**
292 * 293 * Creates a Statement object that will generate ResultSet objects
293 * @return a new default Statement object 294 * with the given type and concurrency. This method is the same as
294 * @throws SQLException if a database access error occurs 295 * the createStatement method above, but it allows the default
295 */ 296 * result set type and concurrency to be overridden.
296 @Override 297 *
297 public Statement createStatement() throws SQLException { 298 * @param resultSetType a result set type; one of
298 return createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, 299 * ResultSet.TYPE_FORWARD_ONLY, ResultSet.TYPE_SCROLL_INSENSITIVE,
299 ResultSet.HOLD_CURSORS_OVER_COMMIT); 300 * or ResultSet.TYPE_SCROLL_SENSITIVE
300 } 301 * @param resultSetConcurrency a concurrency type; one of
301 302 * ResultSet.CONCUR_READ_ONLY or ResultSet.CONCUR_UPDATABLE
302 /** 303 * @return a new Statement object that will generate ResultSet objects with
303 * Creates a Statement object that will generate ResultSet objects with the given type and concurrency. This method 304 * the given type and concurrency
304 * is the same as the createStatement method above, but it allows the default result set type and concurrency to be 305 * @throws SQLException if a database access error occurs
305 * overridden. 306 */
306 * 307 @Override
307 * @param resultSetType a result set type; one of ResultSet.TYPE_FORWARD_ONLY, ResultSet.TYPE_SCROLL_INSENSITIVE, 308 public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
308 * or ResultSet.TYPE_SCROLL_SENSITIVE 309 return createStatement(resultSetType, resultSetConcurrency, ResultSet.HOLD_CURSORS_OVER_COMMIT);
309 * @param resultSetConcurrency a concurrency type; one of ResultSet.CONCUR_READ_ONLY or ResultSet.CONCUR_UPDATABLE 310 }
310 * @return a new Statement object that will generate ResultSet objects with the given type and concurrency 311
311 * @throws SQLException if a database access error occurs 312 /**
312 */ 313 * Creates a Statement object that will generate ResultSet objects
313 @Override 314 * with the given type, concurrency, and holdability. This method
314 public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { 315 * is the same as the createStatement method above, but it allows
315 return createStatement(resultSetType, resultSetConcurrency, ResultSet.HOLD_CURSORS_OVER_COMMIT); 316 * the default result set type, concurrency, and holdability to be
316 } 317 * overridden.
317 318 *
318 /** 319 * @param resultSetType one of the following ResultSet constants:
319 * Creates a Statement object that will generate ResultSet objects 320 * ResultSet.TYPE_FORWARD_ONLY, ResultSet.TYPE_SCROLL_INSENSITIVE,
320 * with the given type, concurrency, and holdability. This method 321 * or ResultSet.TYPE_SCROLL_SENSITIVE
321 * is the same as the createStatement method above, but it allows 322 * @param resultSetConcurrency one of the following ResultSet
322 * the default result set type, concurrency, and holdability to be 323 * constants: ResultSet.CONCUR_READ_ONLY or
323 * overridden. 324 * ResultSet.CONCUR_UPDATABLE
324 * 325 * @param resultSetHoldability one of the following ResultSet
325 * @param resultSetType one of the following ResultSet constants: 326 * constants: ResultSet.HOLD_CURSORS_OVER_COMMIT or
326 * ResultSet.TYPE_FORWARD_ONLY, ResultSet.TYPE_SCROLL_INSENSITIVE, 327 * ResultSet.CLOSE_CURSORS_AT_COMMIT
327 * or ResultSet.TYPE_SCROLL_SENSITIVE 328 *
328 * @param resultSetConcurrency one of the following ResultSet 329 * @return a new Statement object that will generate ResultSet
329 * constants: ResultSet.CONCUR_READ_ONLY or 330 * objects with the given type, concurrency, and holdability
330 * ResultSet.CONCUR_UPDATABLE 331 * @throws SQLException if a database access error occurs or the
331 * @param resultSetHoldability one of the following ResultSet 332 * given parameters are not ResultSet constants indicating type,
332 * constants: ResultSet.HOLD_CURSORS_OVER_COMMIT or 333 * concurrency, and holdability
333 * ResultSet.CLOSE_CURSORS_AT_COMMIT 334 */
334 * 335 @Override
335 * @return a new Statement object that will generate ResultSet 336 public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
336 * objects with the given type, concurrency, and holdability 337 try {
337 * @throws SQLException if a database access error occurs or the 338 Statement ret = new MonetStatement(this, resultSetType, resultSetConcurrency, resultSetHoldability);
338 * given parameters are not ResultSet constants indicating type, 339 // store it in the map for when we close...
339 * concurrency, and holdability 340 statements.put(ret, null);
340 */ 341 return ret;
341 @Override 342 } catch (IllegalArgumentException e) {
342 public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) 343 throw new SQLException(e.toString(), "M0M03");
343 throws SQLException { 344 }
344 try { 345 // we don't have to catch SQLException because that is declared to
345 Statement ret = new MonetStatement(this, resultSetType, resultSetConcurrency, resultSetHoldability); 346 // be thrown
346 // store it in the map for when we close... 347 }
347 statements.put(ret, null); 348
348 return ret; 349 /**
349 } catch (IllegalArgumentException e) { 350 * Retrieves the current auto-commit mode for this Connection object.
350 throw new SQLException(e.toString(), "M0M03"); 351 *
351 } 352 * @return the current state of this Connection object's auto-commit mode
352 // we don't have to catch SQLException because that is declared to 353 * @see #setAutoCommit(boolean)
353 // be thrown 354 */
354 } 355 @Override
355 356 public boolean getAutoCommit() throws SQLException {
356 /** 357 return autoCommit;
357 * Retrieves the current auto-commit mode for this Connection object. 358 }
358 * 359
359 * @return the current state of this Connection object's auto-commit mode 360 /**
360 * @see #setAutoCommit(boolean) 361 * Retrieves this Connection object's current catalog name.
361 */ 362 *
362 @Override 363 * @return the current catalog name or null if there is none
363 public boolean getAutoCommit() throws SQLException { 364 * @throws SQLException if a database access error occurs or the current language is not SQL
364 return autoCommit; 365 */
365 } 366 @Override
366 367 public String getCatalog() throws SQLException {
367 /** 368 // MonetDB does NOT support catalogs
368 * Retrieves this Connection object's current catalog name. 369 return null;
369 * 370 }
370 * @return the current catalog name or null if there is none 371
371 * @throws SQLException if a database access error occurs or the current language is not SQL 372 /**
372 */ 373 * Retrieves the current holdability of ResultSet objects created using this Connection object.
373 @Override 374 *
374 public String getCatalog() throws SQLException { 375 * @return the holdability, one of ResultSet.HOLD_CURSORS_OVER_COMMIT or ResultSet.CLOSE_CURSORS_AT_COMMIT
375 // MonetDB does NOT support catalogs 376 */
376 return null; 377 @Override
377 } 378 public int getHoldability() {
378 379 // TODO: perhaps it is better to have the server implement
379 /** 380 // CLOSE_CURSORS_AT_COMMIT
380 * Retrieves the current holdability of ResultSet objects created using this Connection object. 381 return ResultSet.HOLD_CURSORS_OVER_COMMIT;
381 * 382 }
382 * @return the holdability, one of ResultSet.HOLD_CURSORS_OVER_COMMIT or ResultSet.CLOSE_CURSORS_AT_COMMIT 383
383 */ 384 /**
384 @Override 385 * Retrieves a DatabaseMetaData object that contains metadata about
385 public int getHoldability() { 386 * the database to which this Connection object represents a
386 // TODO: perhaps it is better to have the server implement 387 * connection. The metadata includes information about the
387 // CLOSE_CURSORS_AT_COMMIT 388 * database's tables, its supported SQL grammar, its stored
388 return ResultSet.HOLD_CURSORS_OVER_COMMIT; 389 * procedures, the capabilities of this connection, and so on.
389 } 390 *
390 391 * @throws SQLException if the current language is not SQL
391 /** 392 * @return a DatabaseMetaData object for this Connection object
392 * Retrieves a DatabaseMetaData object that contains metadata about 393 */
393 * the database to which this Connection object represents a 394 @Override
394 * connection. The metadata includes information about the 395 public DatabaseMetaData getMetaData() throws SQLException {
395 * database's tables, its supported SQL grammar, its stored 396 if (!this.language.getRepresentation().equals("sql")) {
396 * procedures, the capabilities of this connection, and so on. 397 throw new SQLException("This method is only supported in SQL mode", "M0M04");
397 * 398 }
398 * @throws SQLException if the current language is not SQL 399 return new MonetDatabaseMetaData(this);
399 * @return a DatabaseMetaData object for this Connection object 400 }
400 */ 401
401 @Override 402 /**
402 public DatabaseMetaData getMetaData() throws SQLException { 403 * Retrieves this Connection object's current transaction isolation level.
403 if (!this.language.getRepresentation().equals("sql")) { 404 *
404 throw new SQLException("This method is only supported in SQL mode", "M0M04"); 405 * @return the current transaction isolation level, which will be Connection.TRANSACTION_SERIALIZABLE
405 } 406 */
406 return new MonetDatabaseMetaData(this); 407 @Override
407 } 408 public int getTransactionIsolation() {
408 409 return TRANSACTION_SERIALIZABLE;
409 /** 410 }
410 * Retrieves this Connection object's current transaction isolation level. 411
411 * 412 /**
412 * @return the current transaction isolation level, which will be Connection.TRANSACTION_SERIALIZABLE 413 * Retrieves the Map object associated with this Connection object. Unless the application has added an entry,
413 */ 414 * the type map returned will be empty.
414 @Override 415 *
415 public int getTransactionIsolation() { 416 * @return the java.util.Map object associated with this Connection object
416 return TRANSACTION_SERIALIZABLE; 417 */
417 } 418 @Override
418 419 public Map<String,Class<?>> getTypeMap() {
419 /** 420 return typeMap;
420 * Retrieves the Map object associated with this Connection object. Unless the application has added an entry, 421 }
421 * the type map returned will be empty. 422
422 * 423 /**
423 * @return the java.util.Map object associated with this Connection object 424 * Retrieves the first warning reported by calls on this Connection
424 */ 425 * object. If there is more than one warning, subsequent warnings
425 @Override 426 * will be chained to the first one and can be retrieved by calling
426 public Map<String,Class<?>> getTypeMap() { 427 * the method SQLWarning.getNextWarning on the warning that was
427 return typeMap; 428 * retrieved previously.
428 } 429 *
429 430 * This method may not be called on a closed connection; doing so will cause an SQLException to be thrown.
430 /** 431 *
431 * Retrieves the first warning reported by calls on this Connection 432 * Note: Subsequent warnings will be chained to this SQLWarning.
432 * object. If there is more than one warning, subsequent warnings 433 *
433 * will be chained to the first one and can be retrieved by calling 434 * @return the first SQLWarning object or null if there are none
434 * the method SQLWarning.getNextWarning on the warning that was 435 * @throws SQLException if a database access error occurs or this method is called on a closed connection
435 * retrieved previously. 436 */
436 * 437 @Override
437 * This method may not be called on a closed connection; doing so will cause an SQLException to be thrown. 438 public SQLWarning getWarnings() throws SQLException {
438 * 439 if (closed) {
439 * Note: Subsequent warnings will be chained to this SQLWarning. 440 throw new SQLException("Cannot call on closed Connection", "M1M20");
440 * 441 }
441 * @return the first SQLWarning object or null if there are none 442 // if there are no warnings, this will be null, which fits with the specification.
442 * @throws SQLException if a database access error occurs or this method is called on a closed connection 443 return warnings;
443 */ 444 }
444 @Override 445
445 public SQLWarning getWarnings() throws SQLException { 446 /**
446 if (closed) { 447 * Retrieves whether this Connection object has been closed. A
447 throw new SQLException("Cannot call on closed Connection", "M1M20"); 448 * connection is closed if the method close has been called on it or
448 } 449 * if certain fatal errors have occurred. This method is guaranteed
449 // if there are no warnings, this will be null, which fits with the specification. 450 * to return true only when it is called after the method
450 return warnings; 451 * Connection.close has been called.
451 } 452 *
452 453 * This method generally cannot be called to determine whether a
453 /** 454 * connection to a database is valid or invalid. A typical client
454 * Retrieves whether this Connection object has been closed. A 455 * can determine that a connection is invalid by catching any
455 * connection is closed if the method close has been called on it or 456 * exceptions that might be thrown when an operation is attempted.
456 * if certain fatal errors have occurred. This method is guaranteed 457 *
457 * to return true only when it is called after the method 458 * @return true if this Connection object is closed; false if it is still open
458 * Connection.close has been called. 459 */
459 * 460 @Override
460 * This method generally cannot be called to determine whether a 461 public boolean isClosed() {
461 * connection to a database is valid or invalid. A typical client 462 return closed;
462 * can determine that a connection is invalid by catching any 463 }
463 * exceptions that might be thrown when an operation is attempted. 464
464 * 465 /**
465 * @return true if this Connection object is closed; false if it is still open 466 * Retrieves whether this Connection object is in read-only mode.
466 */ 467 * MonetDB currently doesn't support updateable result sets, but
467 @Override 468 * updates are possible. Hence the Connection object is never in
468 public boolean isClosed() { 469 * read-only mode.
469 return closed; 470 *
470 } 471 * @return true if this Connection object is read-only; false otherwise
471 472 */
472 /** 473 @Override
473 * Retrieves whether this Connection object is in read-only mode. 474 public boolean isReadOnly() {
474 * MonetDB currently doesn't support updateable result sets, but 475 return false;
475 * updates are possible. Hence the Connection object is never in 476 }
476 * read-only mode. 477
477 * 478 @Override
478 * @return true if this Connection object is read-only; false otherwise 479 public String nativeSQL(String sql) {
479 */ 480 /* there is currently no way to get the native MonetDB rewritten SQL string back, so just return the original string */
480 @Override 481 /* in future we may replace/remove the escape sequences { <escape-type> ...} before sending it to the server */
481 public boolean isReadOnly() { 482 return sql;
482 return false; 483 }
483 } 484
484 485 @Override
485 @Override 486 public CallableStatement prepareCall(String sql) {
486 public String nativeSQL(String sql) {return sql;} 487 /* not implemented yet */
487 488 return null;
488 @Override 489 }
489 public CallableStatement prepareCall(String sql) {return null;} 490
490 491 @Override
491 @Override 492 public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) {
492 public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) {return null;} 493 /* not implemented yet */
493 494 return null;
494 @Override 495 }
495 public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, 496
496 int resultSetHoldability) {return null;} 497 @Override
497 498 public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) {
498 /** 499 /* not implemented yet */
499 * Creates a PreparedStatement object for sending parameterized SQL 500 return null;
500 * statements to the database. 501 }
501 * 502
502 * A SQL statement with or without IN parameters can be pre-compiled 503 /**
503 * and stored in a PreparedStatement object. This object can then be 504 * Creates a PreparedStatement object for sending parameterized SQL
504 * used to efficiently execute this statement multiple times. 505 * statements to the database.
505 * 506 *
506 * Note: This method is optimized for handling parametric SQL 507 * A SQL statement with or without IN parameters can be pre-compiled
507 * statements that benefit from precompilation. If the driver 508 * and stored in a PreparedStatement object. This object can then be
508 * supports precompilation, the method prepareStatement will send 509 * used to efficiently execute this statement multiple times.
509 * the statement to the database for precompilation. Some drivers 510 *
510 * may not support precompilation. In this case, the statement may 511 * Note: This method is optimized for handling parametric SQL
511 * not be sent to the database until the PreparedStatement object is 512 * statements that benefit from precompilation. If the driver
512 * executed. This has no direct effect on users; however, it does 513 * supports precompilation, the method prepareStatement will send
513 * affect which methods throw certain SQLException objects. 514 * the statement to the database for precompilation. Some drivers
514 * 515 * may not support precompilation. In this case, the statement may
515 * Result sets created using the returned PreparedStatement object 516 * not be sent to the database until the PreparedStatement object is
516 * will by default be type TYPE_FORWARD_ONLY and have a concurrency 517 * executed. This has no direct effect on users; however, it does
517 * level of CONCUR_READ_ONLY. 518 * affect which methods throw certain SQLException objects.
518 * 519 *
519 * @param sql an SQL statement that may contain one or more '?' IN 520 * Result sets created using the returned PreparedStatement object
520 * parameter placeholders 521 * will by default be type TYPE_FORWARD_ONLY and have a concurrency
521 * @return a new default PreparedStatement object containing the 522 * level of CONCUR_READ_ONLY.
522 * pre-compiled SQL statement 523 *
523 * @throws SQLException if a database access error occurs 524 * @param sql an SQL statement that may contain one or more '?' IN
524 */ 525 * parameter placeholders
525 @Override 526 * @return a new default PreparedStatement object containing the
526 public PreparedStatement prepareStatement(String sql) throws SQLException { 527 * pre-compiled SQL statement
527 return prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, 528 * @throws SQLException if a database access error occurs
528 ResultSet.HOLD_CURSORS_OVER_COMMIT); 529 */
529 } 530 @Override
530 531 public PreparedStatement prepareStatement(String sql) throws SQLException {
531 /** 532 return prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
532 * Creates a PreparedStatement object that will generate ResultSet 533 }
533 * objects with the given type and concurrency. This method is the 534
534 * same as the prepareStatement method above, but it allows the 535 /**
535 * default result set type and concurrency to be overridden. 536 * Creates a PreparedStatement object that will generate ResultSet
536 * 537 * objects with the given type and concurrency. This method is the
537 * @param sql a String object that is the SQL statement to be sent to the 538 * same as the prepareStatement method above, but it allows the
538 * database; may contain one or more ? IN parameters 539 * default result set type and concurrency to be overridden.
539 * @param resultSetType a result set type; one of 540 *
540 * ResultSet.TYPE_FORWARD_ONLY, ResultSet.TYPE_SCROLL_INSENSITIVE, 541 * @param sql a String object that is the SQL statement to be sent to the
541 * or ResultSet.TYPE_SCROLL_SENSITIVE 542 * database; may contain one or more ? IN parameters
542 * @param resultSetConcurrency a concurrency type; one of 543 * @param resultSetType a result set type; one of
543 * ResultSet.CONCUR_READ_ONLY or ResultSet.CONCUR_UPDATABLE 544 * ResultSet.TYPE_FORWARD_ONLY, ResultSet.TYPE_SCROLL_INSENSITIVE,
544 * @return a new PreparedStatement object containing the pre-compiled SQL 545 * or ResultSet.TYPE_SCROLL_SENSITIVE
545 * statement that will produce ResultSet objects with the given 546 * @param resultSetConcurrency a concurrency type; one of
546 * type and concurrency 547 * ResultSet.CONCUR_READ_ONLY or ResultSet.CONCUR_UPDATABLE
547 * @throws SQLException if a database access error occurs or the given 548 * @return a new PreparedStatement object containing the pre-compiled SQL
548 * parameters are not ResultSet constants indicating 549 * statement that will produce ResultSet objects with the given
549 * type and concurrency 550 * type and concurrency
550 */ 551 * @throws SQLException if a database access error occurs or the given
551 @Override 552 * parameters are not ResultSet constants indicating
552 public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) 553 * type and concurrency
553 throws SQLException { 554 */
554 return prepareStatement(sql, resultSetType, resultSetConcurrency, ResultSet.HOLD_CURSORS_OVER_COMMIT); 555 @Override
555 } 556 public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
556 557 return prepareStatement(sql, resultSetType, resultSetConcurrency, ResultSet.HOLD_CURSORS_OVER_COMMIT);
557 /** 558 }
558 * Creates a PreparedStatement object that will generate ResultSet 559
559 * objects with the given type, concurrency, and holdability. 560 /**
560 * 561 * Creates a PreparedStatement object that will generate ResultSet
561 * This method is the same as the prepareStatement method above, but 562 * objects with the given type, concurrency, and holdability.
562 * it allows the default result set type, concurrency, and 563 *
563 * holdability to be overridden. 564 * This method is the same as the prepareStatement method above, but
564 * 565 * it allows the default result set type, concurrency, and
565 * @param sql a String object that is the SQL statement to be sent 566 * holdability to be overridden.
566 * to the database; may contain one or more ? IN parameters 567 *
567 * @param resultSetType one of the following ResultSet constants: 568 * @param sql a String object that is the SQL statement to be sent
568 * ResultSet.TYPE_FORWARD_ONLY, ResultSet.TYPE_SCROLL_INSENSITIVE, 569 * to the database; may contain one or more ? IN parameters
569 * or ResultSet.TYPE_SCROLL_SENSITIVE 570 * @param resultSetType one of the following ResultSet constants:
570 * @param resultSetConcurrency one of the following ResultSet 571 * ResultSet.TYPE_FORWARD_ONLY, ResultSet.TYPE_SCROLL_INSENSITIVE,
571 * constants: ResultSet.CONCUR_READ_ONLY or 572 * or ResultSet.TYPE_SCROLL_SENSITIVE
572 * ResultSet.CONCUR_UPDATABLE 573 * @param resultSetConcurrency one of the following ResultSet
573 * @param resultSetHoldability one of the following ResultSet 574 * constants: ResultSet.CONCUR_READ_ONLY or
574 * constants: ResultSet.HOLD_CURSORS_OVER_COMMIT or 575 * ResultSet.CONCUR_UPDATABLE
575 * ResultSet.CLOSE_CURSORS_AT_COMMIT 576 * @param resultSetHoldability one of the following ResultSet
576 * @return a new PreparedStatement object, containing the 577 * constants: ResultSet.HOLD_CURSORS_OVER_COMMIT or
577 * pre-compiled SQL statement, that will generate ResultSet objects 578 * ResultSet.CLOSE_CURSORS_AT_COMMIT
578 * with the given type, concurrency, and holdability 579 * @return a new PreparedStatement object, containing the
579 * @throws SQLException if a database access error occurs or the 580 * pre-compiled SQL statement, that will generate ResultSet objects
580 * given parameters are not ResultSet constants indicating type, 581 * with the given type, concurrency, and holdability
581 * concurrency, and holdability 582 * @throws SQLException if a database access error occurs or the
582 */ 583 * given parameters are not ResultSet constants indicating type,
583 @Override 584 * concurrency, and holdability
584 public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, 585 */
585 int resultSetHoldability) throws SQLException { 586 @Override
586 try { 587 public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability)
587 PreparedStatement ret = new MonetPreparedStatement(this, resultSetType, resultSetConcurrency, 588 throws SQLException {
588 resultSetHoldability, sql); 589 try {
589 // store it in the map for when we close... 590 PreparedStatement ret = new MonetPreparedStatement(this, resultSetType, resultSetConcurrency,
590 statements.put(ret, null); 591 resultSetHoldability, sql);
591 return ret; 592 // store it in the map for when we close...
592 } catch (IllegalArgumentException e) { 593 statements.put(ret, null);
593 throw new SQLException(e.toString(), "M0M03"); 594 return ret;
594 } 595 } catch (IllegalArgumentException e) {
595 // we don't have to catch SQLException because that is declared to 596 throw new SQLException(e.toString(), "M0M03");
596 // be thrown 597 }
597 } 598 // we don't have to catch SQLException because that is declared to
598 599 // be thrown
599 /** 600 }
600 * Creates a default PreparedStatement object that has the 601
601 * capability to retrieve auto-generated keys. The given constant 602 /**
602 * tells the driver whether it should make auto-generated keys 603 * Creates a default PreparedStatement object that has the
603 * available for retrieval. This parameter is ignored if the SQL 604 * capability to retrieve auto-generated keys. The given constant
604 * statement is not an INSERT statement. 605 * tells the driver whether it should make auto-generated keys
605 * 606 * available for retrieval. This parameter is ignored if the SQL
606 * Note: This method is optimized for handling parametric SQL 607 * statement is not an INSERT statement.
607 * statements that benefit from precompilation. If the driver 608 *
608 * supports precompilation, the method prepareStatement will send 609 * Note: This method is optimized for handling parametric SQL
609 * the statement to the database for precompilation. Some drivers 610 * statements that benefit from precompilation. If the driver
610 * may not support precompilation. In this case, the statement may 611 * supports precompilation, the method prepareStatement will send
611 * not be sent to the database until the PreparedStatement object is 612 * the statement to the database for precompilation. Some drivers
612 * executed. This has no direct effect on users; however, it does 613 * may not support precompilation. In this case, the statement may
613 * affect which methods throw certain SQLExceptions. 614 * not be sent to the database until the PreparedStatement object is
614 * 615 * executed. This has no direct effect on users; however, it does
615 * Result sets created using the returned PreparedStatement object 616 * affect which methods throw certain SQLExceptions.
616 * will by default be type TYPE_FORWARD_ONLY and have a concurrency 617 *
617 * level of CONCUR_READ_ONLY. 618 * Result sets created using the returned PreparedStatement object
618 * 619 * will by default be type TYPE_FORWARD_ONLY and have a concurrency
619 * @param sql an SQL statement that may contain one or more '?' IN 620 * level of CONCUR_READ_ONLY.
620 * parameter placeholders 621 *
621 * @param autoGeneratedKeys a flag indicating whether auto-generated 622 * @param sql an SQL statement that may contain one or more '?' IN
622 * keys should be returned; one of 623 * parameter placeholders
623 * Statement.RETURN_GENERATED_KEYS or 624 * @param autoGeneratedKeys a flag indicating whether auto-generated
624 * Statement.NO_GENERATED_KEYS 625 * keys should be returned; one of
625 * @return a new PreparedStatement object, containing the 626 * Statement.RETURN_GENERATED_KEYS or
626 * pre-compiled SQL statement, that will have the capability 627 * Statement.NO_GENERATED_KEYS
627 * of returning auto-generated keys 628 * @return a new PreparedStatement object, containing the
628 * @throws SQLException - if a database access error occurs or the 629 * pre-compiled SQL statement, that will have the capability
629 * given parameter is not a Statement constant indicating 630 * of returning auto-generated keys
630 * whether auto-generated keys should be returned 631 * @throws SQLException - if a database access error occurs or the
631 */ 632 * given parameter is not a Statement constant indicating
632 @Override 633 * whether auto-generated keys should be returned
633 public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { 634 */
634 if (autoGeneratedKeys != Statement.RETURN_GENERATED_KEYS && autoGeneratedKeys != Statement.NO_GENERATED_KEYS) { 635 @Override
635 throw new SQLException("Invalid argument, expected RETURN_GENERATED_KEYS or NO_GENERATED_KEYS", "M1M05"); 636 public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
636 } 637 if (autoGeneratedKeys != Statement.RETURN_GENERATED_KEYS &&
637 /* MonetDB has no way to disable this, so just do the normal thing ;) */ 638 autoGeneratedKeys != Statement.NO_GENERATED_KEYS)
638 return prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); 639 throw new SQLException("Invalid argument, expected RETURN_GENERATED_KEYS or NO_GENERATED_KEYS", "M1M05");
639 } 640
640 641 /* MonetDB has no way to disable this, so just do the normal
641 @Override 642 * thing ;) */
642 public PreparedStatement prepareStatement(String sql, int[] columnIndexes) {return null;} 643 return prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
643 644 }
644 @Override 645
645 public PreparedStatement prepareStatement(String sql, String[] columnNames) {return null;} 646 /**
646 647 * Creates a default PreparedStatement object capable of returning the auto-generated keys designated by the given array.
647 /** 648 * This array contains the indexes of the columns in the target table that contain the auto-generated keys that should be made available.
648 * Removes the given Savepoint object from the current transaction. 649 * The driver will ignore the array if the SQL statement is not an INSERT statement, or an SQL statement able to
649 * Any reference to the savepoint after it have been removed will 650 * return auto-generated keys (the list of such statements is vendor-specific).
650 * cause an SQLException to be thrown. 651 *
651 * 652 * An SQL statement with or without IN parameters can be pre-compiled and stored in a PreparedStatement object.
652 * @param savepoint the Savepoint object to be removed 653 * This object can then be used to efficiently execute this statement multiple times.
653 * @throws SQLException if a database access error occurs or the given 654 *
654 * Savepoint object is not a valid savepoint in the current 655 * Note: This method is optimized for handling parametric SQL statements that benefit from precompilation.
655 * transaction 656 * If the driver supports precompilation, the method prepareStatement will send the statement to the database for precompilation.
656 */ 657 * Some drivers may not support precompilation. In this case, the statement may not be sent to the database until the PreparedStatement
657 @Override 658 * object is executed. This has no direct effect on users; however, it does affect which methods throw certain SQLExceptions.
658 public void releaseSavepoint(Savepoint savepoint) throws SQLException { 659 *
659 if (!(savepoint instanceof MonetSavepoint)) { 660 * Result sets created using the returned PreparedStatement object will by default be type TYPE_FORWARD_ONLY and have
660 throw new SQLException("This driver can only handle savepoints it created itself", "M0M06"); 661 * a concurrency level of CONCUR_READ_ONLY. The holdability of the created result sets can be determined by calling getHoldability().
661 } 662 *
662 MonetSavepoint sp = (MonetSavepoint) savepoint; 663 * Parameters:
663 // note: can't use sendIndependentCommand here because we need 664 * sql - an SQL statement that may contain one or more '?' IN parameter placeholders
664 // to process the auto_commit state the server gives 665 * columnIndexes - an array of column indexes indicating the columns that should be returned from the inserted row or rows
665 // create a container for the result 666 * Returns:
666 this.createResponseList("RELEASE SAVEPOINT " + sp.getName()); 667 * a new PreparedStatement object, containing the pre-compiled statement, that is capable of
667 } 668 * returning the auto-generated keys designated by the given array of column indexes
668 669 * Throws:
669 /** 670 * SQLException - if a database access error occurs or this method is called on a closed connection
670 * Undoes all changes made in the current transaction and releases 671 * SQLFeatureNotSupportedException - if the JDBC driver does not support this method
671 * any database locks currently held by this Connection object. This 672 */
672 * method should be used only when auto-commit mode has been 673 @Override
673 * disabled. 674 public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
674 * 675 throw new SQLFeatureNotSupportedException("prepareStatement(String sql, int[] columnIndexes) not supported", "0A000");
675 * @throws SQLException if a database access error occurs or this 676 }
676 * Connection object is in auto-commit mode 677
677 * @see #setAutoCommit(boolean) 678 /**
678 */ 679 * Creates a default PreparedStatement object capable of returning the auto-generated keys designated by the given array.
679 @Override 680 * This array contains the names of the columns in the target table that contain the auto-generated keys that should be returned.
680 public void rollback() throws SQLException { 681 * The driver will ignore the array if the SQL statement is not an INSERT statement, or an SQL statement able to
681 // note: can't use sendIndependentCommand here because we need 682 * return auto-generated keys (the list of such statements is vendor-specific).
682 // to process the auto_commit state the server gives 683 *
683 // create a container for the result 684 * An SQL statement with or without IN parameters can be pre-compiled and stored in a PreparedStatement object.
684 this.createResponseList("ROLLBACK"); 685 * This object can then be used to efficiently execute this statement multiple times.
685 } 686 *
686 687 * Note: This method is optimized for handling parametric SQL statements that benefit from precompilation.
687 /** 688 * If the driver supports precompilation, the method prepareStatement will send the statement to the database for precompilation.
688 * Undoes all changes made after the given Savepoint object was set. 689 * Some drivers may not support precompilation. In this case, the statement may not be sent to the database until the PreparedStatement
689 * 690 * object is executed. This has no direct effect on users; however, it does affect which methods throw certain SQLExceptions.
690 * This method should be used only when auto-commit has been 691 *
691 * disabled. 692 * Result sets created using the returned PreparedStatement object will by default be type TYPE_FORWARD_ONLY and have
692 * 693 * a concurrency level of CONCUR_READ_ONLY. The holdability of the created result sets can be determined by calling getHoldability().
693 * @param savepoint the Savepoint object to roll back to 694 *
694 * @throws SQLException if a database access error occurs, the 695 * Parameters:
695 * Savepoint object is no longer valid, or this Connection 696 * sql - an SQL statement that may contain one or more '?' IN parameter placeholders
696 * object is currently in auto-commit mode 697 * columnNames - an array of column names indicating the columns that should be returned from the inserted row or rows
697 */ 698 * Returns:
698 @Override 699 * a new PreparedStatement object, containing the pre-compiled statement, that is capable of
699 public void rollback(Savepoint savepoint) throws SQLException { 700 * returning the auto-generated keys designated by the given array of column names
700 if (!(savepoint instanceof MonetSavepoint)) { 701 * Throws:
701 throw new SQLException("This driver can only handle savepoints it created itself", "M0M06"); 702 * SQLException - if a database access error occurs or this method is called on a closed connection
702 } 703 * SQLFeatureNotSupportedException - if the JDBC driver does not support this method
703 704 */
704 MonetSavepoint sp = (MonetSavepoint)savepoint; 705 @Override
705 // note: can't use sendIndependentCommand here because we need 706 public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
706 // to process the auto_commit state the server gives 707 throw new SQLFeatureNotSupportedException("prepareStatement(String sql, String[] columnNames) not supported", "0A000");
707 // create a container for the result 708 }
708 this.createResponseList("ROLLBACK TO SAVEPOINT " + sp.getName()); 709
709 } 710 /**
710 711 * Removes the given Savepoint object from the current transaction.
711 /** 712 * Any reference to the savepoint after it have been removed will
712 * Sets this connection's auto-commit mode to the given state. If a 713 * cause an SQLException to be thrown.
713 * connection is in auto-commit mode, then all its SQL statements 714 *
714 * will be executed and committed as individual transactions. 715 * @param savepoint the Savepoint object to be removed
715 * Otherwise, its SQL statements are grouped into transactions that 716 * @throws SQLException if a database access error occurs or the given
716 * are terminated by a call to either the method commit or the 717 * Savepoint object is not a valid savepoint in the current
717 * method rollback. By default, new connections are in auto-commit 718 * transaction
718 * mode. 719 */
719 * 720 @Override
720 * The commit occurs when the statement completes or the next 721 public void releaseSavepoint(Savepoint savepoint) throws SQLException {
721 * execute occurs, whichever comes first. In the case of statements 722 if (!(savepoint instanceof MonetSavepoint)) {
722 * returning a ResultSet object, the statement completes when the 723 throw new SQLException("This driver can only handle savepoints it created itself", "M0M06");
723 * last row of the ResultSet object has been retrieved or the 724 }
724 * ResultSet object has been closed. In advanced cases, a single 725 MonetSavepoint sp = (MonetSavepoint) savepoint;
725 * statement may return multiple results as well as output parameter 726 // note: can't use sendIndependentCommand here because we need
726 * values. In these cases, the commit occurs when all results and 727 // to process the auto_commit state the server gives
727 * output parameter values have been retrieved. 728 this.sendTransactionCommand("RELEASE SAVEPOINT " + sp.getName());
728 * 729 }
729 * NOTE: If this method is called during a transaction, the 730
730 * transaction is committed. 731 /**
731 * 732 * Undoes all changes made in the current transaction and releases
732 * @param autoCommit true to enable auto-commit mode; false to disable it 733 * any database locks currently held by this Connection object. This
733 * @throws SQLException if a database access error occurs 734 * method should be used only when auto-commit mode has been
734 * @see #getAutoCommit() 735 * disabled.
735 */ 736 *
736 @Override 737 * @throws SQLException if a database access error occurs or this
737 public void setAutoCommit(boolean autoCommit) throws SQLException { 738 * Connection object is in auto-commit mode
738 if (this.autoCommit != autoCommit) { 739 * @see #setAutoCommit(boolean)
739 this.sendControlCommand(ControlCommands.AUTO_COMMIT, (autoCommit ? 1 : 0)); 740 */
740 this.autoCommit = autoCommit; 741 @Override
741 } 742 public void rollback() throws SQLException {
742 } 743 // note: can't use sendIndependentCommand here because we need
743 744 // to process the auto_commit state the server gives
744 /** 745 // create a container for the result
745 * Sets the given catalog name in order to select a subspace of this 746 this.sendTransactionCommand("ROLLBACK");
746 * Connection object's database in which to work. If the driver 747 }
747 * does not support catalogs, it will silently ignore this request. 748
748 */ 749 /**
749 @Override 750 * Undoes all changes made after the given Savepoint object was set.
750 public void setCatalog(String catalog) throws SQLException { 751 *
751 throw new SQLFeatureNotSupportedException("setCatalog(String catalog) not supported", "0A000"); 752 * This method should be used only when auto-commit has been
752 } 753 * disabled.
753 754 *
754 /** 755 * @param savepoint the Savepoint object to roll back to
755 * Changes the default holdability of ResultSet objects created using this 756 * @throws SQLException if a database access error occurs, the
756 * Connection object to the given holdability. The default holdability of 757 * Savepoint object is no longer valid, or this Connection
757 * ResultSet objects can be be determined by invoking DatabaseMetaData.getResultSetHoldability(). 758 * object is currently in auto-commit mode
758 * 759 */
759 * @param holdability - a ResultSet holdability constant; one of 760 @Override
760 * ResultSet.HOLD_CURSORS_OVER_COMMIT or 761 public void rollback(Savepoint savepoint) throws SQLException {
761 * ResultSet.CLOSE_CURSORS_AT_COMMIT 762 if (!(savepoint instanceof MonetSavepoint)) {
762 * @see #getHoldability() 763 throw new SQLException("This driver can only handle savepoints it created itself", "M0M06");
763 */ 764 }
764 @Override 765
765 public void setHoldability(int holdability) throws SQLException { 766 MonetSavepoint sp = (MonetSavepoint)savepoint;
766 // we only support ResultSet.HOLD_CURSORS_OVER_COMMIT 767 // note: can't use sendIndependentCommand here because we need
767 if (holdability != ResultSet.HOLD_CURSORS_OVER_COMMIT) 768 // to process the auto_commit state the server gives
768 throw new SQLFeatureNotSupportedException("setHoldability(CLOSE_CURSORS_AT_COMMIT) not supported", "0A000"); 769 // create a container for the result
769 } 770 this.sendTransactionCommand("ROLLBACK TO SAVEPOINT " + sp.getName());
770 771 }
771 /** 772
772 * Puts this connection in read-only mode as a hint to the driver to 773 /**
773 * enable database optimizations. MonetDB doesn't support any mode 774 * Sets this connection's auto-commit mode to the given state. If a
774 * here, hence an SQLWarning is generated if attempted to set 775 * connection is in auto-commit mode, then all its SQL statements
775 * to true here. 776 * will be executed and committed as individual transactions.
776 * 777 * Otherwise, its SQL statements are grouped into transactions that
777 * @param readOnly true enables read-only mode; false disables it 778 * are terminated by a call to either the method commit or the
778 * @throws SQLException if a database access error occurs or this 779 * method rollback. By default, new connections are in auto-commit
779 * method is called during a transaction. 780 * mode.
780 */ 781 *
781 @Override 782 * The commit occurs when the statement completes or the next
782 public void setReadOnly(boolean readOnly) throws SQLException { 783 * execute occurs, whichever comes first. In the case of statements
783 if (readOnly) { 784 * returning a ResultSet object, the statement completes when the
784 addWarning("cannot setReadOnly(true): read-only Connection mode not supported", "01M08"); 785 * last row of the ResultSet object has been retrieved or the
785 } 786 * ResultSet object has been closed. In advanced cases, a single
786 } 787 * statement may return multiple results as well as output parameter
787 788 * values. In these cases, the commit occurs when all results and
788 /** 789 * output parameter values have been retrieved.
789 * Creates an unnamed savepoint in the current transaction and 790 *
790 * returns the new Savepoint object that represents it. 791 * NOTE: If this method is called during a transaction, the
791 * 792 * transaction is committed.
792 * @return the new Savepoint object 793 *
793 * @throws SQLException if a database access error occurs or this Connection 794 * @param autoCommit true to enable auto-commit mode; false to disable it
794 * object is currently in auto-commit mode 795 * @throws SQLException if a database access error occurs
795 */ 796 * @see #getAutoCommit()
796 @Override 797 */
797 public Savepoint setSavepoint() throws SQLException { 798 @Override
798 // create a new Savepoint object 799 public void setAutoCommit(boolean autoCommit) throws SQLException {
799 MonetSavepoint sp = new MonetSavepoint(); 800 if (this.autoCommit != autoCommit) {
800 // note: can't use sendIndependentCommand here because we need 801 this.sendControlCommand(ControlCommands.AUTO_COMMIT, (autoCommit ? 1 : 0));
801 // to process the auto_commit state the server gives 802 this.autoCommit = autoCommit;
802 // create a container for the result 803 }
803 this.createResponseList("SAVEPOINT " + sp.getName()); 804 }
804 return sp; 805
805 } 806 /**
806 807 * Sets the given catalog name in order to select a subspace of this
807 /** 808 * Connection object's database in which to work. If the driver
808 * Creates a savepoint with the given name in the current 809 * does not support catalogs, it will silently ignore this request.
809 * transaction and returns the new Savepoint object that represents 810 */
810 * it. 811 @Override
811 * 812 public void setCatalog(String catalog) throws SQLException {
812 * @param name a String containing the name of the savepoint 813 throw new SQLFeatureNotSupportedException("setCatalog(String catalog) not supported", "0A000");
813 * @return the new Savepoint object 814 }
814 * @throws SQLException if a database access error occurs or this Connection 815
815 * object is currently in auto-commit mode 816 /**
816 */ 817 * Changes the default holdability of ResultSet objects created using this
817 @Override 818 * Connection object to the given holdability. The default holdability of
818 public Savepoint setSavepoint(String name) throws SQLException { 819 * ResultSet objects can be be determined by invoking DatabaseMetaData.getResultSetHoldability().
819 // create a new Savepoint object 820 *
820 MonetSavepoint sp; 821 * @param holdability - a ResultSet holdability constant; one of
821 try { 822 * ResultSet.HOLD_CURSORS_OVER_COMMIT or
822 sp = new MonetSavepoint(name); 823 * ResultSet.CLOSE_CURSORS_AT_COMMIT
823 } catch (IllegalArgumentException e) { 824 * @see #getHoldability()
824 throw new SQLException(e.getMessage(), "M0M03"); 825 */
825 } 826 @Override
826 // note: can't use sendIndependentCommand here because we need 827 public void setHoldability(int holdability) throws SQLException {
827 // to process the auto_commit state the server gives 828 // we only support ResultSet.HOLD_CURSORS_OVER_COMMIT
828 // create a container for the result 829 if (holdability != ResultSet.HOLD_CURSORS_OVER_COMMIT)
829 this.createResponseList("SAVEPOINT " + sp.getName()); 830 throw new SQLFeatureNotSupportedException("setHoldability(CLOSE_CURSORS_AT_COMMIT) not supported", "0A000");
830 return sp; 831 }
831 } 832
832 833 /**
833 /** 834 * Puts this connection in read-only mode as a hint to the driver to
834 * Attempts to change the transaction isolation level for this 835 * enable database optimizations. MonetDB doesn't support any mode
835 * Connection object to the one given. The constants defined in the 836 * here, hence an SQLWarning is generated if attempted to set
836 * interface Connection are the possible transaction isolation 837 * to true here.
837 * levels. 838 *
838 * 839 * @param readOnly true enables read-only mode; false disables it
839 * @param level one of the following Connection constants: Connection.TRANSACTION_READ_UNCOMMITTED, 840 * @throws SQLException if a database access error occurs or this
840 * Connection.TRANSACTION_READ_COMMITTED, Connection.TRANSACTION_REPEATABLE_READ, or 841 * method is called during a transaction.
841 * Connection.TRANSACTION_SERIALIZABLE. 842 */
842 */ 843 @Override
843 @Override 844 public void setReadOnly(boolean readOnly) throws SQLException {
844 public void setTransactionIsolation(int level) { 845 if (readOnly) {
845 if (level != TRANSACTION_SERIALIZABLE) { 846 addWarning("cannot setReadOnly(true): read-only Connection mode not supported", "01M08");
846 addWarning("MonetDB only supports fully serializable " + 847 }
847 "transactions, continuing with transaction level raised to TRANSACTION_SERIALIZABLE", "01M09"); 848 }
848 } 849
849 } 850 /**
850 851 * Creates an unnamed savepoint in the current transaction and
851 /** 852 * returns the new Savepoint object that represents it.
852 * Installs the given TypeMap object as the type map for this 853 *
853 * Connection object. The type map will be used for the custom 854 * @return the new Savepoint object
854 * mapping of SQL structured types and distinct types. 855 * @throws SQLException if a database access error occurs or this Connection
855 * 856 * object is currently in auto-commit mode
856 * @param map the java.util.Map object to install as the replacement for 857 */
857 * this Connection object's default type map 858 @Override
858 */ 859 public Savepoint setSavepoint() throws SQLException {
859 @Override 860 // create a new Savepoint object
860 public void setTypeMap(Map<String, Class<?>> map) { 861 MonetSavepoint sp = new MonetSavepoint();
861 typeMap = map; 862 // note: can't use sendIndependentCommand here because we need
862 } 863 // to process the auto_commit state the server gives
863 864 // create a container for the result
864 /** 865 this.sendTransactionCommand("SAVEPOINT " + sp.getName());
865 * Returns a string identifying this Connection to the MonetDB server. 866 return sp;
866 * 867 }
867 * @return a String representing this Object 868
868 */ 869 /**
869 @Override 870 * Creates a savepoint with the given name in the current
870 public String toString() { 871 * transaction and returns the new Savepoint object that represents
871 return "MonetDB Connection (" + this.getJDBCURL() + ") " + (closed ? "disconnected" : "connected"); 872 * it.
872 } 873 *
873 874 * @param name a String containing the name of the savepoint
874 //== Java 1.6 methods (JDBC 4.0) 875 * @return the new Savepoint object
875 876 * @throws SQLException if a database access error occurs or this Connection
876 /** 877 * object is currently in auto-commit mode
877 * Factory method for creating Array objects. 878 */
878 * 879 @Override
879 * Note: When createArrayOf is used to create an array object that 880 public Savepoint setSavepoint(String name) throws SQLException {
880 * maps to a primitive data type, then it is implementation-defined 881 // create a new Savepoint object
881 * whether the Array object is an array of that primitive data type 882 MonetSavepoint sp;
882 * or an array of Object. 883 try {
883 * 884 sp = new MonetSavepoint(name);
884 * Note: The JDBC driver is responsible for mapping the elements 885 } catch (IllegalArgumentException e) {
885 * Object array to the default JDBC SQL type defined in 886 throw new SQLException(e.getMessage(), "M0M03");
886 * java.sql.Types for the given class of Object. The default mapping 887 }
887 * is specified in Appendix B of the JDBC specification. If the 888 // note: can't use sendIndependentCommand here because we need
888 * resulting JDBC type is not the appropriate type for the given 889 // to process the auto_commit state the server gives
889 * typeName then it is implementation defined whether an 890 // create a container for the result
890 * SQLException is thrown or the driver supports the resulting conversion. 891 this.sendTransactionCommand("SAVEPOINT " + sp.getName());
891 * 892 return sp;
892 * @param typeName the SQL name of the type the elements of the 893 }
893 * array map to. The typeName is a database-specific name 894
894 * which may be the name of a built-in type, a user-defined 895 /**
895 * type or a standard SQL type supported by this database. 896 * Attempts to change the transaction isolation level for this
896 * This is the value returned by Array.getBaseTypeName 897 * Connection object to the one given. The constants defined in the
897 * @return an Array object whose elements map to the specified SQL type 898 * interface Connection are the possible transaction isolation
898 * @throws SQLException if a database error occurs, the JDBC type 899 * levels.
899 * is not appropriate for the typeName and the conversion is 900 *
900 * not supported, the typeName is null or this method is 901 * @param level one of the following Connection constants: Connection.TRANSACTION_READ_UNCOMMITTED,
901 * called on a closed connection 902 * Connection.TRANSACTION_READ_COMMITTED, Connection.TRANSACTION_REPEATABLE_READ, or
902 * @throws SQLFeatureNotSupportedException the JDBC driver does 903 * Connection.TRANSACTION_SERIALIZABLE.
903 * not support this data type 904 */
904 * @since 1.6 905 @Override
905 */ 906 public void setTransactionIsolation(int level) {
906 @Override 907 if (level != TRANSACTION_SERIALIZABLE) {
907 public java.sql.Array createArrayOf(String typeName, Object[] elements) throws SQLException { 908 addWarning("MonetDB only supports fully serializable " +
908 throw new SQLFeatureNotSupportedException("createArrayOf() not supported", "0A000"); 909 "transactions, continuing with transaction level raised to TRANSACTION_SERIALIZABLE", "01M09");
909 } 910 }
910 911 }
911 /** 912
912 * Constructs an object that implements the Clob interface. The 913 /**
913 * object returned initially contains no data. The setAsciiStream, 914 * Installs the given TypeMap object as the type map for this
914 * setCharacterStream and setString methods of the Clob interface 915 * Connection object. The type map will be used for the custom
915 * may be used to add data to the Clob. 916 * mapping of SQL structured types and distinct types.
916 * 917 *
917 * @return a MonetClob instance 918 * @param map the java.util.Map object to install as the replacement for
918 * @throws SQLFeatureNotSupportedException the JDBC driver does 919 * this Connection object's default type map
919 * not support MonetClob objects that can be filled in 920 */
920 * @since 1.6 921 @Override
921 */ 922 public void setTypeMap(Map<String, Class<?>> map) {
922 @Override 923 typeMap = map;
923 public java.sql.Clob createClob() throws SQLException { 924 }
924 return new MonetClob(""); 925
925 } 926 /**
926 927 * Returns a string identifying this Connection to the MonetDB server.
927 /** 928 *
928 * Constructs an object that implements the Blob interface. The 929 * @return a String representing this Object
929 * object returned initially contains no data. The setBinaryStream 930 */
930 * and setBytes methods of the Blob interface may be used to add 931 @Override
931 * data to the Blob. 932 public String toString() {
932 * 933 return "MonetDB Connection (" + this.getJDBCURL() + ") " + (closed ? "disconnected" : "connected");
933 * @return a MonetBlob instance 934 }
934 * @throws SQLFeatureNotSupportedException the JDBC driver does 935
935 * not support MonetBlob objects that can be filled in 936 /**
936 * @since 1.6 937 * Factory method for creating Array objects.
937 */ 938 *
938 @Override 939 * Note: When createArrayOf is used to create an array object that
939 public java.sql.Blob createBlob() throws SQLException { 940 * maps to a primitive data type, then it is implementation-defined
940 return new MonetBlob(new byte[1]); 941 * whether the Array object is an array of that primitive data type
941 } 942 * or an array of Object.
942 943 *
943 /** 944 * Note: The JDBC driver is responsible for mapping the elements
944 * Constructs an object that implements the NClob interface. The 945 * Object array to the default JDBC SQL type defined in
945 * object returned initially contains no data. The setAsciiStream, 946 * java.sql.Types for the given class of Object. The default mapping
946 * setCharacterStream and setString methods of the NClob interface 947 * is specified in Appendix B of the JDBC specification. If the
947 * may be used to add data to the NClob. 948 * resulting JDBC type is not the appropriate type for the given
948 * 949 * typeName then it is implementation defined whether an
949 * @return an NClob instance 950 * SQLException is thrown or the driver supports the resulting conversion.
950 * @throws SQLFeatureNotSupportedException the JDBC driver does 951 *
951 * not support MonetNClob objects that can be filled in 952 * @param typeName the SQL name of the type the elements of the
952 * @since 1.6 953 * array map to. The typeName is a database-specific name
953 */ 954 * which may be the name of a built-in type, a user-defined
954 @Override 955 * type or a standard SQL type supported by this database.
955 public java.sql.NClob createNClob() throws SQLException { 956 * This is the value returned by Array.getBaseTypeName
956 throw new SQLFeatureNotSupportedException("createNClob() not supported", "0A000"); 957 * @return an Array object whose elements map to the specified SQL type
957 } 958 * @throws SQLException if a database error occurs, the JDBC type
958 959 * is not appropriate for the typeName and the conversion is
959 /** 960 * not supported, the typeName is null or this method is
960 * Factory method for creating Struct objects. 961 * called on a closed connection
961 * 962 * @throws SQLFeatureNotSupportedException the JDBC driver does
962 * @param typeName the SQL type name of the SQL structured type that 963 * not support this data type
963 * this Struct object maps to. The typeName is the name of a 964 * @since 1.6
964 * user-defined type that has been defined for this database. 965 */
965 * It is the value returned by Struct.getSQLTypeName. 966 @Override
966 * @param attributes the attributes that populate the returned object 967 public java.sql.Array createArrayOf(String typeName, Object[] elements) throws SQLException {
967 * @return a Struct object that maps to the given SQL type and is 968 throw new SQLFeatureNotSupportedException("createArrayOf() not supported", "0A000");
968 * populated with the given attributes 969 }
969 * @throws SQLException if a database error occurs, the typeName 970
970 * is null or this method is called on a closed connection 971
971 * @throws SQLFeatureNotSupportedException the JDBC driver does 972 //== end methods of interface java.sql.Connection
972 * not support this data type 973
973 * @since 1.6 974 /**
974 */ 975 * Constructs an object that implements the Clob interface. The
975 @Override 976 * object returned initially contains no data. The setAsciiStream,
976 public java.sql.Struct createStruct(String typeName, Object[] attributes) throws SQLException { 977 * setCharacterStream and setString methods of the Clob interface
977 throw new SQLFeatureNotSupportedException("createStruct() not supported", "0A000"); 978 * may be used to add data to the Clob.
978 } 979 *
979 980 * @return a MonetClob instance
980 /** 981 * @throws SQLFeatureNotSupportedException the JDBC driver does
981 * Constructs an object that implements the SQLXML interface. The 982 * not support MonetClob objects that can be filled in
982 * object returned initially contains no data. The 983 * @since 1.6
983 * createXmlStreamWriter object and setString method of the SQLXML 984 */
984 * interface may be used to add data to the SQLXML object. 985 @Override
985 * 986 public java.sql.Clob createClob() throws SQLException {
986 * @return An object that implements the SQLXML interface 987 return new MonetClob("");
987 * @throws SQLFeatureNotSupportedException the JDBC driver does 988 }
988 * not support this data type 989
989 * @since 1.6 990 /**
990 */ 991 * Constructs an object that implements the Blob interface. The
991 @Override 992 * object returned initially contains no data. The setBinaryStream
992 public java.sql.SQLXML createSQLXML() throws SQLException { 993 * and setBytes methods of the Blob interface may be used to add
993 throw new SQLFeatureNotSupportedException("createSQLXML() not supported", "0A000"); 994 * data to the Blob.
994 } 995 *
995 996 * @return a MonetBlob instance
996 /** 997 * @throws SQLFeatureNotSupportedException the JDBC driver does
997 * Returns true if the connection has not been closed and is still 998 * not support MonetBlob objects that can be filled in
998 * valid. The driver shall submit a query on the connection or use 999 * @since 1.6
999 * some other mechanism that positively verifies the connection is 1000 */
1000 * still valid when this method is called. 1001 @Override
1001 * 1002 public java.sql.Blob createBlob() throws SQLException {
1002 * The query submitted by the driver to validate the connection 1003 return new MonetBlob(new byte[1]);
1003 * shall be executed in the context of the current transaction. 1004 }
1004 * 1005
1005 * @param timeout The time in seconds to wait for the database 1006 /**
1006 * operation used to validate the connection to complete. If 1007 * Constructs an object that implements the NClob interface. The
1007 * the timeout period expires before the operation completes, 1008 * object returned initially contains no data. The setAsciiStream,
1008 * this method returns false. A value of 0 indicates a 1009 * setCharacterStream and setString methods of the NClob interface
1009 * timeout is not applied to the database operation. 1010 * may be used to add data to the NClob.
1010 * @return true if the connection is valid, false otherwise 1011 *
1011 * @throws SQLException if the value supplied for timeout is less than 0 1012 * @return an NClob instance
1012 * @since 1.6 1013 * @throws SQLFeatureNotSupportedException the JDBC driver does
1013 */ 1014 * not support MonetNClob objects that can be filled in
1014 @Override 1015 * @since 1.6
1015 public boolean isValid(int timeout) throws SQLException { 1016 */
1016 if (timeout < 0) 1017 @Override
1017 throw new SQLException("timeout is less than 0", "M1M05"); 1018 public java.sql.NClob createNClob() throws SQLException {
1018 if (closed) 1019 throw new SQLFeatureNotSupportedException("createNClob() not supported", "0A000");
1019 return false; 1020 }
1020 1021
1021 // ping db using query: select 1; 1022 /**
1022 Statement stmt = null; 1023 * Factory method for creating Struct objects.
1023 ResultSet rs = null; 1024 *
1024 try { 1025 * @param typeName the SQL type name of the SQL structured type that
1025 stmt = createStatement(); 1026 * this Struct object maps to. The typeName is the name of a
1026 stmt.setQueryTimeout(timeout); 1027 * user-defined type that has been defined for this database.
1027 rs = stmt.executeQuery("SELECT 1"); 1028 * It is the value returned by Struct.getSQLTypeName.
1028 rs.close(); 1029 * @param attributes the attributes that populate the returned object
1029 rs = null; 1030 * @return a Struct object that maps to the given SQL type and is
1030 stmt.close(); 1031 * populated with the given attributes
1031 return true; 1032 * @throws SQLException if a database error occurs, the typeName
1032 } catch (Exception e) { 1033 * is null or this method is called on a closed connection
1033 if (rs != null) { 1034 * @throws SQLFeatureNotSupportedException the JDBC driver does
1034 try { 1035 * not support this data type
1035 rs.close(); 1036 * @since 1.6
1036 } catch (Exception ignored) {} 1037 */
1037 } 1038 @Override
1038 if (stmt != null) { 1039 public java.sql.Struct createStruct(String typeName, Object[] attributes) throws SQLException {
1039 try { 1040 throw new SQLFeatureNotSupportedException("createStruct() not supported", "0A000");
1040 stmt.close(); 1041 }
1041 } catch (Exception ignored) {} 1042
1042 } 1043 /**
1043 } 1044 * Constructs an object that implements the SQLXML interface. The
1044 return false; 1045 * object returned initially contains no data. The
1045 } 1046 * createXmlStreamWriter object and setString method of the SQLXML
1046 1047 * interface may be used to add data to the SQLXML object.
1047 /** 1048 *
1048 * Returns the value of the client info property specified by name. 1049 * @return An object that implements the SQLXML interface
1049 * This method may return null if the specified client info property 1050 * @throws SQLFeatureNotSupportedException the JDBC driver does
1050 * has not been set and does not have a default value. 1051 * not support this data type
1051 * This method will also return null if the specified client info 1052 * @since 1.6
1052 * property name is not supported by the driver. 1053 */
1053 * Applications may use the DatabaseMetaData.getClientInfoProperties method 1054 @Override
1054 * to determine the client info properties supported by the driver. 1055 public java.sql.SQLXML createSQLXML() throws SQLException {
1055 * 1056 throw new SQLFeatureNotSupportedException("createSQLXML() not supported", "0A000");
1056 * @param name - The name of the client info property to retrieve 1057 }
1057 * @return The value of the client info property specified or null 1058
1058 * @throws SQLException - if the database server returns an error 1059 /**
1059 * when fetching the client info value from the database 1060 * Returns true if the connection has not been closed and is still
1060 * or this method is called on a closed connection 1061 * valid. The driver shall submit a query on the connection or use
1061 * @since 1.6 1062 * some other mechanism that positively verifies the connection is
1062 */ 1063 * still valid when this method is called.
1063 @Override 1064 *
1064 public String getClientInfo(String name) throws SQLException { 1065 * The query submitted by the driver to validate the connection
1065 if (name == null || name.isEmpty()) 1066 * shall be executed in the context of the current transaction.
1066 return null; 1067 *
1067 return conn_props.getProperty(name); 1068 * @param timeout The time in seconds to wait for the database
1068 } 1069 * operation used to validate the connection to complete. If
1069 1070 * the timeout period expires before the operation completes,
1070 /** 1071 * this method returns false. A value of 0 indicates a
1071 * Returns a list containing the name and current value of each client info 1072 * timeout is not applied to the database operation.
1072 * property supported by the driver. The value of a client info property may 1073 * @return true if the connection is valid, false otherwise
1073 * be null if the property has not been set and does not have a default value. 1074 * @throws SQLException if the value supplied for timeout is less than 0
1074 * 1075 * @since 1.6
1075 * @return A Properties object that contains the name and current value 1076 */
1076 * of each of the client info properties supported by the driver. 1077 @Override
1077 * @throws SQLException - if the database server returns an error 1078 public boolean isValid(int timeout) throws SQLException {
1078 * when fetching the client info value from the database 1079 if (timeout < 0)
1079 * or this method is called on a closed connection 1080 throw new SQLException("timeout is less than 0", "M1M05");
1080 * @since 1.6 1081 if (closed)
1081 */ 1082 return false;
1082 @Override 1083
1083 public Properties getClientInfo() throws SQLException { 1084 // ping db using query: select 1;
1084 // return a clone of the connection properties object 1085 Statement stmt = null;
1085 return new Properties(conn_props); 1086 ResultSet rs = null;
1086 } 1087 boolean isValid = false;
1087 1088 try {
1088 /** 1089 stmt = createStatement();
1089 * Sets the value of the client info property specified by name to the value specified by value. 1090 if (stmt != null) {
1090 * Applications may use the DatabaseMetaData.getClientInfoProperties method to determine 1091 int original_timeout = stmt.getQueryTimeout();
1091 * the client info properties supported by the driver and the maximum length that may be specified 1092 if (timeout > 0 && original_timeout != timeout) {
1092 * for each property. 1093 // we need to change the requested timeout for this test query
1093 * 1094 stmt.setQueryTimeout(timeout);
1094 * The driver stores the value specified in a suitable location in the database. For example 1095 }
1095 * in a special register, session parameter, or system table column. For efficiency the driver 1096 rs = stmt.executeQuery("SELECT 1");
1096 * may defer setting the value in the database until the next time a statement is executed 1097 if (rs != null && rs.next()) {
1097 * or prepared. Other than storing the client information in the appropriate place in the 1098 isValid = true;
1098 * database, these methods shall not alter the behavior of the connection in anyway. 1099 }
1099 * The values supplied to these methods are used for accounting, diagnostics and debugging purposes only. 1100 if (timeout > 0 && original_timeout != timeout) {
1100 * 1101 // restore the original server timeout value
1101 * The driver shall generate a warning if the client info name specified is not recognized by the driver. 1102 stmt.setQueryTimeout(original_timeout);
1102 * 1103 }
1103 * If the value specified to this method is greater than the maximum length for the property 1104 }
1104 * the driver may either truncate the value and generate a warning or generate a SQLClientInfoException. 1105 } catch (SQLException se) {
1105 * If the driver generates a SQLClientInfoException, the value specified was not set on the connection. 1106 String msg = se.getMessage();
1106 * 1107 if (msg != null && msg.equals("Current transaction is aborted (please ROLLBACK)")) {
1107 * The following are standard client info properties. Drivers are not required to support these 1108 isValid = true;
1108 * properties however if the driver supports a client info property that can be described by one 1109 }
1109 * of the standard properties, the standard property name should be used. 1110 /* ignore stmt errors/exceptions, we are only testing if the connection is still alive and usable */
1110 * 1111 } finally {
1111 * ApplicationName - The name of the application currently utilizing the connection 1112 if (rs != null) {
1112 * ClientUser - The name of the user that the application using the connection is performing work for. 1113 try {
1113 * This may not be the same as the user name that was used in establishing the connection. 1114 rs.close();
1114 * ClientHostname - The hostname of the computer the application using the connection is running on. 1115 } catch (Exception e2) { /* ignore error */ }
1115 * 1116 }
1116 * @param name - The name of the client info property to set 1117 if (stmt != null) {
1117 * @param value - The value to set the client info property to. If the 1118 try {
1118 * value is null, the current value of the specified property is cleared. 1119 stmt.close();
1119 * @throws SQLClientInfoException - if the database server returns an error 1120 } catch (Exception e2) { /* ignore error */ }
1120 * while setting the clientInfo values on the database server 1121 }
1121 * or this method is called on a closed connection 1122 }
1122 * @since 1.6 1123 return isValid;
1123 */ 1124 }
1124 @Override 1125
1125 public void setClientInfo(String name, String value) throws java.sql.SQLClientInfoException { 1126 /**
1126 if (name == null || name.isEmpty()) { 1127 * Returns the value of the client info property specified by name.
1127 addWarning("setClientInfo: missing property name", "01M07"); 1128 * This method may return null if the specified client info property
1128 return; 1129 * has not been set and does not have a default value.
1129 } 1130 * This method will also return null if the specified client info
1130 // If the value is null, the current value of the specified property is cleared. 1131 * property name is not supported by the driver.
1131 if (value == null) { 1132 * Applications may use the DatabaseMetaData.getClientInfoProperties method
1132 if (conn_props.containsKey(name)) 1133 * to determine the client info properties supported by the driver.
1133 conn_props.remove(name); 1134 *
1134 return; 1135 * @param name - The name of the client info property to retrieve
1135 } 1136 * @return The value of the client info property specified or null
1136 // only set value for supported property names 1137 * @throws SQLException - if the database server returns an error
1137 if (name.equals("host") || name.equals("port") || name.equals("user") || name.equals("password") || 1138 * when fetching the client info value from the database
1138 name.equals("database") || name.equals("language") || name.equals("so_timeout") || 1139 * or this method is called on a closed connection
1139 name.equals("hash") || name.equals("treat_blob_as_binary") || name.equals("follow_redirects") || 1140 * @since 1.6
1140 name.equals("treat_clob_as_longvarchar") || name.equals("embedded") || name.equals("directory")) { 1141 */
1141 conn_props.setProperty(name, value); 1142 @Override
1142 } else { 1143 public String getClientInfo(String name) throws SQLException {
1143 addWarning("setClientInfo: " + name + "is not a recognised property", "01M07"); 1144 if (name == null || name.isEmpty())
1144 } 1145 return null;
1145 } 1146 return conn_props.getProperty(name);
1146 1147 }
1147 /** 1148
1148 * Sets the value of the connection's client info properties. 1149 /**
1149 * The Properties object contains the names and values of the client info 1150 * Returns a list containing the name and current value of each client info
1150 * properties to be set. The set of client info properties contained in the 1151 * property supported by the driver. The value of a client info property may
1151 * properties list replaces the current set of client info properties on the connection. 1152 * be null if the property has not been set and does not have a default value.
1152 * If a property that is currently set on the connection is not present in the 1153 *
1153 * properties list, that property is cleared. Specifying an empty properties list 1154 * @return A Properties object that contains the name and current value
1154 * will clear all of the properties on the connection. 1155 * of each of the client info properties supported by the driver.
1155 * See setClientInfo (String, String) for more information. 1156 * @throws SQLException - if the database server returns an error
1156 * 1157 * when fetching the client info value from the database
1157 * If an error occurs in setting any of the client info properties, a 1158 * or this method is called on a closed connection
1158 * SQLClientInfoException is thrown. The SQLClientInfoException contains information 1159 * @since 1.6
1159 * indicating which client info properties were not set. The state of the client 1160 */
1160 * information is unknown because some databases do not allow multiple client info 1161 @Override
1161 * properties to be set atomically. For those databases, one or more properties may 1162 public Properties getClientInfo() throws SQLException {
1162 * have been set before the error occurred. 1163 // return a clone of the connection properties object
1163 * 1164 return new Properties(conn_props);
1164 * @param props - The list of client info properties to set 1165 }
1165 * @throws SQLClientInfoException - if the database server returns an error 1166
1166 * while setting the clientInfo values on the database server 1167 /**
1167 * or this method is called on a closed connection 1168 * Sets the value of the client info property specified by name to the value specified by value.
1168 * @since 1.6 1169 * Applications may use the DatabaseMetaData.getClientInfoProperties method to determine
1169 */ 1170 * the client info properties supported by the driver and the maximum length that may be specified
1170 @Override 1171 * for each property.
1171 public void setClientInfo(Properties props) throws java.sql.SQLClientInfoException { 1172 *
1172 if (props != null) { 1173 * The driver stores the value specified in a suitable location in the database. For example
1173 for (Map.Entry<Object, Object> entry : props.entrySet()) { 1174 * in a special register, session parameter, or system table column. For efficiency the driver
1174 setClientInfo(entry.getKey().toString(), entry.getValue().toString()); 1175 * may defer setting the value in the database until the next time a statement is executed
1175 } 1176 * or prepared. Other than storing the client information in the appropriate place in the
1176 } 1177 * database, these methods shall not alter the behavior of the connection in anyway.
1177 } 1178 * The values supplied to these methods are used for accounting, diagnostics and debugging purposes only.
1178 1179 *
1179 //== Java 1.7 methods (JDBC 4.1) 1180 * The driver shall generate a warning if the client info name specified is not recognized by the driver.
1180 1181 *
1181 /** 1182 * If the value specified to this method is greater than the maximum length for the property
1182 * Sets the given schema name to access. 1183 * the driver may either truncate the value and generate a warning or generate a SQLClientInfoException.
1183 * 1184 * If the driver generates a SQLClientInfoException, the value specified was not set on the connection.
1184 * @param schema the name of a schema in which to work 1185 *
1185 * @throws SQLException if a database access error occurs or this method is called on a closed connection 1186 * The following are standard client info properties. Drivers are not required to support these
1186 * @since 1.7 1187 * properties however if the driver supports a client info property that can be described by one
1187 */ 1188 * of the standard properties, the standard property name should be used.
1188 @Override 1189 *
1189 public void setSchema(String schema) throws SQLException { 1190 * ApplicationName - The name of the application currently utilizing the connection
1190 if (closed) 1191 * ClientUser - The name of the user that the application using the connection is performing work for.
1191 throw new SQLException("Cannot call on closed Connection", "M1M20"); 1192 * This may not be the same as the user name that was used in establishing the connection.
1192 if (schema == null) 1193 * ClientHostname - The hostname of the computer the application using the connection is running on.
1193 throw new SQLException("Missing schema name", "M1M05"); 1194 *
1194 1195 * @param name - The name of the client info property to set
1195 try (Statement st = createStatement()) { 1196 * @param value - The value to set the client info property to. If the
1196 st.execute("SET SCHEMA \"" + schema + "\""); 1197 * value is null, the current value of the specified property is cleared.
1197 } 1198 * @throws SQLClientInfoException - if the database server returns an error
1198 } 1199 * while setting the clientInfo values on the database server
1199 1200 * or this method is called on a closed connection
1200 /** 1201 * @since 1.6
1201 * Retrieves this Connection object's current schema name. 1202 */
1202 * 1203 @Override
1203 * @return the current schema name or null if there is none 1204 public void setClientInfo(String name, String value) throws java.sql.SQLClientInfoException {
1204 * @throws SQLException if a database access error occurs or this method is called on a closed connection 1205 if (name == null || name.isEmpty()) {
1205 */ 1206 addWarning("setClientInfo: missing property name", "01M07");
1206 @Override 1207 return;
1207 public String getSchema() throws SQLException { 1208 }
1208 if (closed) { 1209 // If the value is null, the current value of the specified property is cleared.
1209 throw new SQLException("Cannot call on closed Connection", "M1M20"); 1210 if (value == null) {
1210 } 1211 if (conn_props.containsKey(name))
1211 String cur_schema; 1212 conn_props.remove(name);
1212 Statement st = createStatement(); 1213 return;
1213 ResultSet rs = null; 1214 }
1214 try { 1215 // only set value for supported property names
1215 rs = st.executeQuery("SELECT CURRENT_SCHEMA"); 1216 if (name.equals("host") || name.equals("port") || name.equals("user") || name.equals("password") ||
1216 if (!rs.next()) 1217 name.equals("database") || name.equals("language") || name.equals("so_timeout") ||
1217 throw new SQLException("Row expected", "02000"); 1218 name.equals("hash") || name.equals("treat_blob_as_binary") || name.equals("follow_redirects") ||
1218 cur_schema = rs.getString(1); 1219 name.equals("treat_clob_as_longvarchar") || name.equals("embedded") || name.equals("directory")) {
1219 } finally { 1220 conn_props.setProperty(name, value);
1220 if (rs != null) 1221 } else {
1221 rs.close(); 1222 addWarning("setClientInfo: " + name + "is not a recognised property", "01M07");
1222 st.close(); 1223 }
1223 } 1224 }
1224 return cur_schema; 1225
1225 } 1226 /**
1226 1227 * Sets the value of the connection's client info properties.
1227 /** 1228 * The Properties object contains the names and values of the client info
1228 * Terminates an open connection. Calling abort results in: 1229 * properties to be set. The set of client info properties contained in the
1229 * * The connection marked as closed 1230 * properties list replaces the current set of client info properties on the connection.
1230 * * Closes any physical connection to the database 1231 * If a property that is currently set on the connection is not present in the
1231 * * Releases resources used by the connection 1232 * properties list, that property is cleared. Specifying an empty properties list
1232 * * Insures that any thread that is currently accessing the 1233 * will clear all of the properties on the connection.
1233 * connection will either progress to completion or throw an 1234 * See setClientInfo (String, String) for more information.
1234 * SQLException. 1235 *
1235 * Calling abort marks the connection closed and releases any 1236 * If an error occurs in setting any of the client info properties, a
1236 * resources. Calling abort on a closed connection is a no-op. 1237 * SQLClientInfoException is thrown. The SQLClientInfoException contains information
1237 * 1238 * indicating which client info properties were not set. The state of the client
1238 * @param executor The Executor implementation which will be used by abort 1239 * information is unknown because some databases do not allow multiple client info
1239 * @throws SQLException if a database access error occurs or the executor is null 1240 * properties to be set atomically. For those databases, one or more properties may
1240 * @throws SecurityException if a security manager exists and its checkPermission method denies calling abort 1241 * have been set before the error occurred.
1241 */ 1242 *
1242 @Override 1243 * @param props - The list of client info properties to set
1243 public void abort(Executor executor) throws SQLException { 1244 * @throws SQLClientInfoException - if the database server returns an error
1244 if (closed) 1245 * while setting the clientInfo values on the database server
1245 return; 1246 * or this method is called on a closed connection
1246 if (executor == null) 1247 * @since 1.6
1247 throw new SQLException("executor is null", "M1M05"); 1248 */
1248 // this is really the simplest thing to do, it destroys 1249 @Override
1249 // everything (in particular the server connection) 1250 public void setClientInfo(Properties props) throws java.sql.SQLClientInfoException {
1250 close(); 1251 if (props != null) {
1251 } 1252 for (Map.Entry<Object, Object> entry : props.entrySet()) {
1252 1253 setClientInfo(entry.getKey().toString(), entry.getValue().toString());
1253 /** 1254 }
1254 * Sets the maximum period a Connection or objects created from the 1255 }
1255 * Connection will wait for the database to reply to any one 1256 }
1256 * request. If any request remains unanswered, the waiting method 1257
1257 * will return with a SQLException, and the Connection or objects 1258 /**
1258 * created from the Connection will be marked as closed. Any 1259 * Sets the given schema name to access.
1259 * subsequent use of the objects, with the exception of the close, 1260 *
1260 * isClosed or Connection.isValid methods, will result in a 1261 * @param schema the name of a schema in which to work
1261 * SQLException. 1262 * @throws SQLException if a database access error occurs or this method is called on a closed connection
1262 * 1263 * @since 1.7
1263 * @param executor The Executor implementation which will be used by setNetworkTimeout 1264 */
1264 * @param millis The time in milliseconds to wait for the database operation to complete 1265 @Override
1265 * @throws SQLException if a database access error occurs, this method is called on a closed connection, the 1266 public void setSchema(String schema) throws SQLException {
1266 * executor is null, or the value specified for seconds is less than 0. 1267 if (closed)
1267 */ 1268 throw new SQLException("Cannot call on closed Connection", "M1M20");
1268 @Override 1269 if (schema == null)
1269 public void setNetworkTimeout(Executor executor, int millis) throws SQLException { 1270 throw new SQLException("Missing schema name", "M1M05");
1270 if (closed) { 1271
1271 throw new SQLException("Cannot call on closed Connection", "M1M20"); 1272 Statement st = createStatement();
1272 } 1273 schema = schema.replaceAll("\\\\", "\\\\\\\\").replaceAll("'", "\\\\'");
1273 if (executor == null) 1274 try {
1274 throw new SQLException("executor is null", "M1M05"); 1275 st.execute("SET SCHEMA \"" + schema + "\"");
1275 if (millis < 0) 1276 } finally {
1276 throw new SQLException("milliseconds is less than zero", "M1M05"); 1277 st.close();
1277 this.setSoTimeout(millis); 1278 }
1278 } 1279 }
1279 1280
1280 /** 1281 /**
1281 * Retrieves the number of milliseconds the driver will wait for a database request to complete. If the limit is 1282 * Retrieves this Connection object's current schema name.
1282 * exceeded, a SQLException is thrown. 1283 *
1283 * 1284 * @return the current schema name or null if there is none
1284 * @return the current timeout limit in milliseconds; zero means there is no limit 1285 * @throws SQLException if a database access error occurs or this method is called on a closed connection
1285 * @throws SQLException if a database access error occurs or this method is called on a closed Connection 1286 */
1286 */ 1287 @Override
1287 @Override 1288 public String getSchema() throws SQLException {
1288 public int getNetworkTimeout() throws SQLException { 1289 if (closed) {
1289 if (closed) { 1290 throw new SQLException("Cannot call on closed Connection", "M1M20");
1290 throw new SQLException("Cannot call on closed Connection", "M1M20"); 1291 }
1291 } 1292 String cur_schema;
1292 return this.getSoTimeout(); 1293 Statement st = createStatement();
1293 } 1294 ResultSet rs = null;
1294 1295 try {
1295 //== end methods of interface Connection 1296 rs = st.executeQuery("SELECT CURRENT_SCHEMA");
1296 1297 if (!rs.next())
1297 /** 1298 throw new SQLException("Row expected", "02000");
1298 * Returns whether the BLOB type should be mapped to BINARY type. 1299 cur_schema = rs.getString(1);
1299 */ 1300 } finally {
1300 public boolean getBlobAsBinary() { 1301 if (rs != null)
1301 return blobIsBinary; 1302 rs.close();
1302 } 1303 st.close();
1303 1304 }
1304 /** 1305 return cur_schema;
1305 * Returns whether the CLOB type should be mapped to LONGVARCHAR type. 1306 }
1306 */ 1307
1307 public boolean getClobAsLongChar() { 1308 /**
1308 return clobIsLongChar; 1309 * Terminates an open connection. Calling abort results in:
1309 } 1310 * * The connection marked as closed
1310 1311 * * Closes any physical connection to the database
1311 /** 1312 * * Releases resources used by the connection
1312 * Sends the given string to MonetDB as regular statement, making sure there is a prompt after the command is sent. 1313 * * Insures that any thread that is currently accessing the
1313 * All possible returned information is discarded. Encountered errors are reported. 1314 * connection will either progress to completion or throw an
1314 * 1315 * SQLException.
1315 * @param command the exact string to send to MonetDB 1316 * Calling abort marks the connection closed and releases any
1316 * @throws SQLException if an IO exception or a database error occurs 1317 * resources. Calling abort on a closed connection is a no-op.
1317 */ 1318 *
1318 void sendIndependentCommand(String command) throws SQLException { 1319 * @param executor The Executor implementation which will be used by abort
1319 try { 1320 * @throws SQLException if a database access error occurs or the executor is null
1320 protocol.writeNextQuery(language.getQueryTemplateIndex(0), command, language.getQueryTemplateIndex(1)); 1321 * @throws SecurityException if a security manager exists and its checkPermission method denies calling abort
1321 protocol.waitUntilPrompt(); 1322 */
1322 int csrh = protocol.getCurrentServerResponse(); 1323 @Override
1323 if (csrh == ServerResponses.ERROR) { 1324 public void abort(Executor executor) throws SQLException {
1324 String error = protocol.getRemainingStringLine(0); 1325 if (closed)
1325 throw new SQLException(error.substring(6), error.substring(0, 5)); 1326 return;
1326 } 1327 if (executor == null)
1327 } catch (SocketTimeoutException e) { 1328 throw new SQLException("executor is null", "M1M05");
1328 close(); // JDBC 4.1 semantics: abort() 1329 // this is really the simplest thing to do, it destroys
1329 throw new SQLException("connection timed out", "08M33"); 1330 // everything (in particular the server connection)
1330 } catch (IOException e) { 1331 close();
1331 throw new SQLException(e.getMessage(), "08000"); 1332 }
1332 } 1333
1333 } 1334 /**
1334 1335 * Sets the maximum period a Connection or objects created from the
1335 /** 1336 * Connection will wait for the database to reply to any one
1336 * Adds a warning to the pile of warnings this Connection object has. If there were no warnings (or clearWarnings 1337 * request. If any request remains unanswered, the waiting method
1337 * was called) this warning will be the first, otherwise this warning will get appended to the current warning. 1338 * will return with a SQLException, and the Connection or objects
1338 * 1339 * created from the Connection will be marked as closed. Any
1339 * @param reason the warning message 1340 * subsequent use of the objects, with the exception of the close,
1340 */ 1341 * isClosed or Connection.isValid methods, will result in a
1341 protected void addWarning(String reason, String sqlstate) { 1342 * SQLException.
1342 if (warnings == null) { 1343 *
1343 warnings = new SQLWarning(reason, sqlstate); 1344 * @param executor The Executor implementation which will be used by setNetworkTimeout
1344 } else { 1345 * @param millis The time in milliseconds to wait for the database operation to complete
1345 warnings.setNextWarning(new SQLWarning(reason, sqlstate)); 1346 * @throws SQLException if a database access error occurs, this method is called on a closed connection, the
1346 } 1347 * executor is null, or the value specified for seconds is less than 0.
1347 } 1348 */
1348 1349 @Override
1349 /** 1350 public void setNetworkTimeout(Executor executor, int millis) throws SQLException {
1350 * A list of Response objects. Responses are added to this list. Methods of this class are not synchronized. This is 1351 if (closed)
1351 * left as responsibility to the caller to prevent concurrent access. 1352 throw new SQLException("Cannot call on closed Connection", "M1M20");
1352 */ 1353 if (executor == null)
1353 public class ResponseList { 1354 throw new SQLException("executor is null", "M1M05");
1354 1355 if (millis < 0)
1355 /** The cache size (number of rows in a DataBlockResponse object) */ 1356 throw new SQLException("milliseconds is less than zero", "M1M05");
1356 private final int cachesize; 1357
1357 /** The maximum number of results for this query */ 1358 try {
1358 private final int maxrows; 1359 this.setSoTimeout(millis);
1359 /** The ResultSet type to produce */ 1360 } catch (SocketException e) {
1360 private final int rstype; 1361 throw new SQLNonTransientConnectionException(e.getMessage(), "08000");
1361 /** The ResultSet concurrency to produce */ 1362 }
1362 private final int rsconcur; 1363 }
1363 /** The sequence number of this ResponseList */ 1364
1364 private final int seqnr; 1365 /**
1365 /** A list of the Responses associated with the query, in the right order */ 1366 * Retrieves the number of milliseconds the driver will wait for a
1366 private final List<IResponse> responses = new ArrayList<>(); 1367 * database request to complete. If the limit is exceeded, a
1367 /** A map of ResultSetResponses, used for additional DataBlockResponse mapping */ 1368 * SQLException is thrown.
1368 private Map<Integer, ResultSetResponse> rsresponses; 1369 *
1369 /** The current header returned by getNextResponse() */ 1370 * @return the current timeout limit in milliseconds; zero means
1370 private int curResponse = -1; 1371 * there is no limit
1371 1372 * @throws SQLException if a database access error occurs or
1372 /** 1373 * this method is called on a closed Connection
1373 * Main constructor. The query argument can either be a String or List. An SQLException is thrown if another 1374 * @since 1.7
1374 * object instance is supplied. 1375 */
1375 * 1376 @Override
1376 * @param cachesize overall cachesize to use 1377 public int getNetworkTimeout() throws SQLException {
1377 * @param maxrows maximum number of rows to allow in the set 1378 if (closed)
1378 * @param rstype the type of result sets to produce 1379 throw new SQLException("Cannot call on closed Connection", "M1M20");
1379 * @param rsconcur the concurrency of result sets to produce 1380
1380 */ 1381 try {
1381 ResponseList(int cachesize, int maxrows, int rstype, int rsconcur) { 1382 return this.getSoTimeout();
1382 this.cachesize = cachesize; 1383 } catch (SocketException e) {
1383 this.maxrows = maxrows; 1384 throw new SQLNonTransientConnectionException(e.getMessage(), "08000");
1384 this.rstype = rstype; 1385 }
1385 this.rsconcur = rsconcur; 1386 }
1386 this.seqnr = SeqCounter++; 1387
1387 } 1388 //== end methods of interface Connection
1388 1389
1389 public int getCachesize() { 1390 /**
1390 return cachesize; 1391 * Returns whether the BLOB type should be mapped to BINARY type.
1391 } 1392 */
1392 1393 public boolean getBlobAsBinary() {
1393 public int getRstype() { 1394 return blobIsBinary;
1394 return rstype; 1395 }
1395 } 1396
1396 1397 /**
1397 public int getRsconcur() { 1398 * Returns whether the CLOB type should be mapped to LONGVARCHAR type.
1398 return rsconcur; 1399 */
1399 } 1400 public boolean getClobAsLongChar() {
1400 1401 return clobIsLongChar;
1401 public int getMaxrows() { 1402 }
1402 return maxrows; 1403
1403 } 1404 /**
1404 1405 * Sends the given string to MonetDB as special transaction command.
1405 /** 1406 * All possible returned information is discarded.
1406 * Retrieves the next available response, or null if there are no more responses. 1407 * Encountered errors are reported.
1407 * 1408 *
1408 * @return the next Response available or null 1409 * @param command the exact string to send to MonetDB
1409 */ 1410 * @throws SQLException if an IO exception or a database error occurs
1410 IResponse getNextResponse() throws SQLException { 1411 */
1411 if (rstype == ResultSet.TYPE_FORWARD_ONLY) { 1412 private void sendTransactionCommand(String command) throws SQLException {
1412 // free resources if we're running forward only 1413 // create a container for the result
1413 if (curResponse >= 0 && curResponse < responses.size()) { 1414 ResponseList l = new ResponseList(0, 0, ResultSet.FETCH_FORWARD, ResultSet.CONCUR_READ_ONLY);
1414 IResponse tmp = responses.get(curResponse); 1415 // send the appropriate query string to the database
1415 if (tmp != null) { 1416 try {
1416 tmp.close(); 1417 l.processQuery(command);
1417 } 1418 } finally {
1418 responses.set(curResponse, null); 1419 l.close();
1419 } 1420 }
1420 } 1421 }
1421 curResponse++; 1422
1422 if (curResponse >= responses.size()) { 1423 /**
1423 // ResponseList is obviously completed so, there are no more responses 1424 * Sends the given string to MonetDB as regular statement, making sure there is a prompt after the command is sent.
1424 return null; 1425 * All possible returned information is discarded. Encountered errors are reported.
1425 } else { 1426 *
1426 // return this response 1427 * @param command the exact string to send to MonetDB
1427 return responses.get(curResponse); 1428 * @throws SQLException if an IO exception or a database error occurs
1428 } 1429 */
1429 } 1430 void sendIndependentCommand(String command) throws SQLException {
1430 1431 try {
1431 /** 1432 protocol.writeNextQuery(language.getQueryTemplateIndex(0), command, language.getQueryTemplateIndex(1));
1432 * Closes the Response at index i, if not null. 1433 protocol.waitUntilPrompt();
1433 * 1434 int csrh = protocol.getCurrentServerResponse();
1434 * @param i the index position of the header to close 1435 if (csrh == ServerResponses.ERROR) {
1435 */ 1436 String error = protocol.getRemainingStringLine(0);
1436 void closeResponse(int i) { 1437 throw new SQLException(error.substring(6), error.substring(0, 5));
1437 if (i < 0 || i >= responses.size()) return; 1438 }
1438 IResponse tmp = responses.set(i, null); 1439 } catch (SocketTimeoutException e) {
1439 if (tmp != null) 1440 close(); // JDBC 4.1 semantics: abort()
1440 tmp.close(); 1441 throw new SQLNonTransientConnectionException("connection timed out", "08M33");
1441 } 1442 } catch (IOException e) {
1442 1443 throw new SQLNonTransientConnectionException(e.getMessage(), "08000");
1443 /** 1444 }
1444 * Closes the current response. 1445 }
1445 */ 1446
1446 void closeCurrentResponse() { 1447 /**
1447 closeResponse(curResponse); 1448 * Adds a warning to the pile of warnings this Connection object has. If there were no warnings (or clearWarnings
1448 } 1449 * was called) this warning will be the first, otherwise this warning will get appended to the current warning.
1449 1450 *
1450 /** 1451 * @param reason the warning message
1451 * Closes the current and previous responses. 1452 */
1452 */ 1453 void addWarning(String reason, String sqlstate) {
1453 void closeCurOldResponses() { 1454 if (warnings == null) {
1454 for (int i = curResponse; i >= 0; i--) { 1455 warnings = new SQLWarning(reason, sqlstate);
1455 closeResponse(i); 1456 } else {
1456 } 1457 warnings.setNextWarning(new SQLWarning(reason, sqlstate));
1457 } 1458 }
1458 1459 }
1459 /** 1460
1460 * Closes this ResponseList by closing all the Responses in this ResponseList. 1461 /**
1461 */ 1462 * A list of Response objects. Responses are added to this list. Methods of this class are not synchronized. This is
1462 public void close() { 1463 * left as responsibility to the caller to prevent concurrent access.
1463 for (int i = 0; i < responses.size(); i++) { 1464 */
1464 closeResponse(i); 1465 public class ResponseList {
1465 } 1466
1466 } 1467 /** The cache size (number of rows in a DataBlockResponse object) */
1467 1468 private final int cachesize;
1468 /** 1469 /** The maximum number of results for this query */
1469 * Returns whether this ResponseList has still unclosed Responses. 1470 private final int maxrows;
1470 */ 1471 /** The ResultSet type to produce */
1471 boolean hasUnclosedResponses() { 1472 private final int rstype;
1472 for (IResponse r : responses) { 1473 /** The ResultSet concurrency to produce */
1473 if (r != null) 1474 private final int rsconcur;
1474 return true; 1475 /** The sequence number of this ResponseList */
1475 } 1476 private final int seqnr;
1476 return false; 1477 /** A list of the Responses associated with the query, in the right order */
1477 } 1478 private final List<IResponse> responses = new ArrayList<>();
1478 1479 /** A map of ResultSetResponses, used for additional DataBlockResponse mapping */
1479 /** 1480 private Map<Integer, ResultSetResponse> rsresponses;
1480 * Executes the query contained in this ResponseList, and stores the Responses resulting from this query in this 1481 /** The current header returned by getNextResponse() */
1481 * ResponseList. 1482 private int curResponse = -1;
1482 * 1483
1483 * @throws SQLException if a database error occurs 1484 /**
1484 */ 1485 * Main constructor. The query argument can either be a String or List. An SQLException is thrown if another
1485 void processQuery(String query) throws SQLException { 1486 * object instance is supplied.
1486 this.executeQuery(language.getQueryTemplates(), query); 1487 *
1487 } 1488 * @param cachesize overall cachesize to use
1488 1489 * @param maxrows maximum number of rows to allow in the set
1489 /** 1490 * @param rstype the type of result sets to produce
1490 * Internal executor of queries. 1491 * @param rsconcur the concurrency of result sets to produce
1491 * 1492 */
1492 * @param templ the template to fill in 1493 ResponseList(int cachesize, int maxrows, int rstype, int rsconcur) {
1493 * @param query the query to execute 1494 this.cachesize = cachesize;
1494 * @throws SQLException if a database error occurs 1495 this.maxrows = maxrows;
1495 */ 1496 this.rstype = rstype;
1496 @SuppressWarnings("fallthrough") 1497 this.rsconcur = rsconcur;
1497 public void executeQuery(String[] templ, String query) throws SQLException { 1498 this.seqnr = SeqCounter++;
1498 String error = null; 1499 }
1499 1500
1500 try { 1501 public int getCachesize() {
1501 // make sure we're ready to send query; read data till we have the prompt it is possible (and most 1502 return cachesize;
1502 // likely) that we already have the prompt and do not have to skip any lines. Ignore errors from 1503 }
1503 // previous result sets. 1504
1504 protocol.waitUntilPrompt(); 1505 public int getRstype() {
1505 1506 return rstype;
1506 // {{{ set reply size 1507 }
1507 /* 1508
1508 * Change the reply size of the server. If the given value is the same as the current value known 1509 public int getRsconcur() {
1509 * to use, then ignore this call. If it is set to 0 we get a prompt after the server sent it's 1510 return rsconcur;
1510 * header. 1511 }
1511 * 1512
1512 * 2017: For now, in the embedded connection, the value set cachesize will be always the default one. 1513 public int getMaxrows() {
1513 */ 1514 return maxrows;
1514 int size = (cachesize != 0 && !isEmbedded) ? cachesize : MonetConnection.this.getDefFetchsize(); 1515 }
1515 size = maxrows != 0 ? Math.min(maxrows, size) : size; 1516
1516 // don't do work if it's not needed 1517 /**
1517 if (!isEmbedded && language.getRepresentation().equals("sql") && size != curReplySize && 1518 * Retrieves the next available response, or null if there are no more responses.
1518 !Arrays.deepEquals(templ, language.getCommandTemplates())) { 1519 *
1519 sendControlCommand(ControlCommands.REPLY_SIZE, size); 1520 * @return the next Response available or null
1520 // store the reply size after a successful change 1521 */
1521 curReplySize = size; 1522 IResponse getNextResponse() throws SQLException {
1522 } 1523 if (rstype == ResultSet.TYPE_FORWARD_ONLY) {
1523 // }}} set reply size 1524 // free resources if we're running forward only
1524 1525 if (curResponse >= 0 && curResponse < responses.size()) {
1525 // If the query is larger than the TCP buffer size, use a special send thread to avoid deadlock with 1526 IResponse tmp = responses.get(curResponse);
1526 // the server due to blocking behaviour when the buffer is full. Because the server will be writing 1527 if (tmp != null) {
1527 // back results to us, it will eventually block as well when its TCP buffer gets full, as we are 1528 tmp.close();
1528 // blocking an not consuming from it. The result is a state where both client and server want to 1529 }
1529 // write, but block. 1530 responses.set(curResponse, null);
1530 if (query.length() > getBlockSize()) { 1531 }
1531 // get a reference to the send thread 1532 }
1532 if (senderThread == null) { 1533 curResponse++;
1533 senderThread = new SenderThread(protocol); 1534 if (curResponse >= responses.size()) {
1534 } 1535 // ResponseList is obviously completed so, there are no more responses
1535 // tell it to do some work! 1536 return null;
1536 senderThread.runQuery(templ, query); 1537 } else {
1537 } else { 1538 // return this response
1538 // this is a simple call, which is a lot cheaper and will always succeed for small queries. 1539 return responses.get(curResponse);
1539 protocol.writeNextQuery((templ[0] == null) ? "" : templ[0], query, 1540 }
1540 (templ[1] == null) ? "" : templ[1]); 1541 }
1541 } 1542
1542 1543 /**
1543 // go for new results 1544 * Closes the Response at index i, if not null.
1544 protocol.fetchNextResponseData(); 1545 *
1545 int nextResponse = protocol.getCurrentServerResponse(); 1546 * @param i the index position of the header to close
1546 IResponse res = null; 1547 */
1547 while (nextResponse != ServerResponses.PROMPT) { 1548 void closeResponse(int i) {
1548 // each response should start with a start of header (or error) 1549 if (i < 0 || i >= responses.size()) return;
1549 switch (nextResponse) { 1550 IResponse tmp = responses.set(i, null);
1550 case ServerResponses.SOHEADER: 1551 if (tmp != null)
1551 // make the response object, and fill it 1552 tmp.close();
1552 int nextStartHeader = protocol.getNextStarterHeader(); 1553 }
1553 try { 1554
1554 switch (nextStartHeader) { 1555 /**
1555 case StarterHeaders.Q_PARSE: 1556 * Closes the current response.
1556 throw new ProtocolException("Q_PARSE header not allowed here"); 1557 */
1557 case StarterHeaders.Q_TABLE: 1558 void closeCurrentResponse() {
1558 case StarterHeaders.Q_PREPARE: { 1559 closeResponse(curResponse);
1559 res = protocol.getNextResultSetResponse(MonetConnection.this, 1560 }
1560 ResponseList.this, this.seqnr, this.maxrows); 1561
1561 ResultSetResponse rsreponse = (ResultSetResponse) res; 1562 /**
1562 if (rsresponses == null) { 1563 * Closes the current and previous responses.
1563 rsresponses = new HashMap<>(); 1564 */
1564 } 1565 void closeCurOldResponses() {
1565 rsresponses.put(rsreponse.getId(), rsreponse); 1566 for (int i = curResponse; i >= 0; i--) {
1566 } 1567 closeResponse(i);
1567 break; 1568 }
1568 case StarterHeaders.Q_UPDATE: 1569 }
1569 res = protocol.getNextUpdateResponse(); 1570
1570 break; 1571 /**
1571 case StarterHeaders.Q_SCHEMA: 1572 * Closes this ResponseList by closing all the Responses in this ResponseList.
1572 res = protocol.getNextSchemaResponse(); 1573 */
1573 break; 1574 public void close() {
1574 case StarterHeaders.Q_TRANS: 1575 for (int i = 0; i < responses.size(); i++) {
1575 res = protocol.getNextAutoCommitResponse(); 1576 closeResponse(i);
1576 boolean isAutoCommit = ((AutoCommitResponse) res).isAutocommit(); 1577 }
1577 1578 }
1578 if (MonetConnection.this.getAutoCommit() && isAutoCommit) { 1579
1579 MonetConnection.this.addWarning("Server enabled auto commit mode " + 1580 /**
1580 "while local state already was auto commit.", "01M11"); 1581 * Returns whether this ResponseList has still unclosed Responses.
1581 } 1582 */
1582 MonetConnection.this.autoCommit = isAutoCommit; 1583 boolean hasUnclosedResponses() {
1583 break; 1584 for (IResponse r : responses) {
1584 case StarterHeaders.Q_BLOCK: { 1585 if (r != null)
1585 AbstractDataBlockResponse next = protocol.getNextDatablockResponse(rsresponses); 1586 return true;
1586 if (next == null) { 1587 }
1587 error = "M0M12!No ResultSetResponse for a DataBlock found"; 1588 return false;
1588 break; 1589 }
1589 } 1590
1590 res = next; 1591 /**
1591 } 1592 * Executes the query contained in this ResponseList, and stores the Responses resulting from this query in this
1592 break; 1593 * ResponseList.
1593 } 1594 *
1594 } catch (ProtocolException e) { 1595 * @throws SQLException if a database error occurs
1595 error = "M0M10!error while parsing start of header:\n" + e.getMessage() + " found: '" 1596 */
1596 + protocol.getRemainingStringLine(0).charAt(e.getErrorOffset()) + "'" + 1597 void processQuery(String query) throws SQLException {
1597 " in: \"" + protocol.getRemainingStringLine(0) + "\"" + " at pos: " 1598 this.executeQuery(language.getQueryTemplates(), query);
1598 + e.getErrorOffset(); 1599 }
1599 // flush all the rest 1600
1600 protocol.waitUntilPrompt(); 1601 /**
1601 nextResponse = protocol.getCurrentServerResponse(); 1602 * Internal executor of queries.
1602 break; 1603 *
1603 } 1604 * @param templ the template to fill in
1604 1605 * @param query the query to execute
1605 // immediately handle errors after parsing the header (res may be null) 1606 * @throws SQLException if a database error occurs
1606 if (error != null) { 1607 */
1607 protocol.waitUntilPrompt(); 1608 @SuppressWarnings("fallthrough")
1608 nextResponse = protocol.getCurrentServerResponse(); 1609 public void executeQuery(String[] templ, String query) throws SQLException {
1609 break; 1610 String error = null;
1610 } 1611
1611 1612 try {
1612 // here we have a res object, which we can start filling 1613 // make sure we're ready to send query; read data till we have the prompt it is possible (and most
1613 if (res instanceof IIncompleteResponse) { 1614 // likely) that we already have the prompt and do not have to skip any lines. Ignore errors from
1614 IIncompleteResponse iter = (IIncompleteResponse) res; 1615 // previous result sets.
1615 while (iter.wantsMore()) { 1616 protocol.waitUntilPrompt();
1616 try { 1617
1617 protocol.fetchNextResponseData(); 1618 // {{{ set reply size
1618 iter.addLines(protocol); 1619 /*
1619 } catch (ProtocolException ex) { 1620 * Change the reply size of the server. If the given value is the same as the current value known
1620 // right, some protocol violation, skip the rest of the result 1621 * to use, then ignore this call. If it is set to 0 we get a prompt after the server sent it's
1621 error = "M0M10!" + ex.getMessage(); 1622 * header.
1622 protocol.waitUntilPrompt(); 1623 *
1623 nextResponse = protocol.getCurrentServerResponse(); 1624 * 2017: For now, in the embedded connection, the value set cachesize will be always the default one.
1624 break; 1625 */
1625 } 1626 int size = (cachesize != 0 && !isEmbedded) ? cachesize : MonetConnection.this.getDefFetchsize();
1626 } 1627 size = maxrows != 0 ? Math.min(maxrows, size) : size;
1627 } 1628 // don't do work if it's not needed
1628 1629 if (!isEmbedded && language.getRepresentation().equals("sql") && size != curReplySize &&
1629 if (error != null) { 1630 !Arrays.deepEquals(templ, language.getCommandTemplates())) {
1630 break; 1631 sendControlCommand(ControlCommands.REPLY_SIZE, size);
1631 } 1632 // store the reply size after a successful change
1632 1633 curReplySize = size;
1633 // it is of no use to store DataBlockResponses, you never want to retrieve them directly 1634 }
1634 // anyway 1635 // }}} set reply size
1635 if (!(res instanceof AbstractDataBlockResponse)) { 1636
1636 responses.add(res); 1637 // If the query is larger than the TCP buffer size, use a special send thread to avoid deadlock with
1637 } 1638 // the server due to blocking behaviour when the buffer is full. Because the server will be writing
1638 // read the next line (can be prompt, new result, error, etc.) before we start the loop over 1639 // back results to us, it will eventually block as well when its TCP buffer gets full, as we are
1639 protocol.fetchNextResponseData(); 1640 // blocking an not consuming from it. The result is a state where both client and server want to
1640 nextResponse = protocol.getCurrentServerResponse(); 1641 // write, but block.
1641 break; 1642 if (query.length() > getBlockSize()) {
1642 case ServerResponses.INFO: 1643 // get a reference to the send thread
1643 addWarning(protocol.getRemainingStringLine(0), "01000"); 1644 if (senderThread == null) {
1644 // read the next line (can be prompt, new result, error, etc.) before we start the loop over 1645 senderThread = new SenderThread(protocol);
1645 protocol.fetchNextResponseData(); 1646 }
1646 nextResponse = protocol.getCurrentServerResponse(); 1647 // tell it to do some work!
1647 break; 1648 senderThread.runQuery(templ, query);
1648 case ServerResponses.ERROR: 1649 } else {
1649 // read everything till the prompt (should be error) we don't know if we ignore some 1650 // this is a simple call, which is a lot cheaper and will always succeed for small queries.
1650 // garbage here... but the log should reveal that 1651 protocol.writeNextQuery((templ[0] == null) ? "" : templ[0], query,
1651 error = protocol.getRemainingStringLine(0); 1652 (templ[1] == null) ? "" : templ[1]);
1652 protocol.waitUntilPrompt(); 1653 }
1653 nextResponse = protocol.getCurrentServerResponse(); 1654
1654 break; 1655 // go for new results
1655 default: 1656 protocol.fetchNextResponseData();
1656 throw new SQLException("Protocol violation, unexpected line!", "M0M10"); 1657 int nextResponse = protocol.getCurrentServerResponse();
1657 } 1658 IResponse res = null;
1658 } 1659 while (nextResponse != ServerResponses.PROMPT) {
1659 1660 // each response should start with a start of header (or error)
1660 // if we used the senderThread, make sure it has finished 1661 switch (nextResponse) {
1661 if (senderThread != null) { 1662 case ServerResponses.SOHEADER:
1662 String tmp = senderThread.getErrors(); 1663 // make the response object, and fill it
1663 if (tmp != null) { 1664 int nextStartHeader = protocol.getNextStarterHeader();
1664 if (error == null) { 1665 try {
1665 error = "08000!" + tmp; 1666 switch (nextStartHeader) {
1666 } else { 1667 case StarterHeaders.Q_PARSE:
1667 error += "\n08000!" + tmp; 1668 throw new ProtocolException("Q_PARSE header not allowed here");
1668 } 1669 case StarterHeaders.Q_TABLE:
1669 } 1670 case StarterHeaders.Q_PREPARE: {
1670 } 1671 res = protocol.getNextResultSetResponse(MonetConnection.this,
1671 if (error != null) { 1672 ResponseList.this, this.seqnr, this.maxrows);
1672 SQLException ret = null; 1673 ResultSetResponse rsreponse = (ResultSetResponse) res;
1673 String[] errorsList = error.split("\n"); 1674 if (rsresponses == null) {
1674 for (String singleError : errorsList) { 1675 rsresponses = new HashMap<>();
1675 String reason = isEmbedded() ? singleError : singleError.substring(6); 1676 }
1676 String sqlState = isEmbedded() ? "M0M10" : singleError.substring(0, 5); 1677 rsresponses.put(rsreponse.getId(), rsreponse);
1677 if (ret == null) { 1678 }
1678 ret = new SQLException(reason, sqlState); 1679 break;
1679 } else { 1680 case StarterHeaders.Q_UPDATE:
1680 ret.setNextException(new SQLException(reason, sqlState)); 1681 res = protocol.getNextUpdateResponse();
1681 } 1682 break;
1682 } 1683 case StarterHeaders.Q_SCHEMA:
1683 throw ret; 1684 res = protocol.getNextSchemaResponse();
1684 } 1685 break;
1685 } catch (SocketTimeoutException e) { 1686 case StarterHeaders.Q_TRANS:
1686 this.close(); // JDBC 4.1 semantics, abort() 1687 res = protocol.getNextAutoCommitResponse();
1687 throw new SQLException("connection timed out", "08M33"); 1688 boolean isAutoCommit = ((AutoCommitResponse) res).isAutocommit();
1688 } catch (IOException e) { 1689
1689 closed = true; 1690 if (MonetConnection.this.getAutoCommit() && isAutoCommit) {
1690 throw new SQLException(e.getMessage() + " (mserver still alive?)", "08000"); 1691 MonetConnection.this.addWarning("Server enabled auto commit mode " +
1691 } 1692 "while local state already was auto commit.", "01M11");
1692 } 1693 }
1693 } 1694 MonetConnection.this.autoCommit = isAutoCommit;
1695 break;
1696 case StarterHeaders.Q_BLOCK: {
1697 AbstractDataBlockResponse next = protocol.getNextDatablockResponse(rsresponses);
1698 if (next == null) {
1699 error = "M0M12!No ResultSetResponse for a DataBlock found";
1700 break;
1701 }
1702 res = next;
1703 }
1704 break;
1705 }
1706 } catch (ProtocolException e) {
1707 error = "M0M10!error while parsing start of header:\n" + e.getMessage() + " found: '"
1708 + protocol.getRemainingStringLine(0).charAt(e.getErrorOffset()) + "'" +
1709 " in: \"" + protocol.getRemainingStringLine(0) + "\"" + " at pos: "
1710 + e.getErrorOffset();
1711 // flush all the rest
1712 protocol.waitUntilPrompt();
1713 nextResponse = protocol.getCurrentServerResponse();
1714 break;
1715 }
1716 // immediately handle errors after parsing the header (res may be null)
1717 if (error != null) {
1718 protocol.waitUntilPrompt();
1719 nextResponse = protocol.getCurrentServerResponse();
1720 break;
1721 }
1722 // here we have a res object, which we can start filling
1723 if (res instanceof IIncompleteResponse) {
1724 IIncompleteResponse iter = (IIncompleteResponse) res;
1725 while (iter.wantsMore()) {
1726 try {
1727 protocol.fetchNextResponseData();
1728 iter.addLines(protocol);
1729 } catch (ProtocolException ex) {
1730 // right, some protocol violation, skip the rest of the result
1731 error = "M0M10!" + ex.getMessage();
1732 protocol.waitUntilPrompt();
1733 nextResponse = protocol.getCurrentServerResponse();
1734 break;
1735 }
1736 }
1737 }
1738
1739 if (error != null) {
1740 break;
1741 }
1742
1743 // it is of no use to store DataBlockResponses, you never want to retrieve them directly
1744 // anyway
1745 if (!(res instanceof AbstractDataBlockResponse)) {
1746 responses.add(res);
1747 }
1748 // read the next line (can be prompt, new result, error, etc.) before we start the loop over
1749 protocol.fetchNextResponseData();
1750 nextResponse = protocol.getCurrentServerResponse();
1751 break;
1752 case ServerResponses.INFO:
1753 addWarning(protocol.getRemainingStringLine(0), "01000");
1754 // read the next line (can be prompt, new result, error, etc.) before we start the loop over
1755 protocol.fetchNextResponseData();
1756 nextResponse = protocol.getCurrentServerResponse();
1757 break;
1758 case ServerResponses.ERROR:
1759 // read everything till the prompt (should be error) we don't know if we ignore some
1760 // garbage here... but the log should reveal that
1761 error = protocol.getRemainingStringLine(0);
1762 protocol.waitUntilPrompt();
1763 nextResponse = protocol.getCurrentServerResponse();
1764 break;
1765 default:
1766 throw new SQLException("Protocol violation, unexpected line!", "M0M10");
1767 }
1768 }
1769
1770 // if we used the senderThread, make sure it has finished
1771 if (senderThread != null) {
1772 String tmp = senderThread.getErrors();
1773 if (tmp != null) {
1774 if (error == null) {
1775 error = "08000!" + tmp;
1776 } else {
1777 error += "\n08000!" + tmp;
1778 }
1779 }
1780 }
1781 if (error != null) {
1782 SQLException ret = null;
1783 String[] errorsList = error.split("\n");
1784 for (String singleError : errorsList) {
1785 SQLException newErr;
1786 String reason = isEmbedded() ? singleError : singleError.substring(6);
1787 String sqlState = isEmbedded() ? "M0M10" : singleError.substring(0, 5);
1788 if (singleError.length() >= 6) {
1789 newErr = new SQLException(reason, sqlState);
1790 } else {
1791 newErr = new SQLNonTransientConnectionException(singleError, "08000");
1792 }
1793 if (ret == null) {
1794 ret = newErr;
1795 } else {
1796 ret.setNextException(newErr);
1797 }
1798 }
1799 throw ret;
1800 }
1801 } catch (SocketTimeoutException e) {
1802 this.close(); // JDBC 4.1 semantics, abort()
1803 throw new SQLNonTransientConnectionException("connection timed out", "08M33");
1804 } catch (IOException e) {
1805 closed = true;
1806 throw new SQLNonTransientConnectionException(e.getMessage() + " (mserver5 still alive?)", "08006");
1807 }
1808 }
1809 }
1694 } 1810 }