Mercurial > hg > monetdb-java
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 } |