1 | /* |
2 | |
3 | Derby - Class org.apache.derby.impl.jdbc.EmbedConnection |
4 | |
5 | Copyright 1997, 2005 The Apache Software Foundation or its licensors, as applicable. |
6 | |
7 | Licensed under the Apache License, Version 2.0 (the "License"); |
8 | you may not use this file except in compliance with the License. |
9 | You may obtain a copy of the License at |
10 | |
11 | http://www.apache.org/licenses/LICENSE-2.0 |
12 | |
13 | Unless required by applicable law or agreed to in writing, software |
14 | distributed under the License is distributed on an "AS IS" BASIS, |
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | See the License for the specific language governing permissions and |
17 | limitations under the License. |
18 | |
19 | */ |
20 | |
21 | package org.apache.derby.impl.jdbc; |
22 | |
23 | import org.apache.derby.jdbc.InternalDriver; |
24 | |
25 | import org.apache.derby.iapi.reference.Attribute; |
26 | import org.apache.derby.iapi.reference.JDBC20Translation; |
27 | import org.apache.derby.iapi.reference.JDBC30Translation; |
28 | import org.apache.derby.iapi.reference.MessageId; |
29 | import org.apache.derby.iapi.reference.Property; |
30 | import org.apache.derby.iapi.reference.SQLState; |
31 | |
32 | import org.apache.derby.iapi.services.context.ContextManager; |
33 | import org.apache.derby.iapi.services.memory.LowMemory; |
34 | import org.apache.derby.iapi.services.monitor.Monitor; |
35 | import org.apache.derby.iapi.services.sanity.SanityManager; |
36 | |
37 | import org.apache.derby.iapi.jdbc.AuthenticationService; |
38 | import org.apache.derby.iapi.jdbc.EngineConnection; |
39 | |
40 | import org.apache.derby.iapi.db.Database; |
41 | import org.apache.derby.iapi.error.StandardException; |
42 | import org.apache.derby.iapi.services.i18n.MessageService; |
43 | import org.apache.derby.iapi.sql.conn.LanguageConnectionContext; |
44 | import org.apache.derby.iapi.sql.execute.ExecutionContext; |
45 | import org.apache.derby.iapi.sql.dictionary.DataDictionary; |
46 | import org.apache.derby.iapi.store.access.XATransactionController; |
47 | |
48 | /* can't import due to name overlap: |
49 | import java.sql.Connection; |
50 | import java.sql.ResultSet; |
51 | */ |
52 | import java.sql.PreparedStatement; |
53 | import java.sql.CallableStatement; |
54 | import java.sql.DatabaseMetaData; |
55 | import java.sql.SQLException; |
56 | import java.sql.SQLWarning; |
57 | import java.sql.Statement; |
58 | |
59 | import java.util.Properties; |
60 | |
61 | /** |
62 | * Local implementation of Connection for a JDBC driver in |
63 | * the same process as the database. |
64 | * <p> |
65 | * There is always a single root (parent) connection. The |
66 | * initial JDBC connection is the root connection. A |
67 | * call to <I>getCurrentConnection()</I> or with the URL |
68 | * <I>jdbc:default:connection</I> yields a nested connection that shares |
69 | * the same root connection as the parent. A nested connection |
70 | * is implemented using this class. The nested connection copies the |
71 | * state of the parent connection and shares some of the same |
72 | * objects (e.g. ContextManager) that are shared across all |
73 | * nesting levels. The proxy also maintains its own |
74 | * state that is distinct from its parent connection (e.g. |
75 | * autocommit or warnings). |
76 | * <p> |
77 | * <B>SYNCHRONIZATION</B>: Just about all JDBC actions are |
78 | * synchronized across all connections stemming from the |
79 | * same root connection. The synchronization is upon |
80 | * the a synchronized object return by the rootConnection. |
81 | <P><B>Supports</B> |
82 | <UL> |
83 | <LI> JDBC 2.0 |
84 | </UL> |
85 | * |
86 | * @author djd |
87 | * |
88 | * @see TransactionResourceImpl |
89 | * |
90 | */ |
91 | public class EmbedConnection implements EngineConnection |
92 | { |
93 | |
94 | private static final StandardException exceptionClose = StandardException.closeException(); |
95 | |
96 | /** |
97 | * Static exception to be thrown when a Connection request can not |
98 | * be fulfilled due to lack of memory. A static exception as the lack |
99 | * of memory would most likely cause another OutOfMemoryException and |
100 | * if there is not enough memory to create the OOME exception then something |
101 | * like the VM dying could occur. Simpler just to throw a static. |
102 | */ |
103 | public static final SQLException NO_MEM = |
104 | Util.generateCsSQLException(SQLState.LOGIN_FAILED, "java.lang.OutOfMemoryError"); |
105 | |
106 | /** |
107 | * Low memory state object for connection requests. |
108 | */ |
109 | public static final LowMemory memoryState = new LowMemory(); |
110 | |
111 | ////////////////////////////////////////////////////////// |
112 | // OBJECTS SHARED ACROSS CONNECTION NESTING |
113 | ////////////////////////////////////////////////////////// |
114 | DatabaseMetaData dbMetadata; |
115 | |
116 | final TransactionResourceImpl tr; // always access tr thru getTR() |
117 | |
118 | |
119 | ////////////////////////////////////////////////////////// |
120 | // STATE (copied to new nested connections, but nesting |
121 | // specific) |
122 | ////////////////////////////////////////////////////////// |
123 | private boolean active; |
124 | boolean autoCommit = true; |
125 | boolean needCommit; |
126 | /* |
127 | following is a new feature in JDBC3.0 where you can specify the holdability |
128 | of a resultset at the end of the transaction. This gets set by the |
129 | new method setHoldability(int) in JDBC3.0 |
130 | * |
131 | */ |
132 | private int connectionHoldAbility = JDBC30Translation.HOLD_CURSORS_OVER_COMMIT; |
133 | |
134 | |
135 | ////////////////////////////////////////////////////////// |
136 | // NESTING SPECIFIC OBJECTS |
137 | ////////////////////////////////////////////////////////// |
138 | /* |
139 | ** The root connection is the base connection upon |
140 | ** which all actions are synchronized. By default, |
141 | ** we are the root connection unless we are created |
142 | ** by copying the state from another connection. |
143 | */ |
144 | final EmbedConnection rootConnection; |
145 | private SQLWarning topWarning; |
146 | /** |
147 | Factory for JDBC objects to be created. |
148 | */ |
149 | private InternalDriver factory; |
150 | |
151 | /** |
152 | The Connection object the application is using when accessing the |
153 | database through this connection. In most cases this will be equal |
154 | to this. When Connection pooling is being used, then it will |
155 | be set to the Connection object handed to the application. |
156 | It is used for the getConnection() methods of various JDBC objects. |
157 | */ |
158 | private java.sql.Connection applicationConnection; |
159 | |
160 | /** |
161 | An increasing counter to assign to a ResultSet on its creation. |
162 | Used for ordering ResultSets returned from a procedure, always |
163 | returned in order of their creation. Is maintained at the root connection. |
164 | */ |
165 | private int resultSetId; |
166 | |
167 | /** Cached string representation of the connection id */ |
168 | private String connString; |
169 | |
170 | |
171 | ////////////////////////////////////////////////////////// |
172 | // CONSTRUCTORS |
173 | ////////////////////////////////////////////////////////// |
174 | |
175 | // create a new Local Connection, using a new context manager |
176 | // |
177 | public EmbedConnection(InternalDriver driver, String url, Properties info) |
178 | throws SQLException |
179 | { |
180 | // Create a root connection. |
181 | applicationConnection = rootConnection = this; |
182 | factory = driver; |
183 | |
184 | |
185 | tr = new TransactionResourceImpl(driver, url, info); |
186 | |
187 | active = true; |
188 | |
189 | // register this thread and its context manager with |
190 | // the global context service |
191 | setupContextStack(); |
192 | |
193 | try { |
194 | |
195 | // stick my context into the context manager |
196 | EmbedConnectionContext context = pushConnectionContext(tr.getContextManager()); |
197 | |
198 | // if we are shutting down don't attempt to boot or create the database |
199 | boolean shutdown = Boolean.valueOf(info.getProperty(Attribute.SHUTDOWN_ATTR)).booleanValue(); |
200 | |
201 | // see if database is already booted |
202 | Database database = (Database) Monitor.findService(Property.DATABASE_MODULE, tr.getDBName()); |
203 | |
204 | // See if user wants to create a new database. |
205 | boolean createBoot = createBoot(info); |
206 | if (database != null) |
207 | { |
208 | // database already booted by someone else |
209 | tr.setDatabase(database); |
210 | } |
211 | else if (!shutdown) |
212 | { |
213 | // Return false iff the monitor cannot handle a service of the type |
214 | // indicated by the proptocol within the name. If that's the case |
215 | // then we are the wrong driver. |
216 | if (!bootDatabase(info)) |
217 | { |
218 | tr.clearContextInError(); |
219 | setInactive(); |
220 | return; |
221 | } |
222 | } |
223 | |
224 | |
225 | if (createBoot && !shutdown) |
226 | { |
227 | // if we are shutting down don't attempt to boot or create the database |
228 | |
229 | if (tr.getDatabase() != null) { |
230 | addWarning(EmbedSQLWarning.newEmbedSQLWarning(SQLState.DATABASE_EXISTS, getDBName())); |
231 | } else { |
232 | |
233 | // check for user's credential and authenticate the user |
234 | // with system level authentication service. |
235 | // FIXME: We should also check for CREATE DATABASE operation |
236 | // authorization for the user if authorization was |
237 | // set at the system level. |
238 | // Right now, the authorization service does not |
239 | // restrict/account for Create database op. |
240 | checkUserCredentials(null, info); |
241 | |
242 | // Process with database creation |
243 | database = createDatabase(tr.getDBName(), info); |
244 | tr.setDatabase(database); |
245 | } |
246 | } |
247 | |
248 | |
249 | if (tr.getDatabase() == null) { |
250 | String dbname = tr.getDBName(); |
251 | // do not clear the TransactionResource context. It will be restored |
252 | // as part of the finally clause below. |
253 | this.setInactive(); |
254 | throw newSQLException(SQLState.DATABASE_NOT_FOUND, dbname); |
255 | } |
256 | |
257 | |
258 | // Check User's credentials and if it is a valid user of |
259 | // the database |
260 | // |
261 | checkUserCredentials(tr.getDBName(), info); |
262 | |
263 | // Make a real connection into the database, setup lcc, tc and all |
264 | // the rest. |
265 | tr.startTransaction(); |
266 | |
267 | // now we have the database connection, we can shut down |
268 | if (shutdown) { |
269 | throw tr.shutdownDatabaseException(); |
270 | } |
271 | |
272 | } |
273 | catch (OutOfMemoryError noMemory) |
274 | { |
275 | //System.out.println("freeA"); |
276 | restoreContextStack(); |
277 | tr.lcc = null; |
278 | tr.cm = null; |
279 | |
280 | //System.out.println("free"); |
281 | //System.out.println(Runtime.getRuntime().freeMemory()); |
282 | memoryState.setLowMemory(); |
283 | |
284 | //noMemory.printStackTrace(); |
285 | // throw Util.generateCsSQLException(SQLState.LOGIN_FAILED, noMemory.getMessage(), noMemory); |
286 | throw NO_MEM; |
287 | } |
288 | catch (Throwable t) { |
289 | throw handleException(t); |
290 | } finally { |
291 | restoreContextStack(); |
292 | } |
293 | } |
294 | |
295 | |
296 | /** |
297 | Examine the attributes set provided and determine if this is a create |
298 | boot. A boot is a create boot iff. |
299 | |
300 | <OL> |
301 | <LI>create=true - This means create a standard database. |
302 | <LI> createFrom = Path - creates database from backup if it does not exist. |
303 | <LI> restoreFrom = Path - database is restored completley from backup. |
304 | if a database exists in the same place it is replaced by the version |
305 | in the backup otherwise a new one is created using the backup copy. |
306 | <LI> rollForwardRecoveryFrom = Path - rollforward is performed |
307 | using the version backup and any active and archived log files. |
308 | </OL> |
309 | |
310 | @param p the attribute set. |
311 | |
312 | @exception SQLException Ooops. |
313 | */ |
314 | private boolean createBoot(Properties p) throws SQLException |
315 | { |
316 | int createCount = 0; |
317 | |
318 | if (Boolean.valueOf(p.getProperty(Attribute.CREATE_ATTR)).booleanValue()) |
319 | createCount++; |
320 | |
321 | int restoreCount=0; |
322 | //check if the user has specified any /create/restore/recover from backup attributes. |
323 | if (p.getProperty(Attribute.CREATE_FROM) != null) |
324 | restoreCount++; |
325 | if (p.getProperty(Attribute.RESTORE_FROM) != null) |
326 | restoreCount++; |
327 | if (p.getProperty(Attribute.ROLL_FORWARD_RECOVERY_FROM)!=null) |
328 | restoreCount++; |
329 | if(restoreCount > 1) |
330 | throw newSQLException(SQLState.CONFLICTING_RESTORE_ATTRIBUTES); |
331 | |
332 | //add the restore count to create count to make sure |
333 | //user has not specified and restore together by mistake. |
334 | createCount = createCount + restoreCount ; |
335 | |
336 | // |
337 | if (createCount > 1) throw newSQLException(SQLState.CONFLICTING_CREATE_ATTRIBUTES); |
338 | |
339 | //retuns true only for the create flag not for restore flags |
340 | return (createCount - restoreCount) == 1; |
341 | } |
342 | |
343 | /** |
344 | * Create a new connection based off of the |
345 | * connection passed in. Initializes state |
346 | * based on input connection, and copies |
347 | * appropriate object pointers. This is only used |
348 | for nested connections. |
349 | * |
350 | * @param inputConnection the input connection |
351 | */ |
352 | public EmbedConnection(EmbedConnection inputConnection) |
353 | { |
354 | if (SanityManager.DEBUG) |
355 | { |
356 | SanityManager.ASSERT(inputConnection.active, |
357 | "trying to create a proxy for an inactive conneciton"); |
358 | } |
359 | |
360 | // Proxy connections are always autocommit false |
361 | // thus needCommit is irrelavent. |
362 | autoCommit = false; |
363 | |
364 | |
365 | /* |
366 | ** Nesting specific state we are copying from |
367 | ** the inputConnection |
368 | */ |
369 | |
370 | /* |
371 | ** Objects we are sharing across nestings |
372 | */ |
373 | // set it to null to allow it to be final. |
374 | tr = null; // a proxy connection has no direct |
375 | // pointer to the tr. Every call has to go |
376 | // thru the rootConnection's tr. |
377 | active = true; |
378 | this.rootConnection = inputConnection.rootConnection; |
379 | this.applicationConnection = this; |
380 | this.factory = inputConnection.factory; |
381 | |
382 | //if no holdability specified for the resultset, use the holability |
383 | //defined for the connection |
384 | this.connectionHoldAbility = inputConnection.connectionHoldAbility; |
385 | |
386 | //RESOLVE: although it looks like the right |
387 | // thing to share the metadata object, if |
388 | // we do we'll get the wrong behavior on |
389 | // getCurrentConnection().getMetaData().isReadOnly() |
390 | // so don't try to be smart and uncomment the |
391 | // following. Ultimately, the metadata should |
392 | // be shared by all connections anyway. |
393 | //dbMetadata = inputConnection.dbMetadata; |
394 | } |
395 | |
396 | // |
397 | // Check passed-in user's credentials. |
398 | // |
399 | private void checkUserCredentials(String dbname, |
400 | Properties userInfo) |
401 | throws SQLException |
402 | { |
403 | if (SanityManager.DEBUG) |
404 | SanityManager.ASSERT(!isClosed(), "connection is closed"); |
405 | |
406 | // If a database name was passed-in then check user's credential |
407 | // in that database using the database's authentication service, |
408 | // otherwise check if it is a valid user in the JBMS system. |
409 | // |
410 | // NOTE: We always expect an authentication service per database |
411 | // and one at the system level. |
412 | // |
413 | AuthenticationService authenticationService = null; |
414 | |
415 | // Retrieve appropriate authentication service handle |
416 | if (dbname == null) |
417 | authenticationService = getLocalDriver().getAuthenticationService(); |
418 | else |
419 | authenticationService = getTR().getDatabase().getAuthenticationService(); |
420 | |
421 | // check that we do have a authentication service |
422 | // it is _always_ expected. |
423 | if (authenticationService == null) |
424 | { |
425 | String failedString = MessageService.getTextMessage( |
426 | (dbname == null) ? MessageId.AUTH_NO_SERVICE_FOR_SYSTEM : MessageId.AUTH_NO_SERVICE_FOR_DB); |
427 | |
428 | throw newSQLException(SQLState.LOGIN_FAILED, failedString); |
429 | } |
430 | |
431 | // Let's authenticate now |
432 | |
433 | if (!authenticationService.authenticate( |
434 | dbname, |
435 | userInfo |
436 | )) { |
437 | |
438 | throw newSQLException(SQLState.LOGIN_FAILED, MessageService.getTextMessage(MessageId.AUTH_INVALID)); |
439 | |
440 | } |
441 | } |
442 | |
443 | /** |
444 | * Gets the EngineType of the connected database. |
445 | * |
446 | * @return 0 if there is no database, the engine type otherwise. @see org.apache.derby.iapi.reference.EngineType |
447 | */ |
448 | public int getEngineType() |
449 | { |
450 | Database db = getDatabase(); |
451 | |
452 | if( null == db) |
453 | return 0; |
454 | return db.getEngineType(); |
455 | } |
456 | |
457 | /* |
458 | ** Methods from java.sql.Connection |
459 | */ |
460 | |
461 | /** |
462 | * SQL statements without parameters are normally |
463 | * executed using Statement objects. If the same SQL statement |
464 | * is executed many times, it is more efficient to use a |
465 | * PreparedStatement |
466 | * |
467 | * JDBC 2.0 |
468 | * |
469 | * Result sets created using the returned Statement will have |
470 | * forward-only type, and read-only concurrency, by default. |
471 | * |
472 | * @return a new Statement object |
473 | * @exception SQLException if a database-access error occurs. |
474 | */ |
475 | public final Statement createStatement() throws SQLException |
476 | { |
477 | return createStatement(JDBC20Translation.TYPE_FORWARD_ONLY, |
478 | JDBC20Translation.CONCUR_READ_ONLY, |
479 | connectionHoldAbility); |
480 | } |
481 | |
482 | /** |
483 | * JDBC 2.0 |
484 | * |
485 | * Same as createStatement() above, but allows the default result set |
486 | * type and result set concurrency type to be overridden. |
487 | * |
488 | * @param resultSetType a result set type, see ResultSet.TYPE_XXX |
489 | * @param resultSetConcurrency a concurrency type, see ResultSet.CONCUR_XXX |
490 | * @return a new Statement object |
491 | * @exception SQLException if a database-access error occurs. |
492 | */ |
493 | public final Statement createStatement(int resultSetType, |
494 | int resultSetConcurrency) |
495 | throws SQLException |
496 | { |
497 | return createStatement(resultSetType, resultSetConcurrency, |
498 | connectionHoldAbility); |
499 | } |
500 | |
501 | /** |
502 | * JDBC 3.0 |
503 | * |
504 | * Same as createStatement() above, but allows the default result set |
505 | * type, result set concurrency type and result set holdability type to |
506 | * be overridden. |
507 | * |
508 | * @param resultSetType a result set type, see ResultSet.TYPE_XXX |
509 | * @param resultSetConcurrency a concurrency type, see ResultSet.CONCUR_XXX |
510 | * @param resultSetHoldability a holdability type, |
511 | * ResultSet.HOLD_CURSORS_OVER_COMMIT or ResultSet.CLOSE_CURSORS_AT_COMMIT |
512 | * @return a new Statement object |
513 | * @exception SQLException if a database-access error occurs. |
514 | */ |
515 | public final Statement createStatement(int resultSetType, |
516 | int resultSetConcurrency, |
517 | int resultSetHoldability) |
518 | throws SQLException |
519 | { |
520 | checkIfClosed(); |
521 | |
522 | return factory.newEmbedStatement(this, false, |
523 | setResultSetType(resultSetType), resultSetConcurrency, |
524 | resultSetHoldability); |
525 | } |
526 | |
527 | /** |
528 | * A SQL statement with or without IN parameters can be |
529 | * pre-compiled and stored in a PreparedStatement object. This |
530 | * object can then be used to efficiently execute this statement |
531 | * multiple times. |
532 | * |
533 | * <P><B>Note:</B> This method is optimized for handling |
534 | * parametric SQL statements that benefit from precompilation. If |
535 | * the driver supports precompilation, prepareStatement will send |
536 | * the statement to the database for precompilation. Some drivers |
537 | * may not support precompilation. In this case, the statement may |
538 | * not be sent to the database until the PreparedStatement is |
539 | * executed. This has no direct affect on users; however, it does |
540 | * affect which method throws certain SQLExceptions. |
541 | * |
542 | * JDBC 2.0 |
543 | * |
544 | * Result sets created using the returned PreparedStatement will have |
545 | * forward-only type, and read-only concurrency, by default. |
546 | * |
547 | * @param sql a SQL statement that may contain one or more '?' IN |
548 | * parameter placeholders |
549 | * @return a new PreparedStatement object containing the |
550 | * pre-compiled statement |
551 | * @exception SQLException if a database-access error occurs. |
552 | */ |
553 | public final PreparedStatement prepareStatement(String sql) |
554 | throws SQLException |
555 | { |
556 | return prepareStatement(sql,JDBC20Translation.TYPE_FORWARD_ONLY, |
557 | JDBC20Translation.CONCUR_READ_ONLY, |
558 | connectionHoldAbility, |
559 | JDBC30Translation.NO_GENERATED_KEYS, |
560 | null, |
561 | null); |
562 | } |
563 | |
564 | |
565 | /** |
566 | * JDBC 2.0 |
567 | * |
568 | * Same as prepareStatement() above, but allows the default result set |
569 | * type and result set concurrency type to be overridden. |
570 | * |
571 | * @param resultSetType a result set type, see ResultSet.TYPE_XXX |
572 | * @param resultSetConcurrency a concurrency type, see ResultSet.CONCUR_XXX |
573 | * @return a new PreparedStatement object containing the |
574 | * pre-compiled SQL statement |
575 | * @exception SQLException if a database-access error occurs. |
576 | */ |
577 | public final PreparedStatement prepareStatement(String sql, int resultSetType, |
578 | int resultSetConcurrency) |
579 | throws SQLException |
580 | { |
581 | return prepareStatement(sql, |
582 | resultSetType, |
583 | resultSetConcurrency, |
584 | connectionHoldAbility, |
585 | JDBC30Translation.NO_GENERATED_KEYS, |
586 | null, |
587 | null); |
588 | } |
589 | |
590 | /** |
591 | * JDBC 3.0 |
592 | * |
593 | * Same as prepareStatement() above, but allows the default result set |
594 | * type, result set concurrency type and result set holdability |
595 | * to be overridden. |
596 | * |
597 | * @param resultSetType a result set type, see ResultSet.TYPE_XXX |
598 | * @param resultSetConcurrency a concurrency type, see ResultSet.CONCUR_XXX |
599 | * @param resultSetHoldability - one of the following ResultSet constants: |
600 | * ResultSet.HOLD_CURSORS_OVER_COMMIT or ResultSet.CLOSE_CURSORS_AT_COMMIT |
601 | * @return a new PreparedStatement object containing the |
602 | * pre-compiled SQL statement |
603 | * @exception SQLException if a database-access error occurs. |
604 | */ |
605 | public final PreparedStatement prepareStatement(String sql, int resultSetType, |
606 | int resultSetConcurrency, int resultSetHoldability) |
607 | throws SQLException |
608 | { |
609 | return prepareStatement(sql, |
610 | resultSetType, |
611 | resultSetConcurrency, |
612 | resultSetHoldability, |
613 | JDBC30Translation.NO_GENERATED_KEYS, |
614 | null, |
615 | null); |
616 | } |
617 | |
618 | |
619 | /** |
620 | * Creates a default PreparedStatement object capable of returning |
621 | * the auto-generated keys designated by the given array. This array contains |
622 | * the indexes of the columns in the target table that contain the auto-generated |
623 | * keys that should be made available. This array is ignored if the SQL statement |
624 | * is not an INSERT statement |
625 | |
626 | JDBC 3.0 |
627 | * |
628 | * |
629 | * @param sql An SQL statement that may contain one or more ? IN parameter placeholders |
630 | * @param columnIndexes An array of column indexes indicating the columns |
631 | * that should be returned from the inserted row or rows |
632 | * |
633 | * @return A new PreparedStatement object, containing the pre-compiled |
634 | * SQL statement, that will have the capability of returning auto-generated keys |
635 | * designated by the given array of column indexes |
636 | * |
637 | * @exception SQLException Feature not implemented for now. |
638 | */ |
639 | public final PreparedStatement prepareStatement( |
640 | String sql, |
641 | int[] columnIndexes) |
642 | throws SQLException |
643 | { |
644 | throw Util.notImplemented("prepareStatement(String, int[])"); |
645 | } |
646 | |
647 | /** |
648 | * Creates a default PreparedStatement object capable of returning |
649 | * the auto-generated keys designated by the given array. This array contains |
650 | * the names of the columns in the target table that contain the auto-generated |
651 | * keys that should be returned. This array is ignored if the SQL statement |
652 | * is not an INSERT statement |
653 | * |
654 | JDBC 3.0 |
655 | * |
656 | * @param sql An SQL statement that may contain one or more ? IN parameter placeholders |
657 | * @param columnNames An array of column names indicating the columns |
658 | * that should be returned from the inserted row or rows |
659 | * |
660 | * @return A new PreparedStatement object, containing the pre-compiled |
661 | * SQL statement, that will have the capability of returning auto-generated keys |
662 | * designated by the given array of column names |
663 | * |
664 | * @exception SQLException Feature not implemented for now. |
665 | */ |
666 | public final PreparedStatement prepareStatement( |
667 | String sql, |
668 | String[] columnNames) |
669 | throws SQLException |
670 | { |
671 | throw Util.notImplemented("prepareStatement(String, String[])"); |
672 | } |
673 | |
674 | /** |
675 | * Creates a default PreparedStatement object that has the capability to |
676 | * retieve auto-generated keys. The given constant tells the driver |
677 | * whether it should make auto-generated keys available for retrieval. |
678 | * This parameter is ignored if the SQL statement is not an INSERT statement. |
679 | * JDBC 3.0 |
680 | * |
681 | * @param sql A SQL statement that may contain one or more ? IN parameter placeholders |
682 | * @param autoGeneratedKeys A flag indicating whether auto-generated keys |
683 | * should be returned |
684 | * |
685 | * @return A new PreparedStatement object, containing the pre-compiled |
686 | * SQL statement, that will have the capability of returning auto-generated keys |
687 | * |
688 | * @exception SQLException Feature not implemented for now. |
689 | */ |
690 | public final PreparedStatement prepareStatement( |
691 | String sql, |
692 | int autoGeneratedKeys) |
693 | throws SQLException |
694 | { |
695 | return prepareStatement(sql, |
696 | JDBC20Translation.TYPE_FORWARD_ONLY, |
697 | JDBC20Translation.CONCUR_READ_ONLY, |
698 | connectionHoldAbility, |
699 | autoGeneratedKeys, |
700 | null, |
701 | null); |
702 | } |
703 | |
704 | private PreparedStatement prepareStatement(String sql, int resultSetType, |
705 | int resultSetConcurrency, int resultSetHoldability, |
706 | int autoGeneratedKeys, int[] columnIndexes, String[] columnNames) |
707 | throws SQLException |
708 | { |
709 | synchronized (getConnectionSynchronization()) { |
710 | setupContextStack(); |
711 | try { |
712 | return factory.newEmbedPreparedStatement(this, sql, false, |
713 | setResultSetType(resultSetType), |
714 | resultSetConcurrency, |
715 | resultSetHoldability, |
716 | autoGeneratedKeys, |
717 | columnIndexes, |
718 | columnNames); |
719 | } finally { |
720 | restoreContextStack(); |
721 | } |
722 | } |
723 | } |
724 | |
725 | /** |
726 | * A SQL stored procedure call statement is handled by creating a |
727 | * CallableStatement for it. The CallableStatement provides |
728 | * methods for setting up its IN and OUT parameters, and |
729 | * methods for executing it. |
730 | * |
731 | * <P><B>Note:</B> This method is optimized for handling stored |
732 | * procedure call statements. Some drivers may send the call |
733 | * statement to the database when the prepareCall is done; others |
734 | * may wait until the CallableStatement is executed. This has no |
735 | * direct affect on users; however, it does affect which method |
736 | * throws certain SQLExceptions. |
737 | * |
738 | * JDBC 2.0 |
739 | * |
740 | * Result sets created using the returned CallableStatement will have |
741 | * forward-only type, and read-only concurrency, by default. |
742 | * |
743 | * @param sql a SQL statement that may contain one or more '?' |
744 | * parameter placeholders. Typically this statement is a JDBC |
745 | * function call escape string. |
746 | * @return a new CallableStatement object containing the |
747 | * pre-compiled SQL statement |
748 | * @exception SQLException if a database-access error occurs. |
749 | */ |
750 | public final CallableStatement prepareCall(String sql) |
751 | throws SQLException |
752 | { |
753 | return prepareCall(sql, JDBC20Translation.TYPE_FORWARD_ONLY, |
754 | JDBC20Translation.CONCUR_READ_ONLY, |
755 | connectionHoldAbility); |
756 | } |
757 | |
758 | /** |
759 | * JDBC 2.0 |
760 | * |
761 | * Same as prepareCall() above, but allows the default result set |
762 | * type and result set concurrency type to be overridden. |
763 | * |
764 | * @param resultSetType a result set type, see ResultSet.TYPE_XXX |
765 | * @param resultSetConcurrency a concurrency type, see ResultSet.CONCUR_XXX |
766 | * @return a new CallableStatement object containing the |
767 | * pre-compiled SQL statement |
768 | * @exception SQLException if a database-access error occurs. |
769 | */ |
770 | public final CallableStatement prepareCall(String sql, int resultSetType, |
771 | int resultSetConcurrency) |
772 | throws SQLException |
773 | { |
774 | return prepareCall(sql, resultSetType, resultSetConcurrency, |
775 | connectionHoldAbility); |
776 | } |
777 | |
778 | /** |
779 | * JDBC 3.0 |
780 | * |
781 | * Same as prepareCall() above, but allows the default result set |
782 | * type, result set concurrency type and result set holdability |
783 | * to be overridden. |
784 | * |
785 | * @param resultSetType a result set type, see ResultSet.TYPE_XXX |
786 | * @param resultSetConcurrency a concurrency type, see ResultSet.CONCUR_XXX |
787 | * @param resultSetHoldability - one of the following ResultSet constants: |
788 | * ResultSet.HOLD_CURSORS_OVER_COMMIT or ResultSet.CLOSE_CURSORS_AT_COMMIT |
789 | * @return a new CallableStatement object containing the |
790 | * pre-compiled SQL statement |
791 | * @exception SQLException if a database-access error occurs. |
792 | */ |
793 | public final CallableStatement prepareCall(String sql, int resultSetType, |
794 | int resultSetConcurrency, int resultSetHoldability) |
795 | throws SQLException |
796 | { |
797 | checkIfClosed(); |
798 | |
799 | synchronized (getConnectionSynchronization()) |
800 | { |
801 | setupContextStack(); |
802 | try |
803 | { |
804 | return factory.newEmbedCallableStatement(this, sql, |
805 | setResultSetType(resultSetType), |
806 | resultSetConcurrency, |
807 | resultSetHoldability); |
808 | } |
809 | finally |
810 | { |
811 | restoreContextStack(); |
812 | } |
813 | } |
814 | } |
815 | |
816 | /** |
817 | * A driver may convert the JDBC sql grammar into its system's |
818 | * native SQL grammar prior to sending it; nativeSQL returns the |
819 | * native form of the statement that the driver would have sent. |
820 | * |
821 | * @param sql a SQL statement that may contain one or more '?' |
822 | * parameter placeholders |
823 | * @return the native form of this statement |
824 | */ |
825 | public String nativeSQL(String sql) throws SQLException { |
826 | checkIfClosed(); |
827 | // we don't massage the strings at all, so this is easy: |
828 | return sql; |
829 | } |
830 | |
831 | /** |
832 | * If a connection is in auto-commit mode, then all its SQL |
833 | * statements will be executed and committed as individual |
834 | * transactions. Otherwise, its SQL statements are grouped into |
835 | * transactions that are terminated by either commit() or |
836 | * rollback(). By default, new connections are in auto-commit |
837 | * mode. |
838 | * |
839 | * The commit occurs when the statement completes or the next |
840 | * execute occurs, whichever comes first. In the case of |
841 | * statements returning a ResultSet, the statement completes when |
842 | * the last row of the ResultSet has been retrieved or the |
843 | * ResultSet has been closed. In advanced cases, a single |
844 | * statement may return multiple results as well as output |
845 | * parameter values. Here the commit occurs when all results and |
846 | * output param values have been retrieved. |
847 | * |
848 | * @param autoCommit true enables auto-commit; false disables |
849 | * auto-commit. |
850 | * @exception SQLException if a database-access error occurs. |
851 | */ |
852 | public void setAutoCommit(boolean autoCommit) throws SQLException { |
853 | checkIfClosed(); |
854 | |
855 | // Is this a nested connection |
856 | if (rootConnection != this) { |
857 | if (autoCommit) |
858 | throw newSQLException(SQLState.NO_AUTO_COMMIT_ON); |
859 | } |
860 | |
861 | if (this.autoCommit != autoCommit) |
862 | commit(); |
863 | |
864 | this.autoCommit = autoCommit; |
865 | } |
866 | |
867 | /** |
868 | * Get the current auto-commit state. |
869 | * |
870 | * @return Current state of auto-commit mode. |
871 | * @see #setAutoCommit |
872 | */ |
873 | public boolean getAutoCommit() throws SQLException { |
874 | checkIfClosed(); |
875 | return autoCommit; |
876 | } |
877 | |
878 | /** |
879 | * Commit makes all changes made since the previous |
880 | * commit/rollback permanent and releases any database locks |
881 | * currently held by the Connection. This method should only be |
882 | * used when auto commit has been disabled. |
883 | * |
884 | * @exception SQLException if a database-access error occurs. |
885 | * @see #setAutoCommit |
886 | */ |
887 | public void commit() throws SQLException { |
888 | synchronized (getConnectionSynchronization()) |
889 | { |
890 | /* |
891 | ** Note that the context stack is |
892 | ** needed even for rollback & commit |
893 | */ |
894 | setupContextStack(); |
895 | |
896 | try |
897 | { |
898 | getTR().commit(); |
899 | } |
900 | catch (Throwable t) |
901 | { |
902 | throw handleException(t); |
903 | } |
904 | finally |
905 | { |
906 | restoreContextStack(); |
907 | } |
908 | |
909 | needCommit = false; |
910 | } |
911 | } |
912 | |
913 | /** |
914 | * Rollback drops all changes made since the previous |
915 | * commit/rollback and releases any database locks currently held |
916 | * by the Connection. This method should only be used when auto |
917 | * commit has been disabled. |
918 | * |
919 | * @exception SQLException if a database-access error occurs. |
920 | * @see #setAutoCommit |
921 | */ |
922 | public void rollback() throws SQLException { |
923 | |
924 | synchronized (getConnectionSynchronization()) |
925 | { |
926 | /* |
927 | ** Note that the context stack is |
928 | ** needed even for rollback & commit |
929 | */ |
930 | setupContextStack(); |
931 | try |
932 | { |
933 | getTR().rollback(); |
934 | } catch (Throwable t) { |
935 | throw handleException(t); |
936 | } |
937 | finally |
938 | { |
939 | restoreContextStack(); |
940 | } |
941 | needCommit = false; |
942 | } |
943 | } |
944 | |
945 | /** |
946 | * In some cases, it is desirable to immediately release a |
947 | * Connection's database and JDBC resources instead of waiting for |
948 | * them to be automatically released; the close method provides this |
949 | * immediate release. |
950 | * |
951 | * <P><B>Note:</B> A Connection is automatically closed when it is |
952 | * garbage collected. Certain fatal errors also result in a closed |
953 | * Connection. |
954 | * |
955 | * @exception SQLException if a database-access error occurs. |
956 | */ |
957 | public void close() throws SQLException { |
958 | // JDK 1.4 javadoc indicates close on a closed connection is a no-op |
959 | if (isClosed()) |
960 | return; |
961 | |
962 | |
963 | if (rootConnection == this) |
964 | { |
965 | /* Throw error to match DB2/JDBC if a tran is pending in non-autocommit mode */ |
966 | if (!autoCommit && !transactionIsIdle()) { |
967 | throw newSQLException(SQLState.LANG_INVALID_TRANSACTION_STATE); |
968 | } |
969 | |
970 | close(exceptionClose); |
971 | } |
972 | else |
973 | setInactive(); // nested connection |
974 | } |
975 | |
976 | // This inner close takes the exception and calls |
977 | // the context manager to make the connection close. |
978 | // The exception must be a session severity exception. |
979 | // |
980 | // NOTE: This method is not part of JDBC specs. |
981 | // |
982 | private void close(StandardException e) throws SQLException { |
983 | |
984 | synchronized(getConnectionSynchronization()) |
985 | { |
986 | if (rootConnection == this) |
987 | { |
988 | /* |
989 | * If it isn't active, it's already been closed. |
990 | */ |
991 | if (active) { |
992 | setupContextStack(); |
993 | try { |
994 | tr.rollback(); |
995 | |
996 | // Let go of lcc reference so it can be GC'ed after |
997 | // cleanupOnError, the tr will stay around until the |
998 | // rootConnection itself is GC'ed, which is dependent |
999 | // on how long the client program wants to hold on to |
1000 | // the Connection object. |
1001 | tr.clearLcc(); |
1002 | tr.cleanupOnError(e); |
1003 | |
1004 | } catch (Throwable t) { |
1005 | throw handleException(t); |
1006 | } finally { |
1007 | restoreContextStack(); |
1008 | } |
1009 | } |
1010 | } |
1011 | |
1012 | if (!isClosed()) |
1013 | setInactive(); |
1014 | } |
1015 | } |
1016 | |
1017 | /** |
1018 | * Tests to see if a Connection is closed. |
1019 | * |
1020 | * @return true if the connection is closed; false if it's still open |
1021 | */ |
1022 | public final boolean isClosed() { |
1023 | if (active) { |
1024 | |
1025 | // I am attached, check the database state |
1026 | if (getTR().isActive()) { |
1027 | return false; |
1028 | } |
1029 | |
1030 | setInactive(); |
1031 | |
1032 | } |
1033 | return true; |
1034 | } |
1035 | |
1036 | /** |
1037 | * A Connection's database is able to provide information |
1038 | * describing its tables, its supported SQL grammar, its stored |
1039 | * procedures, the capabilities of this connection, etc. This |
1040 | * information is made available through a DatabaseMetaData |
1041 | * object. |
1042 | * |
1043 | * @return a DatabaseMetaData object for this Connection |
1044 | * @exception SQLException if a database-access error occurs. |
1045 | */ |
1046 | public DatabaseMetaData getMetaData() throws SQLException { |
1047 | checkIfClosed(); |
1048 | |
1049 | if (dbMetadata == null) { |
1050 | |
1051 | // There is a case where dbname can be null. |
1052 | // Replication client of this method does not have a |
1053 | // JDBC connection; therefore dbname is null and this |
1054 | // is expected. |
1055 | // |
1056 | dbMetadata = factory.newEmbedDatabaseMetaData(this, getTR().getUrl()); |
1057 | } |
1058 | return dbMetadata; |
1059 | } |
1060 | |
1061 | /** |
1062 | JDBC 3.0 |
1063 | * Retrieves the current holdability of ResultSet objects created using this |
1064 | * Connection object. |
1065 | * |
1066 | * |
1067 | * @return The holdability, one of ResultSet.HOLD_CURSORS_OVER_COMMIT |
1068 | * or ResultSet.CLOSE_CURSORS_AT_COMMIT |
1069 | * |
1070 | */ |
1071 | public final int getHoldability() throws SQLException { |
1072 | checkIfClosed(); |
1073 | return connectionHoldAbility; |
1074 | } |
1075 | |
1076 | /** |
1077 | JDBC 3.0 |
1078 | * Changes the holdability of ResultSet objects created using this |
1079 | * Connection object to the given holdability. |
1080 | * |
1081 | * |
1082 | * @param holdability A ResultSet holdability constant, one of ResultSet.HOLD_CURSORS_OVER_COMMIT |
1083 | * or ResultSet.CLOSE_CURSORS_AT_COMMIT |
1084 | * |
1085 | */ |
1086 | public final void setHoldability(int holdability) throws SQLException { |
1087 | checkIfClosed(); |
1088 | connectionHoldAbility = holdability; |
1089 | } |
1090 | |
1091 | /** |
1092 | * You can put a connection in read-only mode as a hint to enable |
1093 | * database optimizations. |
1094 | * |
1095 | * <P><B>Note:</B> setReadOnly cannot be called while in the |
1096 | * middle of a transaction. |
1097 | * |
1098 | * @param readOnly true enables read-only mode; false disables |
1099 | * read-only mode. |
1100 | * @exception SQLException if a database-access error occurs. |
1101 | */ |
1102 | public final void setReadOnly(boolean readOnly) throws SQLException |
1103 | { |
1104 | synchronized(getConnectionSynchronization()) |
1105 | { |
1106 | setupContextStack(); |
1107 | try { |
1108 | getLanguageConnection().setReadOnly(readOnly); |
1109 | } catch (StandardException e) { |
1110 | throw handleException(e); |
1111 | } finally { |
1112 | restoreContextStack(); |
1113 | } |
1114 | } |
1115 | } |
1116 | |
1117 | /** |
1118 | * Tests to see if the connection is in read-only mode. |
1119 | * |
1120 | * @return true if connection is read-only |
1121 | * @exception SQLException if a database-access error occurs. |
1122 | */ |
1123 | public final boolean isReadOnly() throws SQLException |
1124 | { |
1125 | checkIfClosed(); |
1126 | return getLanguageConnection().isReadOnly(); |
1127 | } |
1128 | |
1129 | /** |
1130 | * A sub-space of this Connection's database may be selected by setting a |
1131 | * catalog name. If the driver does not support catalogs it will |
1132 | * silently ignore this request. |
1133 | * |
1134 | * @exception SQLException if a database-access error occurs. |
1135 | */ |
1136 | public void setCatalog(String catalog) throws SQLException { |
1137 | checkIfClosed(); |
1138 | // silently ignoring this request like the javadoc said. |
1139 | return; |
1140 | } |
1141 | |
1142 | /** |
1143 | * Return the Connection's current catalog name. |
1144 | * |
1145 | * @return the current catalog name or null |
1146 | * @exception SQLException if a database-access error occurs. |
1147 | */ |
1148 | public String getCatalog() throws SQLException { |
1149 | checkIfClosed(); |
1150 | // we do not have support for Catalog, just return null as |
1151 | // the JDBC specs mentions then. |
1152 | return null; |
1153 | } |
1154 | |
1155 | /** |
1156 | * You can call this method to try to change the transaction |
1157 | * isolation level using one of the TRANSACTION_* values. |
1158 | * |
1159 | * <P><B>Note:</B> setTransactionIsolation causes the current |
1160 | * transaction to commit |
1161 | * |
1162 | * @param level one of the TRANSACTION_* isolation values with the |
1163 | * exception of TRANSACTION_NONE; some databases may not support |
1164 | * other values |
1165 | * @exception SQLException if a database-access error occurs. |
1166 | * @see DatabaseMetaData#supportsTransactionIsolationLevel |
1167 | */ |
1168 | public void setTransactionIsolation(int level) throws SQLException { |
1169 | |
1170 | if (level == getTransactionIsolation()) |
1171 | return; |
1172 | |
1173 | // Convert the isolation level to the internal one |
1174 | int iLevel; |
1175 | switch (level) |
1176 | { |
1177 | case java.sql.Connection.TRANSACTION_READ_UNCOMMITTED: |
1178 | iLevel = ExecutionContext.READ_UNCOMMITTED_ISOLATION_LEVEL; |
1179 | break; |
1180 | |
1181 | case java.sql.Connection.TRANSACTION_READ_COMMITTED: |
1182 | iLevel = ExecutionContext.READ_COMMITTED_ISOLATION_LEVEL; |
1183 | break; |
1184 | |
1185 | case java.sql.Connection.TRANSACTION_REPEATABLE_READ: |
1186 | iLevel = ExecutionContext.REPEATABLE_READ_ISOLATION_LEVEL; |
1187 | break; |
1188 | |
1189 | case java.sql.Connection.TRANSACTION_SERIALIZABLE: |
1190 | iLevel = ExecutionContext.SERIALIZABLE_ISOLATION_LEVEL; |
1191 | break; |
1192 | default: |
1193 | throw newSQLException(SQLState.UNIMPLEMENTED_ISOLATION_LEVEL, new Integer(level)); |
1194 | } |
1195 | |
1196 | synchronized(getConnectionSynchronization()) |
1197 | { |
1198 | setupContextStack(); |
1199 | try { |
1200 | getLanguageConnection().setIsolationLevel(iLevel); |
1201 | } catch (StandardException e) { |
1202 | throw handleException(e); |
1203 | } finally { |
1204 | restoreContextStack(); |
1205 | } |
1206 | } |
1207 | } |
1208 | |
1209 | |
1210 | /** |
1211 | * Get this Connection's current transaction isolation mode. |
1212 | * |
1213 | * @return the current TRANSACTION_* mode value |
1214 | * @exception SQLException if a database-access error occurs. |
1215 | */ |
1216 | public final int getTransactionIsolation() throws SQLException { |
1217 | checkIfClosed(); |
1218 | return ExecutionContext.CS_TO_JDBC_ISOLATION_LEVEL_MAP[getLanguageConnection().getCurrentIsolationLevel()]; |
1219 | } |
1220 | |
1221 | /** |
1222 | * The first warning reported by calls on this Connection is |
1223 | * returned. |
1224 | * |
1225 | * <P><B>Note:</B> Subsequent warnings will be chained to this |
1226 | * SQLWarning. |
1227 | * |
1228 | * @return the first SQLWarning or null |
1229 | * |
1230 | * Synchronization note: Warnings are synchronized |
1231 | * on nesting level |
1232 | */ |
1233 | public final synchronized SQLWarning getWarnings() throws SQLException { |
1234 | checkIfClosed(); |
1235 | return topWarning; |
1236 | } |
1237 | |
1238 | /** |
1239 | * After this call, getWarnings returns null until a new warning is |
1240 | * reported for this Connection. |
1241 | * |
1242 | * Synchronization node: Warnings are synchonized |
1243 | * on nesting level |
1244 | */ |
1245 | public final synchronized void clearWarnings() throws SQLException { |
1246 | checkIfClosed(); |
1247 | topWarning = null; |
1248 | } |
1249 | |
1250 | ///////////////////////////////////////////////////////////////////////// |
1251 | // |
1252 | // JDBC 2.0 - New public methods |
1253 | // |
1254 | ///////////////////////////////////////////////////////////////////////// |
1255 | |
1256 | /** |
1257 | * |
1258 | * Get the type-map object associated with this connection. |
1259 | * By default, the map returned is empty. |
1260 | * JDBC 2.0 - java.util.Map requires JDK 1 |
1261 | * |
1262 | */ |
1263 | public java.util.Map getTypeMap() throws SQLException { |
1264 | checkIfClosed(); |
1265 | // just return an immuntable empty map |
1266 | return java.util.Collections.EMPTY_MAP; |
1267 | } |
1268 | |
1269 | /** |
1270 | * Install a type-map object as the default type-map for |
1271 | * this connection. |
1272 | * JDBC 2.0 - java.util.Map requires JDK 1 |
1273 | * |
1274 | * @exception SQLException Feature not implemented for now. |
1275 | */ |
1276 | public final void setTypeMap(java.util.Map map) throws SQLException { |
1277 | checkIfClosed(); |
1278 | if( map == null) |
1279 | throw Util.generateCsSQLException(SQLState.INVALID_API_PARAMETER,map,"map", |
1280 | "java.sql.Connection.setTypeMap"); |
1281 | if(!(map.isEmpty())) |
1282 | throw Util.notImplemented(); |
1283 | } |
1284 | |
1285 | ///////////////////////////////////////////////////////////////////////// |
1286 | // |
1287 | // Implementation specific methods |
1288 | // |
1289 | ///////////////////////////////////////////////////////////////////////// |
1290 | |
1291 | /** |
1292 | Add a warning to the current list of warnings, to follow |
1293 | this note from Connection.getWarnings. |
1294 | Note: Subsequent warnings will be chained to this SQLWarning. |
1295 | |
1296 | @see java.sql.Connection#getWarnings |
1297 | */ |
1298 | public final synchronized void addWarning(SQLWarning newWarning) { |
1299 | if (topWarning == null) { |
1300 | topWarning = newWarning; |
1301 | return; |
1302 | } |
1303 | |
1304 | topWarning.setNextWarning(newWarning); |
1305 | } |
1306 | |
1307 | /** |
1308 | * Return the dbname for this connection. |
1309 | * |
1310 | * @return String The dbname for this connection. |
1311 | */ |
1312 | public String getDBName() |
1313 | { |
1314 | if (SanityManager.DEBUG) |
1315 | SanityManager.ASSERT(!isClosed(), "connection is closed"); |
1316 | |
1317 | return getTR().getDBName(); |
1318 | } |
1319 | |
1320 | public final LanguageConnectionContext getLanguageConnection() { |
1321 | |
1322 | if (SanityManager.DEBUG) |
1323 | SanityManager.ASSERT(!isClosed(), "connection is closed"); |
1324 | |
1325 | return getTR().getLcc(); |
1326 | } |
1327 | |
1328 | /** |
1329 | * Raises an exception if the connection is closed. |
1330 | * |
1331 | * @exception SQLException if the connection is closed |
1332 | */ |
1333 | protected final void checkIfClosed() throws SQLException { |
1334 | if (isClosed()) { |
1335 | throw Util.noCurrentConnection(); |
1336 | } |
1337 | } |
1338 | |
1339 | //EmbedConnection30 overrides this method so it can release the savepoints array if |
1340 | //the exception severity is transaction level |
1341 | SQLException handleException(Throwable thrownException) |
1342 | throws SQLException |
1343 | { |
1344 | /* |
1345 | ** By default, rollback the connection on if autocommit |
1346 | ** is on. |
1347 | */ |
1348 | return getTR().handleException(thrownException, |
1349 | autoCommit, |
1350 | true // Rollback xact on auto commit |
1351 | ); |
1352 | } |
1353 | |
1354 | /** |
1355 | Handle any type of Exception. |
1356 | <UL> |
1357 | <LI> Inform the contexts of the error |
1358 | <LI> Throw an Util based upon the thrown exception. |
1359 | </UL> |
1360 | |
1361 | REMIND: now that we know all the exceptions from our driver |
1362 | are Utils, would it make sense to shut down the system |
1363 | for unknown SQLExceptions? At present, we do not. |
1364 | |
1365 | Because this is the last stop for exceptions, |
1366 | it will catch anything that occurs in it and try |
1367 | to cleanup before re-throwing them. |
1368 | |
1369 | @param thrownException the exception |
1370 | @param rollbackOnAutoCommit rollback the xact on if autocommit is |
1371 | on, otherwise rollback stmt but leave xact open (and |
1372 | continue to hold on to locks). Most of the time, this |
1373 | will be true, excepting operations on result sets, like |
1374 | getInt(). |
1375 | */ |
1376 | final SQLException handleException(Throwable thrownException, |
1377 | boolean rollbackOnAutoCommit) |
1378 | throws SQLException |
1379 | { |
1380 | return getTR().handleException(thrownException, autoCommit, |
1381 | rollbackOnAutoCommit); |
1382 | |
1383 | } |
1384 | |
1385 | /* |
1386 | This is called from the EmbedConnectionContext to |
1387 | close on errors. We assume all handling of the connectin |
1388 | is dealt with via the context stack, and our only role |
1389 | is to mark ourself as closed. |
1390 | */ |
1391 | |
1392 | /** |
1393 | Close the connection when processing errors, or when |
1394 | closing a nested connection. |
1395 | <p> |
1396 | This only marks it as closed and frees up its resources; |
1397 | any closing of the underlying connection or commit work |
1398 | is assumed to be done elsewhere. |
1399 | |
1400 | Called from EmbedConnectionContext's cleanup routine, |
1401 | and by proxy.close(). |
1402 | */ |
1403 | |
1404 | public final void setInactive() { |
1405 | |
1406 | if (active == false) |
1407 | return; |
1408 | // active = false |
1409 | // tr = null !-> active = false |
1410 | |
1411 | synchronized (getConnectionSynchronization()) { |
1412 | active = false; |
1413 | // tr = null; cleanupOnerror sets inactive but still needs tr to |
1414 | // restore context later |
1415 | dbMetadata = null; |
1416 | } |
1417 | } |
1418 | |
1419 | /** |
1420 | @exception Throwable standard error policy |
1421 | */ |
1422 | protected void finalize() throws Throwable |
1423 | { |
1424 | if (rootConnection == this) |
1425 | { |
1426 | super.finalize(); |
1427 | if (!isClosed()) |
1428 | close(exceptionClose); |
1429 | } |
1430 | } |
1431 | |
1432 | /** |
1433 | * if auto commit is on, remember that we need to commit |
1434 | * the current statement. |
1435 | */ |
1436 | protected void needCommit() { |
1437 | if (!needCommit) needCommit = true; |
1438 | } |
1439 | |
1440 | /** |
1441 | * if a commit is needed, perform it. |
1442 | * |
1443 | * Must have connection synchonization and context set up already. |
1444 | * |
1445 | * @exception SQLException if commit returns error |
1446 | */ |
1447 | protected void commitIfNeeded() throws SQLException |
1448 | { |
1449 | if (autoCommit && needCommit) |
1450 | { |
1451 | try |
1452 | { |
1453 | getTR().commit(); |
1454 | } |
1455 | catch (Throwable t) |
1456 | { |
1457 | throw handleException(t); |
1458 | } |
1459 | needCommit = false; |
1460 | } |
1461 | } |
1462 | |
1463 | /** |
1464 | * If in autocommit, then commit. |
1465 | * |
1466 | * Used to force a commit after a result set closes in autocommit mode. |
1467 | * The needCommit mechanism does not work correctly as there are times |
1468 | * with cursors (like a commit, followed by a next, followed by a close) |
1469 | * where the system does not think it needs a commit but we need to |
1470 | * force the commit on close. It seemed safer to just force a commit |
1471 | * on close rather than count on keeping the needCommit flag correct for |
1472 | * all cursor cases. |
1473 | * |
1474 | * Must have connection synchonization and context set up already. |
1475 | * |
1476 | * @exception SQLException if commit returns error |
1477 | */ |
1478 | protected void commitIfAutoCommit() throws SQLException |
1479 | { |
1480 | if (autoCommit) |
1481 | { |
1482 | try |
1483 | { |
1484 | getTR().commit(); |
1485 | } |
1486 | catch (Throwable t) |
1487 | { |
1488 | throw handleException(t); |
1489 | } |
1490 | needCommit = false; |
1491 | } |
1492 | } |
1493 | |
1494 | |
1495 | final protected Object getConnectionSynchronization() |
1496 | { |
1497 | return rootConnection; |
1498 | } |
1499 | |
1500 | /** |
1501 | Install the context manager for this thread. Check connection status here. |
1502 | @exception SQLException if fails |
1503 | */ |
1504 | protected final void setupContextStack() throws SQLException { |
1505 | |
1506 | /* |
1507 | Track this entry, then throw an exception |
1508 | rather than doing the quiet return. Need the |
1509 | track before the throw because the backtrack |
1510 | is in a finally block. |
1511 | */ |
1512 | |
1513 | checkIfClosed(); |
1514 | |
1515 | getTR().setupContextStack(); |
1516 | |
1517 | } |
1518 | |
1519 | protected final void restoreContextStack() throws SQLException { |
1520 | |
1521 | if (SanityManager.DEBUG) |
1522 | Util.ASSERT(this, (active) || getTR().getCsf() !=null, "No context service to do restore"); |
1523 | |
1524 | TransactionResourceImpl tr = getTR(); |
1525 | |
1526 | //REMIND: someone is leaving an incorrect manager on when they |
1527 | // are exiting the system in the nested case. |
1528 | if (SanityManager.DEBUG) |
1529 | { |
1530 | if ((tr.getCsf() != null) && (tr.getCsf().getCurrentContextManager() != |
1531 | tr.getContextManager())) |
1532 | { |
1533 | Util.THROWASSERT(this, |
1534 | "Current Context Manager not the one was expected: " + |
1535 | tr.getCsf().getCurrentContextManager() + " " + |
1536 | tr.getContextManager()); |
1537 | } |
1538 | } |
1539 | |
1540 | tr.restoreContextStack(); |
1541 | } |
1542 | |
1543 | /* |
1544 | ** Create database methods. |
1545 | */ |
1546 | |
1547 | /** |
1548 | Create a new database. |
1549 | @param dbname the database name |
1550 | @param info the properties |
1551 | |
1552 | @return Database The newly created database or null. |
1553 | |
1554 | @exception SQLException if fails to create database |
1555 | */ |
1556 | |
1557 | private Database createDatabase(String dbname, Properties info) |
1558 | throws SQLException { |
1559 | |
1560 | info = filterProperties(info); |
1561 | |
1562 | try { |
1563 | if (Monitor.createPersistentService(Property.DATABASE_MODULE, dbname, info) == null) |
1564 | { |
1565 | // service already exists, create a warning |
1566 | addWarning(EmbedSQLWarning.newEmbedSQLWarning(SQLState.DATABASE_EXISTS, dbname)); |
1567 | } |
1568 | } catch (StandardException mse) { |
1569 | |
1570 | SQLException se = newSQLException(SQLState.CREATE_DATABASE_FAILED, dbname); |
1571 | se.setNextException(handleException(mse)); |
1572 | throw se; |
1573 | } |
1574 | |
1575 | // clear these values as some modules hang onto |
1576 | // the properties set corresponding to service.properties |
1577 | // and they shouldn't be interested in these JDBC attributes. |
1578 | info.clear(); |
1579 | |
1580 | return (Database) Monitor.findService(Property.DATABASE_MODULE, dbname); |
1581 | } |
1582 | |
1583 | |
1584 | /** |
1585 | Return false iff the monitor cannot handle a service |
1586 | of the type indicated by the protocol within the name. |
1587 | If that's the case then we are the wrong driver. |
1588 | |
1589 | Throw exception if anything else is wrong. |
1590 | */ |
1591 | |
1592 | private boolean bootDatabase(Properties info) throws Throwable |
1593 | { |
1594 | String dbname = tr.getDBName(); |
1595 | |
1596 | // boot database now |
1597 | try { |
1598 | |
1599 | info = filterProperties(info); |
1600 | |
1601 | // try to start the service if it doesn't already exist |
1602 | if (!Monitor.startPersistentService(dbname, info)) { |
1603 | // a false indicates the monitor cannot handle a service |
1604 | // of the type indicated by the protocol within the name. |
1605 | // If that's the case then we are the wrong driver |
1606 | // so just return null. |
1607 | return false; |
1608 | } |
1609 | |
1610 | // clear these values as some modules hang onto |
1611 | // the properties set corresponding to service.properties |
1612 | // and they shouldn't be interested in these JDBC attributes. |
1613 | info.clear(); |
1614 | |
1615 | Database database = (Database) Monitor.findService(Property.DATABASE_MODULE, dbname); |
1616 | tr.setDatabase(database); |
1617 | |
1618 | } catch (StandardException mse) { |
1619 | SQLException se = newSQLException(SQLState.BOOT_DATABASE_FAILED, dbname); |
1620 | |
1621 | Throwable ne = mse.getNestedException(); |
1622 | SQLException nse; |
1623 | |
1624 | /* |
1625 | If there is a next exception, assume |
1626 | that the first one is just a redundant "see the |
1627 | next exception" message. |
1628 | if it is a BEI, treat it as a database exception. |
1629 | If there isn't a BEI, treat it as a java exception. |
1630 | |
1631 | In general we probably want to walk the chain |
1632 | and return all of them, but empirically, this |
1633 | is all we need to do for now. |
1634 | */ |
1635 | if (ne instanceof StandardException) |
1636 | nse = Util.generateCsSQLException((StandardException)ne); |
1637 | else if (ne != null) |
1638 | nse = Util.javaException(ne); |
1639 | else |
1640 | nse = Util.generateCsSQLException(mse); |
1641 | |
1642 | se.setNextException(nse); |
1643 | throw se; |
1644 | } |
1645 | |
1646 | // If database exists, getDatabase() will return the database object. |
1647 | // If any error occured while booting an existing database, an |
1648 | // exception would have been thrown already. |
1649 | return true; |
1650 | |
1651 | } |
1652 | |
1653 | /* |
1654 | * Class interface methods used by database metadata to ensure |
1655 | * good relations with autocommit. |
1656 | */ |
1657 | |
1658 | PreparedStatement prepareMetaDataStatement(String sql) |
1659 | throws SQLException { |
1660 | synchronized (getConnectionSynchronization()) { |
1661 | setupContextStack(); |
1662 | PreparedStatement s = null; |
1663 | try { |
1664 | s = factory.newEmbedPreparedStatement(this, sql, true, |
1665 | JDBC20Translation.TYPE_FORWARD_ONLY, |
1666 | JDBC20Translation.CONCUR_READ_ONLY, |
1667 | connectionHoldAbility, |
1668 | JDBC30Translation.NO_GENERATED_KEYS, |
1669 | null, |
1670 | null); |
1671 | } finally { |
1672 | restoreContextStack(); |
1673 | } |
1674 | return s; |
1675 | } |
1676 | } |
1677 | |
1678 | public final InternalDriver getLocalDriver() |
1679 | { |
1680 | if (SanityManager.DEBUG) |
1681 | SanityManager.ASSERT(!isClosed(), "connection is closed"); |
1682 | |
1683 | return getTR().getDriver(); |
1684 | } |
1685 | |
1686 | /** |
1687 | Return the context manager for this connection. |
1688 | */ |
1689 | public final ContextManager getContextManager() { |
1690 | |
1691 | if (SanityManager.DEBUG) |
1692 | SanityManager.ASSERT(!isClosed(), "connection is closed"); |
1693 | |
1694 | return getTR().getContextManager(); |
1695 | } |
1696 | |
1697 | /** |
1698 | * Filter out properties from the passed in set of JDBC attributes |
1699 | * to remove any derby.* properties. This is to ensure that setting |
1700 | * derby.* properties does not work this way, it's not a defined way |
1701 | * to set such properties and could be a secuirty hole in allowing |
1702 | * remote connections to override system, application or database settings. |
1703 | * |
1704 | * @return a new Properties set copied from the parameter but with no |
1705 | * derby.* properties. |
1706 | */ |
1707 | private Properties filterProperties(Properties inputSet) { |
1708 | Properties limited = new Properties(); |
1709 | |
1710 | // filter out any derby.* properties, only |
1711 | // JDBC attributes can be set this way |
1712 | for (java.util.Enumeration e = inputSet.propertyNames(); e.hasMoreElements(); ) { |
1713 | |
1714 | String key = (String) e.nextElement(); |
1715 | |
1716 | // we don't allow properties to be set this way |
1717 | if (key.startsWith("derby.")) |
1718 | continue; |
1719 | limited.put(key, inputSet.getProperty(key)); |
1720 | } |
1721 | return limited; |
1722 | } |
1723 | |
1724 | /* |
1725 | ** methods to be overridden by subimplementations wishing to insert |
1726 | ** their classes into the mix. |
1727 | */ |
1728 | |
1729 | protected Database getDatabase() |
1730 | { |
1731 | if (SanityManager.DEBUG) |
1732 | SanityManager.ASSERT(!isClosed(), "connection is closed"); |
1733 | |
1734 | return getTR().getDatabase(); |
1735 | } |
1736 | |
1737 | final protected TransactionResourceImpl getTR() |
1738 | { |
1739 | return rootConnection.tr; |
1740 | } |
1741 | |
1742 | private EmbedConnectionContext pushConnectionContext(ContextManager cm) { |
1743 | return new EmbedConnectionContext(cm, this); |
1744 | } |
1745 | |
1746 | public final void setApplicationConnection(java.sql.Connection applicationConnection) { |
1747 | this.applicationConnection = applicationConnection; |
1748 | } |
1749 | |
1750 | public final java.sql.Connection getApplicationConnection() { |
1751 | return applicationConnection; |
1752 | } |
1753 | |
1754 | public void setDrdaID(String drdaID) { |
1755 | getLanguageConnection().setDrdaID(drdaID); |
1756 | } |
1757 | |
1758 | /** |
1759 | Reset the connection before it is returned from a PooledConnection |
1760 | to a new application request (wrapped by a BrokeredConnection). |
1761 | Examples of reset covered here is dropping session temporary tables |
1762 | and reseting IDENTITY_VAL_LOCAL. |
1763 | Most JDBC level reset is handled by calling standard java.sql.Connection |
1764 | methods from EmbedPooledConnection. |
1765 | */ |
1766 | public void resetFromPool() throws SQLException { |
1767 | synchronized (getConnectionSynchronization()) |
1768 | { |
1769 | setupContextStack(); |
1770 | try { |
1771 | getLanguageConnection().resetFromPool(); |
1772 | } catch (StandardException t) { |
1773 | throw handleException(t); |
1774 | } |
1775 | finally |
1776 | { |
1777 | restoreContextStack(); |
1778 | } |
1779 | } |
1780 | } |
1781 | |
1782 | /* |
1783 | ** methods to be overridden by subimplementations wishing to insert |
1784 | ** their classes into the mix. |
1785 | ** The reason we need to override them is because we want to create a |
1786 | ** Local20/LocalStatment object (etc) rather than a Local/LocalStatment |
1787 | ** object (etc). |
1788 | */ |
1789 | |
1790 | |
1791 | /* |
1792 | ** XA support |
1793 | */ |
1794 | |
1795 | public final int xa_prepare() throws SQLException { |
1796 | |
1797 | synchronized (getConnectionSynchronization()) |
1798 | { |
1799 | setupContextStack(); |
1800 | try |
1801 | { |
1802 | XATransactionController tc = |
1803 | (XATransactionController) getLanguageConnection().getTransactionExecute(); |
1804 | |
1805 | int ret = tc.xa_prepare(); |
1806 | |
1807 | if (ret == XATransactionController.XA_RDONLY) |
1808 | { |
1809 | // On a prepare call, xa allows an optimization that if the |
1810 | // transaction is read only, the RM can just go ahead and |
1811 | // commit it. So if store returns this read only status - |
1812 | // meaning store has taken the liberty to commit already - we |
1813 | // needs to turn around and call internalCommit (without |
1814 | // committing the store again) to make sure the state is |
1815 | // consistent. Since the transaction is read only, there is |
1816 | // probably not much that needs to be done. |
1817 | |
1818 | getLanguageConnection().internalCommit(false /* don't commitStore again */); |
1819 | } |
1820 | return ret; |
1821 | } catch (StandardException t) |
1822 | { |
1823 | throw handleException(t); |
1824 | } |
1825 | finally |
1826 | { |
1827 | restoreContextStack(); |
1828 | } |
1829 | } |
1830 | } |
1831 | |
1832 | |
1833 | public final void xa_commit(boolean onePhase) throws SQLException { |
1834 | |
1835 | synchronized (getConnectionSynchronization()) |
1836 | { |
1837 | setupContextStack(); |
1838 | try |
1839 | { |
1840 | getLanguageConnection().xaCommit(onePhase); |
1841 | } catch (StandardException t) |
1842 | { |
1843 | throw handleException(t); |
1844 | } |
1845 | finally |
1846 | { |
1847 | restoreContextStack(); |
1848 | } |
1849 | } |
1850 | } |
1851 | public final void xa_rollback() throws SQLException { |
1852 | |
1853 | synchronized (getConnectionSynchronization()) |
1854 | { |
1855 | setupContextStack(); |
1856 | try |
1857 | { |
1858 | getLanguageConnection().xaRollback(); |
1859 | } catch (StandardException t) |
1860 | { |
1861 | throw handleException(t); |
1862 | } |
1863 | finally |
1864 | { |
1865 | restoreContextStack(); |
1866 | } |
1867 | } |
1868 | } |
1869 | /** |
1870 | * returns false if there is an underlying transaction and that transaction |
1871 | * has done work. True if there is no underlying transaction or that |
1872 | * underlying transaction is idle |
1873 | */ |
1874 | public final boolean transactionIsIdle() |
1875 | { |
1876 | return getTR().isIdle(); |
1877 | } |
1878 | private int setResultSetType(int resultSetType) { |
1879 | |
1880 | /* Add warning if scroll sensitive cursor |
1881 | * and downgrade to scroll insensitive cursor. |
1882 | */ |
1883 | if (resultSetType == JDBC20Translation.TYPE_SCROLL_SENSITIVE) |
1884 | { |
1885 | addWarning(EmbedSQLWarning.newEmbedSQLWarning(SQLState.NO_SCROLL_SENSITIVE_CURSORS)); |
1886 | resultSetType = JDBC20Translation.TYPE_SCROLL_INSENSITIVE; |
1887 | } |
1888 | return resultSetType; |
1889 | } |
1890 | |
1891 | |
1892 | /** |
1893 | * Set the transaction isolation level that will be used for the |
1894 | * next prepare. Used by network server to implement DB2 style |
1895 | * isolation levels. |
1896 | * @param level Isolation level to change to. level is the DB2 level |
1897 | * specified in the package names which happen to correspond |
1898 | * to our internal levels. If |
1899 | * level == ExecutionContext.UNSPECIFIED_ISOLATION, |
1900 | * the statement won't be prepared with an isolation level. |
1901 | * |
1902 | * |
1903 | */ |
1904 | public void setPrepareIsolation(int level) throws SQLException |
1905 | { |
1906 | if (level == getPrepareIsolation()) |
1907 | return; |
1908 | |
1909 | switch (level) |
1910 | { |
1911 | case ExecutionContext.READ_UNCOMMITTED_ISOLATION_LEVEL: |
1912 | case ExecutionContext.REPEATABLE_READ_ISOLATION_LEVEL: |
1913 | case ExecutionContext.READ_COMMITTED_ISOLATION_LEVEL: |
1914 | case ExecutionContext.SERIALIZABLE_ISOLATION_LEVEL: |
1915 | case ExecutionContext.UNSPECIFIED_ISOLATION_LEVEL: |
1916 | break; |
1917 | default: |
1918 | throw Util.generateCsSQLException( |
1919 | SQLState.UNIMPLEMENTED_ISOLATION_LEVEL, new Integer(level)); |
1920 | } |
1921 | |
1922 | synchronized(getConnectionSynchronization()) |
1923 | { |
1924 | getLanguageConnection().setPrepareIsolationLevel(level); |
1925 | } |
1926 | } |
1927 | |
1928 | /** |
1929 | * Return prepare isolation |
1930 | */ |
1931 | public int getPrepareIsolation() |
1932 | { |
1933 | return getLanguageConnection().getPrepareIsolationLevel(); |
1934 | } |
1935 | |
1936 | /** |
1937 | Return a unique order number for a result set. |
1938 | A unique value is only needed if the result set is |
1939 | being created within procedure and thus must be using |
1940 | a nested connection. |
1941 | */ |
1942 | final int getResultSetOrderId() { |
1943 | |
1944 | if (this == rootConnection) { |
1945 | return 0; |
1946 | } else { |
1947 | return rootConnection.resultSetId++; |
1948 | } |
1949 | } |
1950 | |
1951 | protected SQLException newSQLException(String messageId) { |
1952 | return Util.generateCsSQLException(messageId); |
1953 | } |
1954 | protected SQLException newSQLException(String messageId, Object arg1) { |
1955 | return Util.generateCsSQLException(messageId, arg1); |
1956 | } |
1957 | protected SQLException newSQLException(String messageId, Object arg1, Object arg2) { |
1958 | return Util.generateCsSQLException(messageId, arg1, arg2); |
1959 | } |
1960 | |
1961 | ///////////////////////////////////////////////////////////////////////// |
1962 | // |
1963 | // OBJECT OVERLOADS |
1964 | // |
1965 | ///////////////////////////////////////////////////////////////////////// |
1966 | |
1967 | /** |
1968 | * Get a String representation that uniquely identifies |
1969 | * this connection. Include the same information that is |
1970 | * printed in the log for various trace and error messages. |
1971 | * |
1972 | * In Derby the "physical" connection is a LanguageConnectionContext, |
1973 | * or LCC. |
1974 | * The JDBC Connection is an JDBC-specific layer on top of this. Rather |
1975 | * than create a new id here, we simply use the id of the underlying LCC. |
1976 | * Note that this is a big aid in debugging, because much of the |
1977 | * engine trace and log code prints the LCC id. |
1978 | * |
1979 | * @return a string representation for this connection |
1980 | */ |
1981 | public String toString() |
1982 | { |
1983 | if ( connString == null ) |
1984 | { |
1985 | |
1986 | LanguageConnectionContext lcc = getLanguageConnection(); |
1987 | |
1988 | connString = |
1989 | this.getClass().getName() + "@" + this.hashCode() + " " + |
1990 | lcc.xidStr + |
1991 | lcc.getTransactionExecute().getTransactionIdString() + |
1992 | "), " + |
1993 | lcc.lccStr + |
1994 | Integer.toString(lcc.getInstanceNumber()) + "), " + |
1995 | lcc.dbnameStr + lcc.getDbname() + "), " + |
1996 | lcc.drdaStr + lcc.getDrdaID() + ") "; |
1997 | } |
1998 | |
1999 | return connString; |
2000 | } |
2001 | |
2002 | |
2003 | } |