KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > impl > sql > conn > GenericLanguageConnectionContext


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.conn.GenericLanguageConnectionContext
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to you under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20  */

21
22 package org.apache.derby.impl.sql.conn;
23
24 import org.apache.derby.iapi.services.context.ContextImpl;
25 import org.apache.derby.iapi.services.cache.CacheManager;
26
27 import org.apache.derby.impl.sql.compile.CompilerContextImpl;
28 import org.apache.derby.impl.sql.execute.InternalTriggerExecutionContext;
29 import org.apache.derby.impl.sql.execute.AutoincrementCounter;
30 import org.apache.derby.impl.sql.GenericPreparedStatement;
31 import org.apache.derby.impl.sql.GenericStatement;
32 import org.apache.derby.iapi.sql.Statement;
33 import org.apache.derby.impl.sql.conn.CachedStatement;
34
35 import org.apache.derby.iapi.services.property.PropertyUtil;
36 import org.apache.derby.iapi.services.context.Context;
37 import org.apache.derby.iapi.services.context.ContextManager;
38 import org.apache.derby.iapi.services.monitor.Monitor;
39 import org.apache.derby.iapi.services.sanity.SanityManager;
40 import org.apache.derby.iapi.services.stream.HeaderPrintWriter;
41 import org.apache.derby.iapi.services.loader.GeneratedClass;
42 import org.apache.derby.iapi.services.cache.Cacheable;
43 import org.apache.derby.iapi.db.Database;
44 import org.apache.derby.iapi.error.StandardException;
45 import org.apache.derby.iapi.sql.compile.CompilerContext;
46 import org.apache.derby.iapi.sql.compile.OptimizerFactory;
47 import org.apache.derby.iapi.sql.conn.Authorizer;
48 import org.apache.derby.iapi.error.ExceptionSeverity;
49 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
50 import org.apache.derby.iapi.sql.conn.LanguageConnectionFactory;
51 import org.apache.derby.iapi.sql.conn.StatementContext;
52 import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
53 import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptorList;
54 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
55 import org.apache.derby.iapi.sql.dictionary.DataDictionaryContext;
56 import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
57 import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
58 import org.apache.derby.iapi.types.DataValueFactory;
59 import org.apache.derby.iapi.sql.compile.TypeCompilerFactory;
60 import org.apache.derby.iapi.sql.depend.DependencyManager;
61 import org.apache.derby.iapi.sql.depend.Provider;
62 import org.apache.derby.iapi.reference.SQLState;
63 import org.apache.derby.iapi.reference.Limits;
64 import org.apache.derby.iapi.sql.execute.ConstantAction;
65 import org.apache.derby.iapi.sql.execute.CursorActivation;
66 import org.apache.derby.iapi.sql.execute.ExecPreparedStatement;
67 import org.apache.derby.iapi.sql.execute.ExecutionContext;
68 import org.apache.derby.iapi.sql.execute.ExecutionStmtValidator;
69 import org.apache.derby.iapi.sql.Activation;
70 import org.apache.derby.iapi.sql.LanguageFactory;
71 import org.apache.derby.iapi.sql.PreparedStatement;
72 import org.apache.derby.iapi.sql.ResultSet;
73 import org.apache.derby.iapi.sql.ParameterValueSet;
74
75 import org.apache.derby.iapi.store.access.TransactionController;
76 import org.apache.derby.iapi.store.access.AccessFactory;
77 import org.apache.derby.iapi.store.access.XATransactionController;
78 import org.apache.derby.iapi.util.IdUtil;
79 import org.apache.derby.iapi.util.StringUtil;
80
81 import org.apache.derby.catalog.UUID;
82 import org.apache.derby.iapi.sql.execute.RunTimeStatistics;
83 import org.apache.derby.iapi.db.TriggerExecutionContext;
84 import org.apache.derby.iapi.reference.Property;
85
86 import java.util.List JavaDoc;
87 import java.util.ArrayList JavaDoc;
88 import java.util.Enumeration JavaDoc;
89 import java.util.Hashtable JavaDoc;
90 import java.util.Properties JavaDoc;
91 import java.util.Vector JavaDoc;
92 import java.util.Stack JavaDoc;
93 import java.io.Serializable JavaDoc;
94
95 /**
96  * LanguageConnectionContext keeps the pool of prepared statements,
97  * activations, and cursors in use by the current connection.
98  * <p>
99  * The generic impl does not provide statement caching.
100  *
101  * @author ames
102  *
103  */

104 public class GenericLanguageConnectionContext
105     extends ContextImpl
106     implements LanguageConnectionContext
107 {
108
109     // make sure these are not zeros
110
private final static int NON_XA = 0;
111     private final static int XA_ONE_PHASE = 1;
112     private final static int XA_TWO_PHASE = 2;
113
114     /*
115         fields
116      */

117
118     private final Vector JavaDoc acts;
119     private volatile boolean unusedActs=false;
120     protected int bindCount;
121     private boolean ddWriteMode;
122     private boolean runTimeStatisticsSetting ;
123     private boolean statisticsTiming;
124
125     //all the temporary tables declared for this connection
126
private ArrayList JavaDoc allDeclaredGlobalTempTables;
127     //The currentSavepointLevel is used to provide the rollback behavior of temporary tables.
128
//At any point, this variable has the total number of savepoints defined for the transaction.
129
private int currentSavepointLevel = 0;
130
131     protected long nextCursorId;
132
133     protected int nextSavepointId;
134
135     private RunTimeStatistics runTimeStatisticsObject;
136     private StringBuffer JavaDoc sb;
137
138     private Database db;
139
140     private final int instanceNumber;
141     private String JavaDoc drdaID;
142     private String JavaDoc dbname;
143
144     private int identifierCasing = UNKNOWN_CASING;
145     
146     /**
147     The transaction to use within this language connection context. It may
148     be more appropriate to have it in a separate context (LanguageTransactionContext?).
149     REVISIT (nat): I shoehorned the transaction context that
150     the language uses into this class. The main purpose is so
151     that the various language code can find out what its
152     transaction is.
153     **/

154     protected TransactionController tran;
155
156     /**
157      * If non-null indicates that a nested user transaction is in progress.
158      */

159     protected TransactionController childTransaction;
160     
161     /**
162      * queryNestingDepth is a counter used to keep track of how many calls
163      * have been made to begin nested transactions. Only the first call
164      * actually starts a Nested User Transaction with the store. Subsequent
165      * calls simply increment this counter. commitNestedTransaction only
166      * decrements the counter and when it drops to 0 actually commits the
167      * nested user transaction.
168      */

169     protected int queryNestingDepth;
170
171     protected DataValueFactory dataFactory;
172     protected LanguageFactory langFactory;
173     protected TypeCompilerFactory tcf;
174     protected OptimizerFactory of;
175     protected LanguageConnectionFactory connFactory;
176     
177     /*
178      * A statement context is "pushed" and "popped" at the beginning and
179      * end of every statement so that only that statement is cleaned up
180      * on a Statement Exception. As a performance optimization, we only push
181      * the outermost statement context once, and never pop it. Also, we
182      * save off a 2nd StatementContext for speeding server side method
183      * invocation, though we still push and pop it as needed. All other
184      * statement contexts will allocated and pushed and popped on demand.
185      */

186     private final StatementContext[] statementContexts = new StatementContext[2];
187     private int statementDepth;
188     protected int outermostTrigger = -1;
189
190     protected Authorizer authorizer;
191     protected String JavaDoc userName = null; //The name the user connects with.
192
//May still be quoted.
193

194     protected SchemaDescriptor sd;
195
196     // RESOLVE - How do we want to set the default.
197
private int defaultIsolationLevel = ExecutionContext.READ_COMMITTED_ISOLATION_LEVEL;
198     protected int isolationLevel = defaultIsolationLevel;
199
200     private boolean isolationLevelExplicitlySet = false;
201     // Isolation level can be changed using JDBC api Connection.setTransactionIsolation
202
// or it can be changed using SQL "set current isolation = NEWLEVEL".
203
//
204
// In XA transactions, BrokeredConnection keeps isolation state information.
205
// When isolation is changed in XA transaction using JDBC, that state gets
206
// correctly set in BrokeredConnection.setTransactionIsolation method. But
207
// when SQL is used to set the isolation level, the code path is different
208
// and it does not go through BrokeredConnection's setTransactionIsolation
209
// method and hence the state is not maintained correctly when coming through
210
// SQL. To get around this, I am adding following flag which will get set
211
// everytime the isolation level is set using JDBC or SQL. This flag will be
212
// checked at global transaction start and end time. If the flag is set to true
213
// then BrokeredConnection's isolation level state will be brought upto date
214
// with Real Connection's isolation level and this flag will be set to false
215
// after that.
216
private boolean isolationLevelSetUsingSQLorJDBC = false;
217
218     // isolation level to when preparing statements.
219
// if unspecified, the statement won't be prepared with a specific
220
// scan isolationlevel
221
protected int prepareIsolationLevel = ExecutionContext.UNSPECIFIED_ISOLATION_LEVEL;
222
223     // Whether or not to write executing statement info to db2j.log
224
private boolean logStatementText;
225     private boolean logQueryPlan;
226     private HeaderPrintWriter istream;
227
228     // this used to be computed in OptimizerFactoryContextImpl; i.e everytime a
229
// connection was made. To keep the semantics same I'm putting it out here
230
// instead of in the OptimizerFactory which is only initialized when the
231
// database is booted.
232
private int lockEscalationThreshold;
233
234     private Vector JavaDoc stmtValidators;
235     private Vector JavaDoc triggerExecutionContexts;
236     private Vector JavaDoc triggerTables;
237
238     protected AccessFactory af;
239
240     // OptimizerTrace
241
private boolean optimizerTrace;
242     private boolean optimizerTraceHtml;
243     private String JavaDoc lastOptimizerTraceOutput;
244     private String JavaDoc optimizerTraceOutput;
245
246     //// Support for AUTOINCREMENT
247

248     /**
249      * To support lastAutoincrementValue: This is a hashtable which maps
250      * schemaName,tableName,columnName to a Long value.
251      */

252     private Hashtable JavaDoc autoincrementHT;
253     /**
254      * whether to allow updates or not.
255      */

256     private boolean autoincrementUpdate;
257     private long identityVal; //support IDENTITY_VAL_LOCAL function
258
private boolean identityNotNull; //frugal programmer
259

260     // cache of ai being handled in memory (bulk insert + alter table).
261
private Hashtable JavaDoc autoincrementCacheHashtable;
262
263     // temp public
264
public CacheManager statementCache;
265
266     /*
267        constructor
268     */

269     public GenericLanguageConnectionContext
270     (
271      ContextManager cm,
272      TransactionController tranCtrl,
273
274      LanguageFactory lf,
275      LanguageConnectionFactory lcf,
276      Database db,
277      String JavaDoc userName,
278      int instanceNumber,
279      String JavaDoc drdaID,
280      String JavaDoc dbname)
281          throws StandardException
282     {
283         super(cm, org.apache.derby.iapi.reference.ContextId.LANG_CONNECTION);
284         acts = new Vector JavaDoc();
285         tran = tranCtrl;
286
287         dataFactory = lcf.getDataValueFactory();
288         tcf = lcf.getTypeCompilerFactory();
289         of = lcf.getOptimizerFactory();
290         langFactory = lf;
291         connFactory = lcf;
292         this.db = db;
293         this.userName = userName;
294         this.instanceNumber = instanceNumber;
295         this.drdaID = drdaID;
296         this.dbname = dbname;
297
298         /* Find out whether or not to log info on executing statements to error log
299          */

300         String JavaDoc logStatementProperty = PropertyUtil.getServiceProperty(getTransactionCompile(),
301                     "derby.language.logStatementText");
302         logStatementText = Boolean.valueOf(logStatementProperty).booleanValue();
303
304         String JavaDoc logQueryPlanProperty = PropertyUtil.getServiceProperty(getTransactionCompile(),
305                     "derby.language.logQueryPlan");
306         logQueryPlan = Boolean.valueOf(logQueryPlanProperty).booleanValue();
307
308         setRunTimeStatisticsMode(logQueryPlan);
309
310         lockEscalationThreshold =
311             PropertyUtil.getServiceInt(tranCtrl,
312                                        Property.LOCKS_ESCALATION_THRESHOLD,
313                                        Property.MIN_LOCKS_ESCALATION_THRESHOLD,
314                                        Integer.MAX_VALUE,
315                                        Property.DEFAULT_LOCKS_ESCALATION_THRESHOLD);
316         stmtValidators = new Vector JavaDoc();
317         triggerExecutionContexts = new Vector JavaDoc();
318         triggerTables = new Vector JavaDoc();
319         
320         af = lcf.getAccessFactory();
321         statementCache = lcf.getStatementCache();
322     }
323
324     public void initialize(boolean sqlConnection) throws StandardException
325     {
326         //
327
//Creating the authorizer authorizes the connection.
328
authorizer = new GenericAuthorizer(IdUtil.getUserAuthorizationId(userName),this, sqlConnection);
329
330         //we can ignore the following if this is a database connection
331
//associated with internal thread such as logSniffer and StageTrunc
332
if(!sqlConnection)
333             return;
334
335         /*
336         ** Set the authorization id. User shouldn't
337         ** be null or else we are going to blow up trying
338         ** to create a schema for this user.
339         */

340         if (SanityManager.DEBUG)
341         {
342             if (getAuthorizationId() == null)
343             {
344                 SanityManager.THROWASSERT("User name is null," +
345                     " check the connection manager to make sure it is set" +
346                     " reasonably");
347             }
348         }
349
350
351         setDefaultSchema(initDefaultSchemaDescriptor());
352     }
353
354     protected SchemaDescriptor initDefaultSchemaDescriptor()
355         throws StandardException {
356         /*
357         ** - If the database supports schemas and a schema with the
358         ** same name as the user's name exists (has been created using
359         ** create schema already) the database will set the users
360         ** default schema to the the schema with the same name as the
361         ** user.
362         ** - Else Set the default schema to APP.
363         */

364         // SchemaDescriptor sd;
365

366         DataDictionary dd = getDataDictionary();
367         String JavaDoc authorizationId = getAuthorizationId();
368     
369         if ( (sd = dd.getSchemaDescriptor(authorizationId, getTransactionCompile(), false)) == null )
370         {
371             sd = new SchemaDescriptor(dd, authorizationId, authorizationId, (UUID) null, false);
372         }
373         return sd;
374     }
375
376     //
377
// LanguageConnectionContext interface
378
//
379
/**
380      * @see LanguageConnectionContext#getLogStatementText
381      */

382     public boolean getLogStatementText()
383     {
384         return logStatementText;
385     }
386
387     /**
388      * @see LanguageConnectionContext#setLogStatementText
389      */

390     public void setLogStatementText(boolean logStatementText)
391     {
392         this.logStatementText = logStatementText;
393     }
394
395     /**
396      * @see LanguageConnectionContext#getLogQueryPlan
397      */

398     public boolean getLogQueryPlan()
399     {
400         return logQueryPlan;
401     }
402
403     /**
404      * @see LanguageConnectionContext#usesSqlAuthorization
405      */

406     public boolean usesSqlAuthorization()
407     {
408         return getDataDictionary().usesSqlAuthorization();
409     }
410
411     /**
412      * get the lock escalation threshold.
413      */

414     public int getLockEscalationThreshold()
415     {
416         return lockEscalationThreshold;
417     }
418
419     /*
420         The methods that follow are for consistency checking purposes
421      */

422
423     public int getCacheSize() {
424         if (statementCache != null)
425             return statementCache.getNumberInUse();
426         else
427             return 0;
428     }
429
430     /**
431      * Add the activation to those known about by this connection.
432      */

433     public void addActivation(Activation a)
434         throws StandardException {
435         acts.addElement(a);
436
437         // DERBY-418. Activations which are marked unused,
438
// are closed here. Activations Vector is iterated
439
// to identify and close unused activations, only if
440
// unusedActs flag is set to true and if the total
441
// size exceeds 20.
442
if( (unusedActs) && (acts.size() > 20) ) {
443             unusedActs = false;
444             for (int i = acts.size() - 1; i >= 0; i--) {
445
446                 // it maybe the case that a Activation's reset() ends up
447
// closing one or more activation leaving our index beyond
448
// the end of the array
449
if (i >= acts.size())
450                     continue;
451
452                 Activation a1 = (Activation) acts.elementAt(i);
453                 if (!a1.isInUse()) {
454                     a1.close();
455                 }
456             }
457         }
458
459         if (SanityManager.DEBUG) {
460
461             if (SanityManager.DEBUG_ON("memoryLeakTrace")) {
462
463                 if (acts.size() > 20)
464                     System.out.println("memoryLeakTrace:GenericLanguageContext:activations " + acts.size());
465             }
466         }
467     }
468
469     /**
470      * Make a note that some activations are marked unused
471      */

472     public void notifyUnusedActivation() {
473         unusedActs = true;
474     }
475
476     /**
477      * @see LanguageConnectionContext#checkIfAnyDeclaredGlobalTempTablesForThisConnection
478      */

479     public boolean checkIfAnyDeclaredGlobalTempTablesForThisConnection() {
480         return (allDeclaredGlobalTempTables == null ? false : true);
481     }
482
483     /**
484      * @see LanguageConnectionContext#addDeclaredGlobalTempTable
485      */

486     public void addDeclaredGlobalTempTable(TableDescriptor td)
487         throws StandardException {
488
489         if (findDeclaredGlobalTempTable(td.getName()) != null) //if table already declared, throw an exception
490
{
491             throw
492                 StandardException.newException(
493                                                SQLState.LANG_OBJECT_ALREADY_EXISTS_IN_OBJECT,
494                                                "Declared global temporary table",
495                                                td.getName(),
496                                                "Schema",
497                                                SchemaDescriptor.STD_DECLARED_GLOBAL_TEMPORARY_TABLES_SCHEMA_NAME);
498         }
499
500         //save all the information about temp table in this special class
501
TempTableInfo tempTableInfo = new TempTableInfo(td, currentSavepointLevel);
502
503         if (allDeclaredGlobalTempTables == null)
504             allDeclaredGlobalTempTables = new ArrayList JavaDoc();
505
506         allDeclaredGlobalTempTables.add(tempTableInfo);
507     }
508
509     /**
510      * @see LanguageConnectionContext#dropDeclaredGlobalTempTable
511      */

512     public boolean dropDeclaredGlobalTempTable(String JavaDoc tableName) {
513     TempTableInfo tempTableInfo = findDeclaredGlobalTempTable(tableName);
514         if (tempTableInfo != null)
515         {
516             if (SanityManager.DEBUG)
517                 if (tempTableInfo.getDeclaredInSavepointLevel() > currentSavepointLevel)
518                     SanityManager.THROWASSERT("declared in savepoint level can not be higher than the current savepoint level");
519
520             //following checks if the table was declared in the current unit of work.
521
if (tempTableInfo.getDeclaredInSavepointLevel() == currentSavepointLevel)
522             {
523                 //since the table was declared in this unit of work,
524
//the drop table method should remove it from the valid list of temp table for this unit of work
525
allDeclaredGlobalTempTables.remove(allDeclaredGlobalTempTables.indexOf(tempTableInfo));
526                 if (allDeclaredGlobalTempTables.size() == 0)
527                     allDeclaredGlobalTempTables = null;
528             }
529             else
530             {
531                 //since the table was not declared in this unit of work, the drop table method will just mark the table as dropped
532
//in the current unit of work. This information will be used at rollback time.
533
tempTableInfo.setDroppedInSavepointLevel(currentSavepointLevel);
534             }
535             return true;
536         } else
537             return false;
538     }
539
540     /**
541      * After a release of a savepoint, we need to go through our temp tables list. If there are tables with their declare or drop
542      * or modified in savepoint levels set to savepoint levels higher than the current savepoint level, then we should change them
543      * to the current savepoint level
544      */

545     private void tempTablesReleaseSavepointLevels() {
546     //unlike rollback, here we check for dropped in / declared in / modified in savepoint levels > current savepoint level only.
547
//This is because the temp tables with their savepoint levels same as currentSavepointLevel have correct value assigned to them and
548
//do not need to be changed and hence no need to check for >=
549
for (int i = 0; i < allDeclaredGlobalTempTables.size(); i++) {
550             TempTableInfo tempTableInfo = (TempTableInfo)allDeclaredGlobalTempTables.get(i);
551             if (tempTableInfo.getDroppedInSavepointLevel() > currentSavepointLevel)
552                 tempTableInfo.setDroppedInSavepointLevel(currentSavepointLevel);
553
554             if (tempTableInfo.getDeclaredInSavepointLevel() > currentSavepointLevel)
555                 tempTableInfo.setDeclaredInSavepointLevel(currentSavepointLevel);
556
557             if (tempTableInfo.getModifiedInSavepointLevel() > currentSavepointLevel)
558                 tempTableInfo.setModifiedInSavepointLevel(currentSavepointLevel);
559         }
560     }
561
562     /**
563      * do the necessary work at commit time for temporary tables
564      * 1)If a temporary table was marked as dropped in this transaction, then remove it from the list of temp tables for this connection
565      * 2)If a temporary table was not dropped in this transaction, then mark it's declared savepoint level and modified savepoint level as -1
566      */

567     private void tempTablesAndCommit() {
568         for (int i = allDeclaredGlobalTempTables.size()-1; i >= 0; i--) {
569             TempTableInfo tempTableInfo = (TempTableInfo)allDeclaredGlobalTempTables.get(i);
570             if (tempTableInfo.getDroppedInSavepointLevel() != -1)
571             {
572                 //this means table was dropped in this unit of work and hence should be removed from valid list of temp tables
573
allDeclaredGlobalTempTables.remove(i);
574             } else //this table was not dropped in this unit of work, hence set its declaredInSavepointLevel as -1 and also mark it as not modified
575
{
576                 tempTableInfo.setDeclaredInSavepointLevel(-1);
577                 tempTableInfo.setModifiedInSavepointLevel(-1);
578             }
579         }
580     }
581
582     /**
583         Reset the connection before it is returned (indirectly) by
584         a PooledConnection object. See EmbeddedConnection.
585      */

586     public void resetFromPool()
587          throws StandardException
588     {
589         // Reset IDENTITY_VAL_LOCAL
590
identityNotNull = false;
591
592         // drop all temp tables.
593
dropAllDeclaredGlobalTempTables();
594     }
595
596     /**
597      * Drop all the declared global temporary tables associated with this connection. This gets called
598      * when a getConnection() is done on a PooledConnection. This will ensure all the temporary tables
599      * declared on earlier connection handle associated with this physical database connection are dropped
600      * before a new connection handle is issued on that same physical database connection.
601      */

602     private void dropAllDeclaredGlobalTempTables() throws StandardException {
603         if (allDeclaredGlobalTempTables == null)
604             return;
605     
606         DependencyManager dm = getDataDictionary().getDependencyManager();
607         StandardException topLevelStandardException = null;
608
609         //collect all the exceptions we might receive while dropping the temporary tables and throw them as one chained exception at the end.
610
for (int i = 0; i < allDeclaredGlobalTempTables.size(); i++) {
611             try {
612                 TempTableInfo tempTableInfo = (TempTableInfo)allDeclaredGlobalTempTables.get(i);
613                 TableDescriptor td = tempTableInfo.getTableDescriptor();
614                 //the following 2 lines of code has been copied from DropTableConstantAction. If there are any changes made there in future,
615
//we should check if they need to be made here too.
616
dm.invalidateFor(td, DependencyManager.DROP_TABLE, this);
617                 tran.dropConglomerate(td.getHeapConglomerateId());
618             } catch (StandardException e) {
619                 e.setNestedException(topLevelStandardException);
620                 topLevelStandardException = e;
621             }
622         }
623     
624         allDeclaredGlobalTempTables = null;
625         try {
626             internalCommit(true);
627         } catch (StandardException e) {
628             e.setNestedException(topLevelStandardException);
629             topLevelStandardException = e;
630         }
631         if (topLevelStandardException != null) throw topLevelStandardException;
632     }
633
634     //do the necessary work at rollback time for temporary tables
635
/**
636      * do the necessary work at rollback time for temporary tables
637      * 1)If a temp table was declared in the UOW, then drop it and remove it from list of temporary tables.
638      * 2)If a temp table was declared and dropped in the UOW, then remove it from list of temporary tables.
639      * 3)If an existing temp table was dropped in the UOW, then recreate it with no data.
640      * 4)If an existing temp table was modified in the UOW, then get rid of all the rows from the table.
641      */

642     private void tempTablesAndRollback()
643         throws StandardException {
644         for (int i = allDeclaredGlobalTempTables.size()-1; i >= 0; i--) {
645             TempTableInfo tempTableInfo = (TempTableInfo)allDeclaredGlobalTempTables.get(i);
646             if (tempTableInfo.getDeclaredInSavepointLevel() >= currentSavepointLevel)
647             {
648                 if (tempTableInfo.getDroppedInSavepointLevel() == -1)
649                 {
650                     //the table was declared but not dropped in the unit of work getting rolled back and hence we will remove
651
//it from valid list of temporary tables and drop the conglomerate associated with it
652
TableDescriptor td = tempTableInfo.getTableDescriptor();
653                     tran.dropConglomerate(td.getHeapConglomerateId()); //remove the conglomerate created for this temp table
654
allDeclaredGlobalTempTables.remove(i); //remove it from the list of temp tables
655
} else if (tempTableInfo.getDroppedInSavepointLevel() >= currentSavepointLevel)
656                 {
657                     //the table was declared and dropped in the unit of work getting rolled back
658
allDeclaredGlobalTempTables.remove(i);
659                 }
660             } else if (tempTableInfo.getDroppedInSavepointLevel() >= currentSavepointLevel) //this means the table was declared in an earlier savepoint unit / transaction and then dropped in current UOW
661
{
662                 //restore the old definition of temp table because drop is being rolledback
663
TableDescriptor td = tempTableInfo.getTableDescriptor();
664                 td = cleanupTempTableOnCommitOrRollback(td, false);
665                 //In order to store the old conglomerate information for the temp table, we need to replace the
666
//existing table descriptor with the old table descriptor which has the old conglomerate information
667
tempTableInfo.setTableDescriptor(td);
668                 tempTableInfo.setDroppedInSavepointLevel(-1);
669                 //following will mark the table as not modified. This is because the table data has been deleted as part of the current rollback
670
tempTableInfo.setModifiedInSavepointLevel(-1);
671                 allDeclaredGlobalTempTables.set(i, tempTableInfo);
672             } else if (tempTableInfo.getModifiedInSavepointLevel() >= currentSavepointLevel) //this means the table was declared in an earlier savepoint unit / transaction and modified in current UOW
673
{
674                 //following will mark the table as not modified. This is because the table data will be deleted as part of the current rollback
675
tempTableInfo.setModifiedInSavepointLevel(-1);
676                 TableDescriptor td = tempTableInfo.getTableDescriptor();
677                 getDataDictionary().getDependencyManager().invalidateFor(td, DependencyManager.DROP_TABLE, this);
678                 cleanupTempTableOnCommitOrRollback(td, true);
679             } // there is no else here because there is no special processing required for temp tables declares in earlier work of unit/transaction and not modified
680
}
681     
682         if (allDeclaredGlobalTempTables.size() == 0)
683             allDeclaredGlobalTempTables = null;
684     }
685
686     /**
687      * This is called at the commit time for temporary tables with ON COMMIT DELETE ROWS
688      * If a temp table with ON COMMIT DELETE ROWS doesn't have any held cursor open on them, we delete the data from
689      * them by dropping the conglomerate and recreating the conglomerate. In order to store the new conglomerate
690      * information for the temp table, we need to replace the existing table descriptor with the new table descriptor
691      * which has the new conglomerate information
692      * @param tableName Temporary table name whose table descriptor is getting changed
693      * @param td New table descriptor for the temporary table
694      */

695     private void replaceDeclaredGlobalTempTable(String JavaDoc tableName, TableDescriptor td) {
696     TempTableInfo tempTableInfo = findDeclaredGlobalTempTable(tableName);
697         tempTableInfo.setDroppedInSavepointLevel(-1);
698         tempTableInfo.setDeclaredInSavepointLevel(-1);
699         tempTableInfo.setTableDescriptor(td);
700         allDeclaredGlobalTempTables.set(allDeclaredGlobalTempTables.indexOf(tempTableInfo), tempTableInfo);
701   }
702
703     /**
704      * @see LanguageConnectionContext#getTableDescriptorForDeclaredGlobalTempTable
705      */

706     public TableDescriptor getTableDescriptorForDeclaredGlobalTempTable(String JavaDoc tableName) {
707     TempTableInfo tempTableInfo = findDeclaredGlobalTempTable(tableName);
708         if (tempTableInfo == null)
709             return null;
710         else
711             return tempTableInfo.getTableDescriptor();
712     }
713
714     /**
715      * Find the declared global temporary table in the list of temporary tables known by this connection.
716      * @param tableName look for this table name in the saved list
717      * @return data structure defining the temporary table if found. Else, return null
718      *
719      */

720     private TempTableInfo findDeclaredGlobalTempTable(String JavaDoc tableName) {
721         if (allDeclaredGlobalTempTables == null)
722             return null;
723
724         for (int i = 0; i < allDeclaredGlobalTempTables.size(); i++) {
725             if (((TempTableInfo)allDeclaredGlobalTempTables.get(i)).matches(tableName))
726                 return (TempTableInfo)allDeclaredGlobalTempTables.get(i);
727         }
728         return null;
729     }
730
731     /**
732      * @see LanguageConnectionContext#markTempTableAsModifiedInUnitOfWork
733      */

734     public void markTempTableAsModifiedInUnitOfWork(String JavaDoc tableName) {
735     TempTableInfo tempTableInfo = findDeclaredGlobalTempTable(tableName);
736     tempTableInfo.setModifiedInSavepointLevel(currentSavepointLevel);
737     }
738
739         /**
740      * @see LanguageConnectionContext#prepareInternalStatement
741      */

742         public PreparedStatement prepareInternalStatement(SchemaDescriptor compilationSchema, String JavaDoc sqlText, boolean isForReadOnly, boolean forMetaData)
743         throws StandardException
744         {
745         return connFactory.getStatement(compilationSchema, sqlText, isForReadOnly).prepare(this, forMetaData);
746         }
747
748         /**
749          * @see LanguageConnectionContext#prepareInternalStatement
750          */

751         public PreparedStatement prepareInternalStatement(String JavaDoc sqlText)
752         throws StandardException
753         {
754             return connFactory.getStatement(sd, sqlText, true).prepare(this);
755         }
756
757     /**
758      * Remove the activation to those known about by this connection.
759      *
760      */

761     public void removeActivation(Activation a)
762     {
763         if (SanityManager.DEBUG) {
764             SanityManager.ASSERT(a.isClosed(), "Activation is not closed");
765         }
766
767         acts.removeElement(a);
768
769         int capacity = acts.capacity();
770
771         if (capacity > 20 && (capacity > 2 * acts.size())) {
772             acts.trimToSize();
773         }
774     }
775
776     /**
777      * Return the number of activations known for this connection.
778      * Note that some of these activations may not be in use
779      * (when a prepared statement is finalized, its activations
780      * are marked as unused and later closed and removed on
781      * the next commit/rollback).
782      */

783     public int getActivationCount() {
784         return acts.size();
785     }
786
787     /**
788      * See if a given cursor is available for use.
789      * if so return its activation. Returns null if not found.
790      * For use in execution.
791      *
792      * @return the activation for the given cursor, null
793      * if none was found.
794      */

795     public CursorActivation lookupCursorActivation(String JavaDoc cursorName) {
796
797         int size = acts.size();
798         if (size > 0)
799         {
800             for (int i = 0; i < size; i++) {
801                  Activation a = (Activation) acts.elementAt(i);
802
803                  if (!a.isInUse())
804                  {
805                     continue;
806                  }
807
808
809
810                 String JavaDoc executingCursorName = a.getCursorName();
811
812                  if (cursorName.equals(executingCursorName)) {
813
814                     ResultSet rs = a.getResultSet();
815                     if (rs == null)
816                         continue;
817
818                      // if the result set is closed, the the cursor doesn't exist
819
if (rs.isClosed()) {
820                         continue;
821                      }
822
823                     return (CursorActivation)a;
824                  }
825             }
826         }
827         return null;
828     }
829
830     /**
831     * This method will remove a statement from the statement cache.
832     * It will be called, for example, if there is an exception preparing
833     * the statement.
834     *
835     * @param statement Statement to remove
836     * @exception StandardException thrown if lookup goes wrong.
837     */

838     public void removeStatement(Statement statement)
839         throws StandardException {
840
841         if (statementCache == null)
842             return;
843  
844             Cacheable cachedItem = statementCache.findCached(statement);
845             if (cachedItem != null)
846                 statementCache.remove(cachedItem);
847     }
848
849     /**
850      * See if a given statement has already been compiled for this user, and
851      * if so use its prepared statement. Returns null if not found.
852      *
853      * @exception StandardException thrown if lookup goes wrong.
854      * @return the prepared statement for the given string, null
855      * if none was found.
856      */

857     public PreparedStatement lookupStatement(GenericStatement statement)
858         throws StandardException {
859
860
861         if (statementCache == null)
862             return null;
863
864         // statement caching disable when in DDL mode
865
if (dataDictionaryInWriteMode()) {
866             return null;
867         }
868
869         Cacheable cachedItem = statementCache.find(statement);
870
871         CachedStatement cs = (CachedStatement) cachedItem;
872
873
874         GenericPreparedStatement ps = cs.getPreparedStatement();
875
876         synchronized (ps) {
877             if (ps.upToDate()) {
878                 GeneratedClass ac = ps.getActivationClass();
879
880                 // Check to see if the statement was prepared before some change
881
// in the class loading set. If this is the case then force it to be invalid
882
int currentClasses =
883                         getLanguageConnectionFactory().getClassFactory().getClassLoaderVersion();
884
885                 if (ac.getClassLoaderVersion() != currentClasses) {
886                     ps.makeInvalid(DependencyManager.INTERNAL_RECOMPILE_REQUEST, this);
887                 }
888
889                 // note that the PreparedStatement is not kept in the cache. This is because
890
// having items kept in the cache that ultimately are held onto by
891
// user code is impossible to manage. E.g. an open ResultSet would hold onto
892
// a PreparedStatement (through its activation) and the user can allow
893
// this object to be garbage collected. Pushing a context stack is impossible
894
// in garbage collection as it may deadlock with the open connection and
895
// the context manager assumes a singel current thread per context stack
896
}
897         }
898
899         statementCache.release(cachedItem);
900         return ps;
901     }
902
903     /**
904         Get a connection unique system generated name for a cursor.
905     */

906     public String JavaDoc getUniqueCursorName()
907     {
908         return getNameString("SQLCUR", nextCursorId++);
909     }
910
911     /**
912         Get a connection unique system generated name for an unnamed savepoint.
913     */

914     public String JavaDoc getUniqueSavepointName()
915     {
916         return getNameString("SAVEPT", nextSavepointId++);
917     }
918
919     /**
920         Get a connection unique system generated id for an unnamed savepoint.
921     */

922     public int getUniqueSavepointID()
923     {
924         return nextSavepointId-1;
925     }
926
927     /**
928      * Build a String for a statement name.
929      *
930      * @param prefix The prefix for the statement name.
931      * @param number The number to append for uniqueness
932      *
933      * @return A unique String for a statement name.
934      */

935     private String JavaDoc getNameString(String JavaDoc prefix, long number)
936     {
937         if (sb != null)
938         {
939             sb.setLength(0);
940         }
941         else
942         {
943             sb = new StringBuffer JavaDoc();
944         }
945         sb.append(prefix).append(number);
946
947         return sb.toString();
948     }
949
950     /**
951      * Do a commit as appropriate for an internally generated
952      * commit (e.g. as needed by sync, or autocommit).
953      *
954      * @param commitStore true if we should commit the Store transaction
955      *
956      * @exception StandardException thrown on failure
957      */

958     public void internalCommit(boolean commitStore) throws StandardException
959     {
960         doCommit(commitStore,
961                                   true,
962                                   NON_XA,
963                                   false);
964     }
965
966     /**
967      * Do a commmit as is appropriate for a user requested
968      * commit (e.g. a java.sql.Connection.commit() or a language
969      * 'COMMIT' statement. Does some extra checking to make
970      * sure that users aren't doing anything bad.
971      *
972      * @exception StandardException thrown on failure
973      */

974     public void userCommit() throws StandardException
975     {
976         doCommit(true,
977                                   true,
978                                   NON_XA,
979                                   true);
980     }
981
982
983     /**
984         Commit the language transaction by doing a commitNoSync()
985         on the store's TransactionController.
986
987         <p>
988         Do *NOT* tell the data dictionary that the transaction is
989         finished. The reason is that this would allow other transactions
990         to see comitted DDL that could be undone in the event of a
991         system crash.
992
993         @param commitflag the flags to pass to commitNoSync in the store's
994                             TransactionController
995
996         @exception StandardException thrown on failure
997      */

998     public final void internalCommitNoSync(int commitflag) throws StandardException
999     {
1000        doCommit(true, false, commitflag, false);
1001    }
1002
1003
1004    /**
1005        Same as userCommit except commit a distributed transaction.
1006        This commit always commit store and sync the commit.
1007
1008        @param onePhase if true, allow it to commit without first going thru a
1009        prepared state.
1010
1011        @exception StandardException thrown if something goes wrong
1012     */

1013    public final void xaCommit(boolean onePhase) throws StandardException
1014    {
1015        // further overload internalCommit to make it understand 2 phase commit
1016
doCommit(true /* commit store */,
1017                                  true /* sync */,
1018                                  onePhase ? XA_ONE_PHASE : XA_TWO_PHASE,
1019                                  true);
1020    }
1021
1022
1023    /**
1024     * This is where the work on internalCommit(), userCOmmit() and
1025     * internalCommitNoSync() actually takes place.
1026     * <p>
1027     * When a commit happens, the language connection context
1028     * will close all open activations/cursors and commit the
1029     * Store transaction.
1030     * <p>
1031     * REVISIT: we talked about having a LanguageTransactionContext,
1032     * but since store transaction management is currently in flux
1033     * and our context might want to delegate to that context,
1034     * for now all commit/rollback actions are handled directly by
1035     * the language connection context.
1036     * REVISIT: this may need additional alterations when
1037     * RELEASE SAVEPOINT/ROLLBACK TO SAVEPOINT show up.
1038     * <P>
1039     * Since the access manager's own context takes care of its own
1040     * resources on commit, and the transaction stays open, there is
1041     * nothing that this context has to do with the transaction controller.
1042     * <p>
1043     * Also, tell the data dictionary that the transaction is finished,
1044     * if necessary (that is, if the data dictionary was put into
1045     * DDL mode in this transaction.
1046     *
1047     *
1048     * @param commitStore true if we should commit the Store transaction
1049     * @param sync true means do a synchronized commit,
1050     * false means do an unsynchronized commit
1051     * @param commitflag if this is an unsynchronized commit, the flags to
1052     * pass to commitNoSync in the store's
1053     * TransactionController. If this is a synchronized
1054     * commit, this flag is overloaded for xacommit.
1055     * @param requestedByUser False iff the commit is for internal use and
1056     * we should ignore the check to prevent commits
1057     * in an atomic statement.
1058     *
1059     * @exception StandardException Thrown on error
1060     */

1061
1062    protected void doCommit(boolean commitStore,
1063                                               boolean sync,
1064                                               int commitflag,
1065                                               boolean requestedByUser)
1066         throws StandardException
1067    {
1068        StatementContext statementContext = getStatementContext();
1069        if (requestedByUser &&
1070            (statementContext != null) &&
1071            statementContext.inUse() &&
1072            statementContext.isAtomic())
1073        {
1074            throw StandardException.newException(SQLState.LANG_NO_COMMIT_IN_NESTED_CONNECTION);
1075        }
1076
1077        // Log commit to error log, if appropriate
1078
if (logStatementText)
1079        {
1080            if (istream == null)
1081            {
1082                istream = Monitor.getStream();
1083            }
1084            String JavaDoc xactId = tran.getTransactionIdString();
1085            istream.printlnWithHeader(LanguageConnectionContext.xidStr +
1086                                      xactId +
1087                                      "), " +
1088                                      LanguageConnectionContext.lccStr +
1089                                      instanceNumber +
1090                                      "), " + LanguageConnectionContext.dbnameStr +
1091                                          dbname +
1092                                          "), " +
1093                                          LanguageConnectionContext.drdaStr +
1094                                          drdaID +
1095                                      "), Committing");
1096        }
1097
1098        resetActivations(false);
1099
1100        //do the clean up work required for temporary tables at the commit time. This cleanup work
1101
//can possibly remove entries from allDeclaredGlobalTempTables and that's why we need to check
1102
//again later to see if we there are still any entries in allDeclaredGlobalTempTables
1103
if (allDeclaredGlobalTempTables != null)
1104        {
1105            tempTablesAndCommit();
1106            //at commit time, for all the temp tables declared with ON COMMIT DELETE ROWS, make sure there are no held cursor open on them.
1107
//If there are no held cursors open on ON COMMIT DELETE ROWS, drop those temp tables and redeclare them to get rid of all the data in them
1108
if (allDeclaredGlobalTempTables != null) {
1109                for (int i=0; i<allDeclaredGlobalTempTables.size(); i++)
1110                {
1111                    TableDescriptor td = ((TempTableInfo)(allDeclaredGlobalTempTables.get(i))).getTableDescriptor();
1112                    if (td.isOnCommitDeleteRows() == false) //do nothing for temp table with ON COMMIT PRESERVE ROWS
1113
{
1114                        continue;
1115                    }
1116                    if (checkIfAnyActivationHasHoldCursor(td.getName()) == false)//temp tables with ON COMMIT DELETE ROWS and no open held cursors
1117
{
1118                        getDataDictionary().getDependencyManager().invalidateFor(td, DependencyManager.DROP_TABLE, this);
1119                        cleanupTempTableOnCommitOrRollback(td, true);
1120                    }
1121                }
1122            }
1123        }
1124
1125
1126        currentSavepointLevel = 0; //reset the current savepoint level for the connection to 0 at the end of commit work for temp tables
1127

1128        // Do *NOT* tell the DataDictionary to start using its cache again
1129
// if this is an unsynchronized commit. The reason is that it
1130
// would allow other transactions to see this transaction's DDL,
1131
// which could be rolled back in case of a system crash.
1132
if (sync)
1133        {
1134            finishDDTransaction();
1135        }
1136
1137        // now commit the Store transaction
1138
TransactionController tc = getTransactionExecute();
1139        if ( tc != null && commitStore )
1140        {
1141            if (sync)
1142            {
1143                if (commitflag == NON_XA)
1144                {
1145                    // regular commit
1146
tc.commit();
1147                }
1148                else
1149                {
1150                    // This may be a xa_commit, check overloaded commitflag.
1151

1152                    if (SanityManager.DEBUG)
1153                        SanityManager.ASSERT(commitflag == XA_ONE_PHASE ||
1154                                             commitflag == XA_TWO_PHASE,
1155                                               "invalid commit flag");
1156
1157                    ((XATransactionController)tc).xa_commit(commitflag == XA_ONE_PHASE);
1158
1159                }
1160            }
1161            else
1162            {
1163                tc.commitNoSync(commitflag);
1164            }
1165
1166            // reset the savepoints to the new
1167
// location, since any outer nesting
1168
// levels expect there to be a savepoint
1169
resetSavepoints();
1170        }
1171    }
1172
1173    /**
1174     * If dropAndRedeclare is true, that means we have come here for temp tables with on commit delete rows
1175     * and no held curosr open on them. We will drop the existing conglomerate and redeclare a new conglomerate
1176     * similar to old conglomerate. This is a more efficient way of deleting all rows from the table.
1177     *
1178     * If dropAndRedeclare is false, that means we have come here for the rollback cleanup work. We are trying
1179     * to restore old definition of the temp table (because the drop on it is being rolled back).
1180     */

1181    private TableDescriptor cleanupTempTableOnCommitOrRollback(TableDescriptor td, boolean dropAndRedeclare)
1182         throws StandardException
1183    {
1184        //create new conglomerate with same properties as the old conglomerate and same row template as the old conglomerate
1185
long conglomId = tran.createConglomerate(
1186            "heap", // we're requesting a heap conglomerate
1187
td.getEmptyExecRow(getContextManager()).getRowArray(), // row template
1188
null, //column sort order - not required for heap
1189
null, // properties
1190
(TransactionController.IS_TEMPORARY | TransactionController.IS_KEPT));
1191
1192        long cid = td.getHeapConglomerateId();
1193
1194        //remove the old conglomerate descriptor from the table descriptor
1195
ConglomerateDescriptor cgd = td.getConglomerateDescriptor(cid);
1196        td.getConglomerateDescriptorList().dropConglomerateDescriptorByUUID(cgd.getUUID());
1197        //add the new conglomerate descriptor to the table descriptor
1198
cgd = getDataDictionary().getDataDescriptorGenerator().newConglomerateDescriptor(conglomId, null, false, null, false, null, td.getUUID(),
1199        td.getSchemaDescriptor().getUUID());
1200        ConglomerateDescriptorList conglomList = td.getConglomerateDescriptorList();
1201        conglomList.add(cgd);
1202
1203        //reset the heap conglomerate number in table descriptor to -1 so it will be refetched next time with the new value
1204
td.resetHeapConglomNumber();
1205
1206        if(dropAndRedeclare)
1207        {
1208            tran.dropConglomerate(cid); //remove the old conglomerate from the system
1209
replaceDeclaredGlobalTempTable(td.getName(), td);
1210        }
1211
1212        return(td);
1213    }
1214
1215    /**
1216      Do a rollback as appropriate for an internally generated
1217      rollback (e.g. as needed by sync, or autocommit).
1218     
1219      When a rollback happens, we
1220      close all open activations and invalidate their
1221      prepared statements. We then tell the cache to
1222      age out everything else, which effectively invalidates
1223      them. Thus, all prepared statements will be
1224      compiled anew on their 1st execution after
1225      a rollback.
1226      <p>
1227      The invalidated statements can revalidate themselves without
1228      a full recompile if they verify their dependencies' providers still
1229      exist unchanged. REVISIT when invalidation types are created.
1230      <p>
1231      REVISIT: this may need additional alterations when
1232      RELEASE SAVEPOINT/ROLLBACK TO SAVEPOINT show up.
1233      <p>
1234      Also, tell the data dictionary that the transaction is finished,
1235      if necessary (that is, if the data dictionary was put into
1236      DDL mode in this transaction.
1237
1238      @exception StandardException thrown on failure
1239     */

1240
1241    public void internalRollback() throws StandardException
1242    {
1243        doRollback(false /* non-xa */, false);
1244    }
1245
1246    /**
1247     * Do a rollback as is appropriate for a user requested
1248     * rollback (e.g. a java.sql.Connection.rollback() or a language
1249     * 'ROLLBACk' statement. Does some extra checking to make
1250     * sure that users aren't doing anything bad.
1251     *
1252     * @exception StandardException thrown on failure
1253     */

1254    public void userRollback() throws StandardException
1255    {
1256        doRollback(false /* non-xa */, true);
1257    }
1258
1259    /**
1260        Same as userRollback() except rolls back a distrubuted transaction.
1261
1262        @exception StandardException thrown if something goes wrong
1263     */

1264    public void xaRollback() throws StandardException
1265    {
1266        doRollback(true /* xa */, true);
1267    }
1268
1269    /**
1270     * When a rollback happens, the language connection context
1271     * will close all open activations and invalidate
1272     * their prepared statements. Then the language will abort the
1273     * Store transaction.
1274     * <p>
1275     * The invalidated statements can revalidate themselves without
1276     * a full recompile if they verify their dependencies' providers still
1277     * exist unchanged. REVISIT when invalidation types are created.
1278     * <p>
1279     * REVISIT: this may need additional alterations when
1280     * RELEASE SAVEPOINT/ROLLBACK TO SAVEPOINT show up.
1281     * <p>
1282     * Also, tell the data dictionary that the transaction is finished,
1283     * if necessary (that is, if the data dictionary was put into
1284     * DDL mode in this transaction.
1285     *
1286     * @param xa true if this is an xa rollback
1287     * @param requestedByUser true if requested by user
1288     *
1289     * @exception StandardException thrown on failure
1290     */

1291    private void doRollback(boolean xa, boolean requestedByUser) throws StandardException
1292    {
1293        StatementContext statementContext = getStatementContext();
1294        if (requestedByUser &&
1295            (statementContext != null) &&
1296            statementContext.inUse() &&
1297            statementContext.isAtomic())
1298        {
1299            throw StandardException.newException(SQLState.LANG_NO_ROLLBACK_IN_NESTED_CONNECTION);
1300        }
1301
1302        // Log rollback to error log, if appropriate
1303
if (logStatementText)
1304        {
1305            if (istream == null)
1306            {
1307                istream = Monitor.getStream();
1308            }
1309            String JavaDoc xactId = tran.getTransactionIdString();
1310            istream.printlnWithHeader(LanguageConnectionContext.xidStr +
1311                                      xactId +
1312                                      "), " +
1313                                      LanguageConnectionContext.lccStr +
1314                                      instanceNumber +
1315                                      "), " + LanguageConnectionContext.dbnameStr +
1316                                          dbname +
1317                                          "), " +
1318                                          LanguageConnectionContext.dbnameStr +
1319                                          dbname +
1320                                          "), " +
1321                                          LanguageConnectionContext.drdaStr +
1322                                          drdaID +
1323                                      "), Rolling back");
1324        }
1325
1326        resetActivations(true);
1327
1328        currentSavepointLevel = 0; //reset the current savepoint level for the connection to 0 at the beginning of rollback work for temp tables
1329
if (allDeclaredGlobalTempTables != null)
1330            tempTablesAndRollback();
1331
1332        finishDDTransaction();
1333
1334        // now rollback the Store transaction
1335
TransactionController tc = getTransactionExecute();
1336        if (tc != null)
1337        {
1338            if (xa)
1339                ((XATransactionController)tc).xa_rollback();
1340            else
1341                tc.abort();
1342            // reset the savepoints to the new
1343
// location, since any outer nesting
1344
// levels expet there to be a savepoint
1345
resetSavepoints();
1346        }
1347    }
1348
1349    /**
1350     * Reset all statement savepoints. Traverses the StatementContext
1351     * stack from bottom to top, calling resetSavePoint()
1352     * on each element.
1353     *
1354     * @exception StandardException thrown if something goes wrong
1355     */

1356    private void resetSavepoints() throws StandardException
1357    {
1358        final ContextManager cm = getContextManager();
1359        final List stmts = cm.getContextStack(org.apache.derby.
1360                                              iapi.reference.
1361                                              ContextId.LANG_STATEMENT);
1362        final int end = stmts.size();
1363        for (int i = 0; i < end; ++i) {
1364            ((StatementContext)stmts.get(i)).resetSavePoint();
1365        }
1366    }
1367
1368    /**
1369     * Let the context deal with a rollback to savepoint
1370     *
1371     * @param savepointName Name of the savepoint that needs to be rolled back
1372     * @param refreshStyle boolean indicating whether or not the controller should close
1373     * open conglomerates and scans. Also used to determine if language should close
1374     * open activations.
1375     * @param kindOfSavepoint A NULL value means it is an internal savepoint (ie not a user defined savepoint)
1376     * Non NULL value means it is a user defined savepoint which can be a SQL savepoint or a JDBC savepoint
1377     * A String value for kindOfSavepoint would mean it is SQL savepoint
1378     * A JDBC Savepoint object value for kindOfSavepoint would mean it is JDBC savepoint
1379     *
1380     * @exception StandardException thrown if something goes wrong
1381     */

1382    public void internalRollbackToSavepoint( String JavaDoc savepointName, boolean refreshStyle, Object JavaDoc kindOfSavepoint )
1383        throws StandardException
1384    {
1385        // now rollback the Store transaction to the savepoint
1386
TransactionController tc = getTransactionExecute();
1387        if (tc != null)
1388        {
1389            boolean closeConglomerates;
1390
1391            if ( refreshStyle )
1392            {
1393                closeConglomerates = true;
1394                // bug 5145 - don't forget to close the activations while rolling
1395
// back to a savepoint
1396
resetActivations(true);
1397            }
1398            else { closeConglomerates = false; }
1399
1400            currentSavepointLevel = tc.rollbackToSavePoint( savepointName, closeConglomerates, kindOfSavepoint );
1401        }
1402
1403        if (tc != null && refreshStyle && allDeclaredGlobalTempTables != null)
1404            tempTablesAndRollback();
1405    }
1406
1407    /**
1408      Let the context deal with a release of a savepoint
1409
1410      @param savepointName Name of the savepoint that needs to be released
1411      @param kindOfSavepoint A NULL value means it is an internal savepoint (ie not a user defined savepoint)
1412      Non NULL value means it is a user defined savepoint which can be a SQL savepoint or a JDBC savepoint
1413      A String value for kindOfSavepoint would mean it is SQL savepoint
1414      A JDBC Savepoint object value for kindOfSavepoint would mean it is JDBC savepoint
1415
1416      @exception StandardException thrown if something goes wrong
1417     */

1418    public void releaseSavePoint( String JavaDoc savepointName, Object JavaDoc kindOfSavepoint ) throws StandardException
1419    {
1420        TransactionController tc = getTransactionExecute();
1421        if (tc != null)
1422        {
1423            currentSavepointLevel = tc.releaseSavePoint( savepointName, kindOfSavepoint );
1424            //after a release of a savepoint, we need to go through our temp tables list.
1425
if (allDeclaredGlobalTempTables != null)
1426                tempTablesReleaseSavepointLevels();
1427        }
1428    }
1429
1430    /**
1431      Sets a savepoint. Causes the Store to set a savepoint.
1432
1433      @param savepointName name of savepoint
1434      @param kindOfSavepoint A NULL value means it is an internal savepoint (ie not a user defined savepoint)
1435      Non NULL value means it is a user defined savepoint which can be a SQL savepoint or a JDBC savepoint
1436      A String value for kindOfSavepoint would mean it is SQL savepoint
1437      A JDBC Savepoint object value for kindOfSavepoint would mean it is JDBC savepoint
1438
1439        @exception StandardException thrown if something goes wrong
1440      */

1441    public void languageSetSavePoint( String JavaDoc savepointName, Object JavaDoc kindOfSavepoint ) throws StandardException
1442    {
1443        TransactionController tc = getTransactionExecute();
1444        if (tc != null)
1445        {
1446            currentSavepointLevel = tc.setSavePoint( savepointName, kindOfSavepoint );
1447        }
1448    }
1449
1450    /**
1451     * Return true if any transaction is blocked, even if not by this one
1452     *
1453     */

1454    public boolean anyoneBlocked()
1455    {
1456        return getTransactionExecute().anyoneBlocked();
1457    }
1458
1459    /**
1460        Sets the transaction controller to use with this language connection
1461        context.
1462
1463        @param tran the transaction to use with this language connection context
1464     */

1465    public void setTransaction( TransactionController tran ) { this.tran = tran; }
1466
1467
1468    /**
1469     * Start a Nested User Transaction (NUT) with the store. If a NUT is
1470     * already active simply increment a counter, queryNestingDepth, to keep
1471     * track of how many times we have tried to start a NUT.
1472     */

1473    public void beginNestedTransaction(boolean readOnly) throws StandardException
1474    {
1475        if (childTransaction == null)
1476            childTransaction = tran.startNestedUserTransaction(readOnly);
1477        queryNestingDepth++;
1478        return;
1479    }
1480
1481    public void commitNestedTransaction()
1482        throws StandardException
1483    {
1484        if (--queryNestingDepth == 0)
1485        {
1486            childTransaction.commit();
1487            childTransaction.destroy();
1488            childTransaction = null;
1489            return;
1490        }
1491    }
1492
1493    /**
1494     * Get the transaction controller to use at compile time with this language
1495     * connection context. If a NUT is active then return NUT else return parent
1496     * transaction.
1497     */

1498    public TransactionController getTransactionCompile()
1499    {
1500        return (childTransaction != null) ? childTransaction : tran;
1501    }
1502
1503    public TransactionController getTransactionExecute()
1504    {
1505        return tran;
1506    }
1507
1508 /** Get the data value factory to use with this language connection
1509        context.
1510     */

1511    public DataValueFactory getDataValueFactory() {
1512        return dataFactory;
1513    }
1514    
1515    /**
1516        Get the language factory to use with this language connection
1517        context.
1518     */

1519    public LanguageFactory getLanguageFactory() {
1520        return langFactory;
1521    }
1522        
1523    public OptimizerFactory getOptimizerFactory() {
1524        return of;
1525    }
1526
1527    /**
1528        Get the language connection factory to use with this language connection
1529        context.
1530     */

1531    public LanguageConnectionFactory getLanguageConnectionFactory() {
1532        return connFactory;
1533    }
1534
1535    /**
1536     * check if there are any activations that reference this temporary table
1537     * @param tableName look for any activations referencing this table name
1538     * @return boolean false if found no activations
1539     */

1540    private boolean checkIfAnyActivationHasHoldCursor(String JavaDoc tableName)
1541            throws StandardException
1542    {
1543        for (int i = acts.size() - 1; i >= 0; i--) {
1544            Activation a = (Activation) acts.elementAt(i);
1545            if (a.checkIfThisActivationHasHoldCursor(tableName))
1546                return true;
1547    }
1548    return false;
1549    }
1550
1551
1552    /**
1553     * Verify that there are no activations with open held result sets.
1554     *
1555     * @return boolean Found no open (held) resultsets.
1556     *
1557     * @exception StandardException thrown on failure
1558     */

1559    /* This gets used in case of hold cursors. If there are any hold cursors open
1560     * then user can't change the isolation level without closing them. At the
1561     * execution time, set transaction isolation level calls this method before
1562     * changing the isolation level.
1563     */

1564    public boolean verifyAllHeldResultSetsAreClosed()
1565            throws StandardException
1566    {
1567        boolean seenOpenResultSets = false;
1568
1569        /* For every activation */
1570        for (int i = acts.size() - 1; i >= 0; i--) {
1571
1572            Activation a = (Activation) acts.elementAt(i);
1573
1574            if (SanityManager.DEBUG)
1575            {
1576                SanityManager.ASSERT(a instanceof CursorActivation, "a is not a CursorActivation");
1577            }
1578
1579            if (!a.isInUse())
1580            {
1581                continue;
1582            }
1583
1584            if (!a.getResultSetHoldability())
1585            {
1586                continue;
1587            }
1588
1589            ResultSet rs = ((CursorActivation) a).getResultSet();
1590
1591            /* is there an open result set? */
1592            if ((rs != null) && !rs.isClosed() && rs.returnsRows())
1593            {
1594                seenOpenResultSets = true;
1595                break;
1596            }
1597        }
1598
1599        if (!seenOpenResultSets)
1600            return(true);
1601
1602        // There may be open ResultSet's that are yet to be garbage collected
1603
// let's try and force these out rather than throw an error
1604
System.gc();
1605        System.runFinalization();
1606
1607
1608        /* For every activation */
1609        for (int i = acts.size() - 1; i >= 0; i--) {
1610                
1611            Activation a = (Activation) acts.elementAt(i);
1612
1613            if (SanityManager.DEBUG)
1614            {
1615                SanityManager.ASSERT(a instanceof CursorActivation, "a is not a CursorActivation");
1616            }
1617
1618            if (!a.isInUse())
1619            {
1620                continue;
1621            }
1622
1623            if (!a.getResultSetHoldability())
1624            {
1625                continue;
1626            }
1627
1628            ResultSet rs = ((CursorActivation) a).getResultSet();
1629
1630            /* is there an open held result set? */
1631            if ((rs != null) && !rs.isClosed() && rs.returnsRows())
1632            {
1633                return(false);
1634            }
1635        }
1636        return(true);
1637    }
1638
1639    /**
1640     * Verify that there are no activations with open result sets
1641     * on the specified prepared statement.
1642     *
1643     * @param pStmt The prepared Statement
1644     * @param provider The object precipitating a possible invalidation
1645     * @param action The action causing the possible invalidation
1646     *
1647     * @return Nothing.
1648     *
1649     * @exception StandardException thrown on failure
1650     */

1651    public boolean verifyNoOpenResultSets(PreparedStatement pStmt, Provider provider,
1652                                       int action)
1653            throws StandardException
1654    {
1655        /*
1656        ** It is not a problem to create an index when there is an open
1657        ** result set, since it doesn't invalidate the access path that was
1658        ** chosen for the result set.
1659        */

1660        boolean seenOpenResultSets = false;
1661
1662        /* For every activation */
1663
1664        // synchronize on acts as other threads may be closing activations
1665
// in this list, thus invalidating the Enumeration
1666
for (int i = acts.size() - 1; i >= 0; i--) {
1667                
1668            Activation a = (Activation) acts.elementAt(i);
1669
1670            if (!a.isInUse())
1671            {
1672                continue;
1673            }
1674            
1675            /* for this prepared statement */
1676            if (pStmt == a.getPreparedStatement()) {
1677                ResultSet rs = a.getResultSet();
1678
1679                /* is there an open result set? */
1680                if (rs != null && ! rs.isClosed())
1681                {
1682                    if (!rs.returnsRows())
1683                        continue;
1684                    seenOpenResultSets = true;
1685                    break;
1686                }
1687                
1688            }
1689        }
1690
1691        if (!seenOpenResultSets)
1692            return false;
1693
1694        // There may be open ResultSet's that are yet to be garbage collected
1695
// let's try and force these out rather than throw an error
1696
System.gc();
1697        System.runFinalization();
1698
1699
1700        /* For every activation */
1701        // synchronize on acts as other threads may be closing activations
1702
// in this list, thus invalidating the Enumeration
1703
for (int i = acts.size() - 1; i >= 0; i--) {
1704                
1705            Activation a = (Activation) acts.elementAt(i);
1706
1707            if (!a.isInUse())
1708            {
1709                continue;
1710            }
1711
1712            /* for this prepared statement */
1713            if (pStmt == a.getPreparedStatement()) {
1714                ResultSet rs = a.getResultSet();
1715
1716                /* is there an open result set? */
1717                if (rs != null && ! rs.isClosed())
1718                {
1719                    if ((provider != null) && rs.returnsRows()) {
1720                    DependencyManager dmgr = getDataDictionary().getDependencyManager();
1721
1722                    throw StandardException.newException(SQLState.LANG_CANT_INVALIDATE_OPEN_RESULT_SET,
1723                                    dmgr.getActionString(action),
1724                                    provider.getObjectName());
1725
1726                    }
1727                    return true;
1728                }
1729            }
1730        }
1731        return false;
1732    }
1733
1734    /**
1735     * Get the Authorization Id
1736     *
1737     * @return String the authorization id
1738     */

1739    public String JavaDoc getAuthorizationId()
1740    {
1741        return authorizer.getAuthorizationId();
1742    }
1743
1744    /**
1745     * Get the default schema
1746     *
1747     * @return SchemaDescriptor the default schema
1748     */

1749    public SchemaDescriptor getDefaultSchema()
1750    {
1751        return sd;
1752    }
1753    /**
1754     * Get the current schema name
1755     *
1756     * @return current schema name
1757     */

1758    public String JavaDoc getCurrentSchemaName()
1759    {
1760        if( null == sd)
1761            return null;
1762        return sd.getSchemaName();
1763    }
1764
1765    /**
1766     * Set the default schema -- used by SET SCHEMA.
1767     *
1768     * @param sd the new default schema.
1769     * If null, then the default schema descriptor is used.
1770     *
1771     * @exception StandardException thrown on failure
1772     */

1773    public void setDefaultSchema(SchemaDescriptor sd)
1774        throws StandardException
1775    {
1776        if (sd == null)
1777        {
1778            sd = initDefaultSchemaDescriptor();
1779        }
1780        this.sd = sd;
1781        
1782    }
1783
1784    /**
1785     * Get the identity column value most recently generated.
1786     *
1787     * @return the generated identity column value
1788     */

1789    public Long JavaDoc getIdentityValue()
1790    {
1791        return identityNotNull ? new Long JavaDoc(identityVal) : null;
1792    }
1793
1794    /**
1795     * Set the field of most recently generated identity column value.
1796     *
1797     * @param val the generated identity column value
1798     */

1799    public void setIdentityValue(long val)
1800    {
1801        identityVal = val;
1802        identityNotNull = true;
1803    }
1804
1805    /**
1806        Empty as much of the cache as possible. It is not guaranteed
1807        that the cache is empty after this call, as statements may be kept
1808        by currently executing queries, activations that are about to be garbage
1809        collected.
1810    */

1811    public void emptyCache() {
1812        /* We know prepared statements don't become dirty
1813        ** statementCache.cleanAll();
1814        */

1815        if (statementCache != null)
1816            statementCache.ageOut();
1817    }
1818
1819    /**
1820     * Push a CompilerContext on the context stack with
1821     * the current default schema as the default schema
1822     * which we compile against.
1823     *
1824     * @return the compiler context
1825     *
1826     * @exception StandardException thrown on failure
1827     */

1828    public final CompilerContext pushCompilerContext()
1829    {
1830        return pushCompilerContext((SchemaDescriptor)null);
1831    }
1832
1833    /**
1834     * Push a CompilerContext on the context stack with
1835     * the passed in default schema as the default schema
1836     * we compile against.
1837     *
1838     * @param sd the default schema
1839     *
1840     * @return the compiler context
1841     *
1842     */

1843    public CompilerContext pushCompilerContext(SchemaDescriptor sd)
1844    {
1845        CompilerContext cc;
1846        boolean firstCompilerContext = false;
1847
1848        // DEBUG END
1849

1850        cc = (CompilerContext) (getContextManager().getContext(CompilerContext.CONTEXT_ID));
1851
1852        /*
1853        ** If there is no compiler context, this is the first one on the
1854        ** stack, so don't pop it when we're done (saves time).
1855        */

1856        if (cc == null) { firstCompilerContext = true; }
1857
1858        if (cc == null || cc.getInUse())
1859        {
1860            cc = new CompilerContextImpl(getContextManager(), this, tcf);
1861            if (firstCompilerContext) { cc.firstOnStack(); }
1862        }
1863        else
1864        {
1865            /* Reset the next column,table, subquery and ResultSet numbers at
1866            * the beginning of each statement
1867            */

1868            cc.resetContext();
1869        }
1870
1871        cc.setInUse(true);
1872
1873        // Save off the current isolation level on entry so that it gets restored
1874
cc.setEntryIsolationLevel( getCurrentIsolationLevel());
1875
1876        StatementContext sc = getStatementContext();
1877        if (sc.getSystemCode())
1878            cc.setReliability(CompilerContext.INTERNAL_SQL_LEGAL);
1879
1880        return cc;
1881    }
1882
1883
1884    /**
1885     * Pop a CompilerContext off the context stack.
1886     *
1887     * @param cc The compiler context.
1888     */

1889    public void popCompilerContext(CompilerContext cc)
1890    {
1891        cc.setCurrentDependent(null);
1892
1893        cc.setInUse(false);
1894
1895        // Restore the isolation level at the time of entry to CompilerContext
1896
isolationLevel = cc.getEntryIsolationLevel();
1897
1898        /*
1899        ** Only pop the compiler context if it's not the first one
1900        ** on the stack.
1901        */

1902        if (! cc.isFirstOnStack())
1903        {
1904            cc.popMe();
1905        }
1906        else
1907        {
1908            cc.setCompilationSchema((SchemaDescriptor)null);
1909        }
1910    }
1911
1912    /**
1913     * Push a StatementContext on the context stack.
1914     *
1915     * @param isAtomic whether this statement is atomic or not
1916     * @param isForReadOnly whether this statement is for a read only resultset
1917     * @param stmtText the text of the statement. Needed for any language
1918     * statement (currently, for any statement that can cause a trigger
1919     * to fire). Please set this unless you are some funky jdbc setXXX
1920     * method or something.
1921     * @param pvs parameter value set, if it has one
1922     * @param rollbackParentContext True if 1) the statement context is
1923     * NOT a top-level context, AND 2) in the event of a statement-level
1924     * exception, the parent context needs to be rolled back, too.
1925     * @param timeoutMillis timeout value for this statement, in milliseconds.
1926     * The value 0 means that no timeout is set.
1927     *
1928     * @return StatementContext The statement context.
1929     *
1930     */

1931    public StatementContext pushStatementContext (boolean isAtomic, boolean isForReadOnly,
1932                              String JavaDoc stmtText, ParameterValueSet pvs,
1933                              boolean rollbackParentContext,
1934                              long timeoutMillis)
1935    {
1936        int parentStatementDepth = statementDepth;
1937        boolean inTrigger = false;
1938        boolean parentIsAtomic = false;
1939
1940        // by default, assume we are going to use the outermost statement context
1941
StatementContext statementContext = statementContexts[0];
1942
1943        /*
1944        ** If we haven't allocated any statement contexts yet, allocate
1945        ** the outermost stmt context now and push it.
1946        */

1947        if (statementContext == null)
1948        {
1949            statementContext = statementContexts[0] = new GenericStatementContext(this, tran);
1950        }
1951        else if (statementDepth > 0)
1952        {
1953            StatementContext parentStatementContext;
1954            /*
1955            ** We also cache a 2nd statement context, though we still
1956            ** push and pop it. Note, new contexts are automatically pushed.
1957            */

1958            if (statementDepth == 1)
1959            {
1960                statementContext = statementContexts[1];
1961
1962                if (statementContext == null)
1963                    statementContext = statementContexts[1] = new GenericStatementContext(this, tran);
1964                else
1965                    statementContext.pushMe();
1966
1967                parentStatementContext = statementContexts[0];
1968            }
1969            else
1970            {
1971                parentStatementContext = getStatementContext();
1972                statementContext = new GenericStatementContext(this, tran);
1973            }
1974
1975            inTrigger = parentStatementContext.inTrigger() || (outermostTrigger == parentStatementDepth);
1976            parentIsAtomic = parentStatementContext.isAtomic();
1977            statementContext.setSQLAllowed(parentStatementContext.getSQLAllowed(), false);
1978            if (parentStatementContext.getSystemCode())
1979                statementContext.setSystemCode();
1980        }
1981
1982        incrementStatementDepth();
1983
1984        statementContext.setInUse(inTrigger, isAtomic || parentIsAtomic, isForReadOnly, stmtText, pvs, timeoutMillis);
1985        if (rollbackParentContext)
1986            statementContext.setParentRollback();
1987        return statementContext;
1988    }
1989
1990    /**
1991     * Pop a StatementContext of the context stack.
1992     *
1993     * @param statementContext The statement context.
1994     * @param error The error, if any (Only relevant for DEBUG)
1995     */

1996    public void popStatementContext(StatementContext statementContext,
1997                                    Throwable JavaDoc error)
1998    {
1999        if ( statementContext != null )
2000        {
2001            /*
2002            ** If someone beat us to the punch, then it is ok,
2003            ** just silently ignore it. We probably got here
2004            ** because we had a try catch block around a push/pop
2005            ** statement context, and we already got the context
2006            ** on a cleanupOnError.
2007            */

2008            if (!statementContext.inUse())
2009            {
2010                return;
2011            }
2012            statementContext.clearInUse();
2013        }
2014
2015        decrementStatementDepth();
2016        if (statementDepth == -1)
2017        {
2018            /*
2019             * Only ignore the pop request for an already
2020             * empty stack when dealing with a session exception.
2021             */

2022            if (SanityManager.DEBUG)
2023            {
2024                int severity = (error instanceof StandardException) ?
2025                                    ((StandardException)error).getSeverity() :
2026                                0;
2027                SanityManager.ASSERT(error != null,
2028                    "Must have error to try popStatementContext with 0 depth");
2029                SanityManager.ASSERT(
2030                    (severity == ExceptionSeverity.SESSION_SEVERITY),
2031                    "Must have session severity error to try popStatementContext with 0 depth");
2032                SanityManager.ASSERT(statementContext == statementContexts[0],
2033                    "statementContext is expected to equal statementContexts[0]");
2034            }
2035            resetStatementDepth(); // pretend we did nothing.
2036
}
2037        else if (statementDepth == 0)
2038        {
2039            if (SanityManager.DEBUG)
2040            {
2041                /* Okay to pop last context on a session exception.
2042                 * (We call clean up on error when exiting connection.)
2043                 */

2044                int severity = (error instanceof StandardException) ?
2045                                    ((StandardException)error).getSeverity() :
2046                                0;
2047                if ((error == null) ||
2048                    (severity != ExceptionSeverity.SESSION_SEVERITY))
2049                {
2050                    SanityManager.ASSERT(statementContext == statementContexts[0],
2051                        "statementContext is expected to equal statementContexts[0]");
2052                }
2053            }
2054        }
2055        else
2056        {
2057            if (SanityManager.DEBUG)
2058            {
2059                SanityManager.ASSERT(statementContext != statementContexts[0],
2060                    "statementContext is not expected to equal statementContexts[0]");
2061                if (statementDepth <= 0)
2062                    SanityManager.THROWASSERT(
2063                        "statement depth expected to be >0, was "+statementDepth);
2064                
2065                if (getContextManager().getContext(statementContext.getIdName()) != statementContext)
2066                {
2067                    SanityManager.THROWASSERT("trying to pop statement context from middle of stack");
2068                }
2069            }
2070
2071            statementContext.popMe();
2072        }
2073
2074    }
2075
2076    /**
2077     * Push a new execution statement validator. An execution statement
2078     * validator is an object that validates the current statement to
2079     * ensure that it is permitted given the current execution context.
2080     * An example of a validator a trigger ExecutionStmtValidator that
2081     * doesn't allow ddl on the trigger target table.
2082     * <p>
2083     * Multiple ExecutionStmtValidators may be active at any given time.
2084     * This mirrors the way there can be multiple connection nestings
2085     * at a single time. The validation is performed by calling each
2086     * validator's validateStatement() method. This yields the union
2087     * of all validations.
2088     *
2089     * @param validator the validator to add
2090     */

2091    public void pushExecutionStmtValidator(ExecutionStmtValidator validator)
2092    {
2093        stmtValidators.addElement(validator);
2094    }
2095
2096    /**
2097     * Remove the validator. Does an object identity (validator == validator)
2098     * comparison. Asserts that the validator is found.
2099     *
2100     * @param validator the validator to remove
2101     *
2102     * @exception StandardException on error
2103     */

2104    public void popExecutionStmtValidator(ExecutionStmtValidator validator)
2105        throws StandardException
2106    {
2107        boolean foundElement = stmtValidators.removeElement(validator);
2108        if (SanityManager.DEBUG)
2109        {
2110            if (!foundElement)
2111            {
2112                SanityManager.THROWASSERT("statement validator "+validator+" not found");
2113            }
2114        }
2115    }
2116
2117    /**
2118     * Push a new trigger execution context.
2119     * <p>
2120     * Multiple TriggerExecutionContexts may be active at any given time.
2121     *
2122     * @param tec the trigger execution context
2123     *
2124     * @exception StandardException on trigger recursion error
2125     */

2126    public void pushTriggerExecutionContext(TriggerExecutionContext tec) throws StandardException
2127    {
2128        if (outermostTrigger == -1)
2129        {
2130            outermostTrigger = statementDepth;
2131        }
2132
2133        /* Maximum 16 nesting levels allowed */
2134        if (triggerExecutionContexts.size() >= Limits.DB2_MAX_TRIGGER_RECURSION)
2135        {
2136            throw StandardException.newException(SQLState.LANG_TRIGGER_RECURSION_EXCEEDED);
2137        }
2138
2139        triggerExecutionContexts.addElement(tec);
2140    }
2141
2142    /**
2143     * Remove the tec. Does an object identity (tec == tec)
2144     * comparison. Asserts that the tec is found.
2145     *
2146     * @param tec the tec to remove
2147     *
2148     * @exception StandardException on error
2149     */

2150    public void popTriggerExecutionContext(TriggerExecutionContext tec)
2151        throws StandardException
2152    {
2153        if (outermostTrigger == statementDepth)
2154        {
2155            outermostTrigger = -1;
2156        }
2157
2158        boolean foundElement = triggerExecutionContexts.removeElement(tec);
2159        if (SanityManager.DEBUG)
2160        {
2161            if (!foundElement)
2162            {
2163                SanityManager.THROWASSERT("trigger execution context "+tec+" not found");
2164            }
2165        }
2166    }
2167
2168    /**
2169     * Get the topmost tec.
2170     *
2171     * @return the tec
2172     */

2173    public TriggerExecutionContext getTriggerExecutionContext()
2174    {
2175        return triggerExecutionContexts.size() == 0 ?
2176                (TriggerExecutionContext)null :
2177                (TriggerExecutionContext)triggerExecutionContexts.lastElement();
2178    }
2179
2180    /**
2181     * Validate a statement. Does so by stepping through all the validators
2182     * and executing them. If a validator throws and exception, then the
2183     * checking is stopped and the exception is passed up.
2184     *
2185     * @param constantAction the constantAction that is about to be executed (and
2186     * should be validated
2187     *
2188     * @exception StandardException on validation failure
2189     */

2190    public void validateStmtExecution(ConstantAction constantAction)
2191        throws StandardException
2192    {
2193        if (SanityManager.DEBUG)
2194        {
2195            SanityManager.ASSERT(constantAction!=null, "constantAction is null");
2196        }
2197
2198        if (stmtValidators.size() > 0)
2199        {
2200            for (Enumeration JavaDoc e = stmtValidators.elements(); e.hasMoreElements(); )
2201            {
2202                ((ExecutionStmtValidator)e.nextElement()).validateStatement(constantAction);
2203            }
2204        }
2205    }
2206    
2207    /**
2208     * Set the trigger table descriptor. Used to compile
2209     * statements that may special trigger pseudo tables.
2210     *
2211     * @param td the table that the trigger is
2212     * defined upon
2213     *
2214     */

2215    public void pushTriggerTable(TableDescriptor td)
2216    {
2217        triggerTables.addElement(td);
2218    }
2219
2220    /**
2221     * Remove the trigger table descriptor.
2222     *
2223     * @param td the table to remove from the stack.
2224     */

2225    public void popTriggerTable(TableDescriptor td)
2226    {
2227        boolean foundElement = triggerTables.removeElement(td);
2228        if (SanityManager.DEBUG)
2229        {
2230            if (!foundElement)
2231            {
2232                SanityManager.THROWASSERT("trigger table not found: "+td);
2233            }
2234        }
2235    }
2236
2237    /**
2238     * Get the topmost trigger table descriptor
2239     *
2240     * @return the table descriptor, or null if we
2241     * aren't in the middle of compiling a create
2242     * trigger.
2243     */

2244    public TableDescriptor getTriggerTable()
2245    {
2246        return triggerTables.size() == 0 ?
2247            (TableDescriptor)null :
2248            (TableDescriptor)triggerTables.lastElement();
2249    }
2250    /**
2251     * @see LanguageConnectionContext#getDatabase
2252     */

2253    public Database
2254    getDatabase()
2255    {
2256        return db;
2257    }
2258
2259    /** @see LanguageConnectionContext#incrementBindCount */
2260    public int incrementBindCount()
2261    {
2262        bindCount++;
2263        return bindCount;
2264    }
2265
2266    
2267    /** @see LanguageConnectionContext#decrementBindCount */
2268    public int decrementBindCount()
2269    {
2270        bindCount--;
2271
2272        if (SanityManager.DEBUG)
2273        {
2274            if (bindCount < 0)
2275                SanityManager.THROWASSERT(
2276                    "Level of nested binding == " + bindCount);
2277        }
2278
2279        return bindCount;
2280    }
2281
2282    /** @see LanguageConnectionContext#getBindCount */
2283    public int getBindCount()
2284    {
2285        return bindCount;
2286    }
2287
2288    /** @see LanguageConnectionContext#setDataDictionaryWriteMode */
2289    public final void setDataDictionaryWriteMode()
2290    {
2291        ddWriteMode = true;
2292    }
2293
2294    /** @see LanguageConnectionContext#dataDictionaryInWriteMode */
2295    public final boolean dataDictionaryInWriteMode()
2296    {
2297        return ddWriteMode;
2298    }
2299
2300    /** @see LanguageConnectionContext#setRunTimeStatisticsMode */
2301    public void setRunTimeStatisticsMode(boolean onOrOff)
2302    {
2303        runTimeStatisticsSetting = onOrOff;
2304    }
2305
2306    /** @see LanguageConnectionContext#getRunTimeStatisticsMode */
2307    public boolean getRunTimeStatisticsMode()
2308    {
2309        return runTimeStatisticsSetting;
2310    }
2311
2312    /** @see LanguageConnectionContext#setStatisticsTiming */
2313    public void setStatisticsTiming(boolean onOrOff)
2314    {
2315        statisticsTiming = onOrOff;
2316    }
2317
2318    /** @see LanguageConnectionContext#getStatisticsTiming */
2319    public boolean getStatisticsTiming()
2320    {
2321        return statisticsTiming;
2322    }
2323
2324    /** @see LanguageConnectionContext#setRunTimeStatisticsObject */
2325    public void setRunTimeStatisticsObject(RunTimeStatistics runTimeStatisticsObject)
2326    {
2327        this.runTimeStatisticsObject = runTimeStatisticsObject;
2328    }
2329
2330    /** @see LanguageConnectionContext#getRunTimeStatisticsObject */
2331    public RunTimeStatistics getRunTimeStatisticsObject()
2332    {
2333        return runTimeStatisticsObject;
2334    }
2335
2336
2337    /**
2338      * Reports how many statement levels deep we are.
2339      *
2340      * @return a statement level >= OUTERMOST_STATEMENT
2341      */

2342    public int getStatementDepth()
2343    { return statementDepth; }
2344
2345    /**
2346     * @see LanguageConnectionContext#isIsolationLevelSetUsingSQLorJDBC
2347     */

2348    public boolean isIsolationLevelSetUsingSQLorJDBC()
2349    {
2350        return isolationLevelSetUsingSQLorJDBC;
2351    }
2352
2353    /**
2354     * @see LanguageConnectionContext#resetIsolationLevelFlagUsedForSQLandJDBC
2355     */

2356    public void resetIsolationLevelFlagUsedForSQLandJDBC()
2357    {
2358        isolationLevelSetUsingSQLorJDBC = false;
2359    }
2360
2361    /**
2362     * @see LanguageConnectionContext#setIsolationLevel
2363     */

2364    public void setIsolationLevel(int isolationLevel) throws StandardException
2365    {
2366        StatementContext stmtCtxt = getStatementContext();
2367        if (stmtCtxt!= null && stmtCtxt.inTrigger())
2368            throw StandardException.newException(SQLState.LANG_NO_XACT_IN_TRIGGER, getTriggerExecutionContext().toString());
2369
2370        // find if there are any held cursors from previous isolation level.
2371
// if yes, then throw an exception that isolation change not allowed until
2372
// the held cursors are closed.
2373
// I had to move this check outside of transaction idle check because if a
2374
// transactions creates held cursors and commits the transaction, then
2375
// there still would be held cursors but the transaction state would be idle.
2376
// In order to check the above mentioned case, the held cursor check
2377
// shouldn't rely on transaction state.
2378
if (this.isolationLevel != isolationLevel)
2379        {
2380            if (!verifyAllHeldResultSetsAreClosed())
2381            {
2382                throw StandardException.newException(SQLState.LANG_CANT_CHANGE_ISOLATION_HOLD_CURSOR);
2383            }
2384        }
2385
2386        /* Commit and set to new isolation level.
2387         * NOTE: We commit first in case there's some kind
2388         * of error, like can't commit within a server side jdbc call.
2389         */

2390        TransactionController tc = getTransactionExecute();
2391        if (!tc.isIdle())
2392        {
2393            // If this transaction is in progress, commit it.
2394
// However, do not allow commit to happen if this is a global
2395
// transaction.
2396
if (tc.isGlobal())
2397                throw StandardException.newException(SQLState.LANG_NO_SET_TRAN_ISO_IN_GLOBAL_CONNECTION);
2398
2399            userCommit();
2400        }
2401        this.isolationLevel = isolationLevel;
2402        this.isolationLevelExplicitlySet = true;
2403        this.isolationLevelSetUsingSQLorJDBC = true;
2404    }
2405
2406    /**
2407     * @see LanguageConnectionContext#getCurrentIsolationLevel
2408     */

2409    public int getCurrentIsolationLevel()
2410    {
2411        return (isolationLevel == ExecutionContext.UNSPECIFIED_ISOLATION_LEVEL) ? defaultIsolationLevel : isolationLevel;
2412    }
2413
2414    /**
2415     * @see LanguageConnectionContext#getCurrentIsolationLevel
2416     */

2417    public String JavaDoc getCurrentIsolationLevelStr()
2418    {
2419        if( isolationLevel >= 0 && isolationLevel < ExecutionContext.CS_TO_SQL_ISOLATION_MAP.length)
2420            return ExecutionContext.CS_TO_SQL_ISOLATION_MAP[ isolationLevel][0];
2421        return ExecutionContext.CS_TO_SQL_ISOLATION_MAP[ ExecutionContext.UNSPECIFIED_ISOLATION_LEVEL][0];
2422    }
2423
2424    /**
2425     * @see LanguageConnectionContext#setPrepareIsolationLevel
2426     */

2427    public void setPrepareIsolationLevel(int level)
2428    {
2429            prepareIsolationLevel = level;
2430    }
2431
2432    /**
2433     * @see LanguageConnectionContext#getPrepareIsolationLevel
2434     */

2435    public int getPrepareIsolationLevel()
2436    {
2437        if (!isolationLevelExplicitlySet)
2438            return prepareIsolationLevel;
2439        else
2440            return ExecutionContext.UNSPECIFIED_ISOLATION_LEVEL;
2441    }
2442
2443    /**
2444     * @see LanguageConnectionContext#getExecutionContext
2445     */

2446    public ExecutionContext getExecutionContext()
2447    {
2448        return (ExecutionContext) getContextManager().getContext(ExecutionContext.CONTEXT_ID);
2449    }
2450
2451    /**
2452     * @see LanguageConnectionContext#getStatementContext
2453     */

2454    public StatementContext getStatementContext()
2455    {
2456        return (StatementContext) getContextManager().getContext(org.apache.derby.iapi.reference.ContextId.LANG_STATEMENT);
2457    }
2458
2459    /**
2460     * @see LanguageConnectionContext#setOptimizerTrace
2461     */

2462    public boolean setOptimizerTrace(boolean onOrOff)
2463    {
2464        if (of == null)
2465        {
2466            return false;
2467        }
2468        if (! of.supportsOptimizerTrace())
2469        {
2470            return false;
2471        }
2472        optimizerTrace = onOrOff;
2473        return true;
2474    }
2475
2476    /**
2477     * @see LanguageConnectionContext#getOptimizerTrace
2478     */

2479    public boolean getOptimizerTrace()
2480    {
2481        return optimizerTrace;
2482    }
2483
2484    /**
2485     * @see LanguageConnectionContext#setOptimizerTraceHtml
2486     */

2487    public boolean setOptimizerTraceHtml(boolean onOrOff)
2488    {
2489        if (of == null)
2490        {
2491            return false;
2492        }
2493        if (! of.supportsOptimizerTrace())
2494        {
2495            return false;
2496        }
2497        optimizerTraceHtml = onOrOff;
2498        return true;
2499    }
2500
2501    /**
2502     * @see LanguageConnectionContext#getOptimizerTraceHtml
2503     */

2504    public boolean getOptimizerTraceHtml()
2505    {
2506        return optimizerTraceHtml;
2507    }
2508
2509    /**
2510     * @see LanguageConnectionContext#setOptimizerTraceOutput
2511     */

2512    public void setOptimizerTraceOutput(String JavaDoc startingText)
2513    {
2514        if (optimizerTrace)
2515        {
2516            lastOptimizerTraceOutput = optimizerTraceOutput;
2517            optimizerTraceOutput = startingText;
2518        }
2519    }
2520
2521    /**
2522     * @see LanguageConnectionContext#appendOptimizerTraceOutput
2523     */

2524    public void appendOptimizerTraceOutput(String JavaDoc output)
2525    {
2526        optimizerTraceOutput =
2527            (optimizerTraceOutput == null) ? output : optimizerTraceOutput + output;
2528    }
2529
2530    /**
2531     * @see LanguageConnectionContext#getOptimizerTraceOutput
2532     */

2533    public String JavaDoc getOptimizerTraceOutput()
2534    {
2535        return lastOptimizerTraceOutput;
2536    }
2537
2538    /**
2539      * Reports whether there is any outstanding work in the transaction.
2540      *
2541      * @return true if there is outstanding work in the transaction
2542      * false otherwise
2543      */

2544    public boolean isTransactionPristine()
2545    {
2546        return getTransactionExecute().isPristine();
2547    }
2548
2549    /**
2550      * Get the lock handle for the current transaction.
2551      *
2552      * @param lockScope SINGLE_TRANSACTION_LOCK or MULTI_TRANSACTION_LOCK
2553      *
2554      * @return the current lock handle
2555      *
2556      * @exception StandardException thrown if something goes wrong
2557      */

2558    public Object JavaDoc getLockObject( int lockScope ) throws StandardException
2559    {
2560        switch( lockScope )
2561        {
2562            case SINGLE_TRANSACTION_LOCK:
2563                return getTransactionExecute().getLockObject();
2564
2565            case MULTI_TRANSACTION_LOCK:
2566                return new Object JavaDoc();
2567
2568            default:
2569                throw StandardException.newException(SQLState.NOT_IMPLEMENTED);
2570        }
2571    }
2572
2573    /**
2574     * Convert an identifier to the proper case for this connection. This method
2575     * is here to support the Plugin.
2576     *
2577     * @param id an identifier string
2578     * @return the string converted to upper or lower case, as appropriate
2579     *
2580     * @exception StandardException thrown if something goes wrong
2581     */

2582    public String JavaDoc convertIdentifierCase( String JavaDoc id) throws StandardException
2583    {
2584        if( ANTI_ANSI_CASING == getIdentifierCasing())
2585            return StringUtil.SQLToLowerCase(id);
2586        else
2587            return StringUtil.SQLToUpperCase(id);
2588    }
2589    
2590    /**
2591      * Get casing for delimited identifiers. This feature is here to
2592      * support the Plugin.
2593      *
2594      * @return ANSI_CASING or ANTI_ANSI_CASING.
2595      *
2596      * @exception StandardException thrown if something goes wrong
2597      */

2598    public int getIdentifierCasing() throws StandardException
2599    {
2600        if( UNKNOWN_CASING == identifierCasing)
2601        {
2602            identifierCasing = ANSI_CASING;
2603        }
2604        return identifierCasing;
2605    }
2606
2607    //
2608
// Context interface
2609
//
2610
/**
2611        If worse than a transaction error, everything goes; we
2612        rely on other contexts to kill the context manager
2613        for this session.
2614        <p>
2615        If a transaction error, act like we saw a rollback.
2616        <p>
2617        If more severe or a java error, the outer cleanup
2618        will shutdown the connection, so we don't have to clean up.
2619        <p>
2620        REMIND: connection should throw out all contexts and start
2621        over when the connection is closed... perhaps by throwing
2622        out the context manager?
2623        <p>
2624        REVISIT: If statement error, should we do anything?
2625        <P>
2626        Since the access manager's own context takes care of its own
2627        resources on errors, there is nothing that this context has
2628        to do with the transaction controller.
2629
2630        @exception StandardException thrown on error. REVISIT: don't want
2631        cleanupOnError's to throw exceptions.
2632     */

2633    public void cleanupOnError(Throwable JavaDoc error) throws StandardException {
2634
2635        /*
2636        ** If it isn't a StandardException, then assume
2637        ** session severity. It is probably an unexpected
2638        ** java error somewhere in the language.
2639        ** Store layer treats JVM error as session severity,
2640        ** hence to be consistent and to avoid getting rawstore
2641        ** protocol violation errors, we treat java errors here
2642        ** to be of session severity.
2643        */

2644
2645        int severity = (error instanceof StandardException) ?
2646            ((StandardException) error).getSeverity() :
2647            ExceptionSeverity.SESSION_SEVERITY;
2648 
2649        if (statementContexts[0] != null)
2650        {
2651            statementContexts[0].clearInUse();
2652            
2653            // Force the StatementContext that's normally
2654
// left on the stack for optimization to be popped
2655
// when the session is closed. Ensures full cleanup
2656
// and no hanging refrences in the ContextManager.
2657
if (severity >= ExceptionSeverity.SESSION_SEVERITY)
2658                statementContexts[0].popMe();
2659        }
2660        if (statementContexts[1] != null)
2661        {
2662            statementContexts[1].clearInUse();
2663        }
2664
2665        // closing the activations closes all the open cursors.
2666
// the activations are, for all intents and purposes, the
2667
// cursors.
2668
if (severity >= ExceptionSeverity.SESSION_SEVERITY)
2669        {
2670            for (int i = acts.size() - 1; i >= 0; i--) {
2671                // it maybe the case that a reset()/close() ends up closing
2672
// one or more activation leaving our index beyond
2673
// the end of the array
2674
if (i >= acts.size())
2675                    continue;
2676                Activation a = (Activation) acts.elementAt(i);
2677                a.reset();
2678                a.close();
2679            }
2680                       
2681            popMe();
2682        }
2683
2684        /*
2685        ** We have some global state that we need
2686        ** to clean up no matter what. Be sure
2687        ** to do so.
2688        */

2689        else if (severity >= ExceptionSeverity.TRANSACTION_SEVERITY)
2690        {
2691            internalRollback();
2692        }
2693    }
2694
2695    /**
2696     * @see Context#isLastHandler
2697     */

2698    public boolean isLastHandler(int severity)
2699    {
2700        return false;
2701    }
2702
2703    //
2704
// class implementation
2705
//
2706

2707
2708    /**
2709        resets all open activations, to close their result sets.
2710        Also cleans up (close()) activations that have been
2711        marked as unused during statement finalization.
2712
2713        @exception StandardException thrown on failure
2714     */

2715    private void resetActivations(boolean andClose) throws StandardException {
2716
2717        // don't use an enumeration as the activation may remove
2718
// itself from the list, thus invalidating the Enumeration
2719
for (int i = acts.size() - 1; i >= 0; i--) {
2720
2721            // it maybe the case that a reset() ends up closing
2722
// one or more activation leaving our index beyond
2723
// the end of the array
2724
if (i >= acts.size())
2725                continue;
2726
2727            Activation a = (Activation) acts.elementAt(i);
2728            /*
2729            ** andClose true means we are here for rollback.
2730            ** In case of rollback, we don't care for holding
2731            ** cursors and that's why I am resetting holdability
2732            ** to false for all activations just before rollback
2733            */

2734            if (andClose)
2735                a.setResultSetHoldability(false);
2736
2737            /*
2738            ** Look for stale activations. Activations are
2739            ** marked as unused during statement finalization.
2740            ** Here, we sweep and remove this inactive ones.
2741            */

2742            if (!a.isInUse())
2743            {
2744                a.close();
2745                continue;
2746            }
2747
2748            a.reset();
2749
2750            // Only invalidate statements if we performed DDL.
2751
if (andClose && dataDictionaryInWriteMode()) {
2752                ExecPreparedStatement ps = a.getPreparedStatement();
2753                if (ps != null) {
2754                    ps.makeInvalid(DependencyManager.ROLLBACK, this);
2755                }
2756            }
2757        }
2758    }
2759
2760    /**
2761        Finish the data dictionary transaction, if any.
2762
2763        @exception StandardException Thrown on error
2764     */

2765    private void finishDDTransaction() throws StandardException {
2766
2767        /* Was the data dictionary put into write mode? */
2768        if (ddWriteMode) {
2769            DataDictionary dd = getDataDictionary();
2770
2771            /* Tell the data dictionary that the transaction is finished */
2772            dd.transactionFinished();
2773
2774            /* The data dictionary isn't in write mode any more */
2775            ddWriteMode = false;
2776        }
2777    }
2778
2779    ////////////////////////////////////////////////////////////////////
2780
//
2781
// MINIONS
2782
//
2783
////////////////////////////////////////////////////////////////////
2784

2785    /**
2786      * Increments the statement depth.
2787      */

2788    private void incrementStatementDepth() { statementDepth++; }
2789
2790    /**
2791      * Decrements the statement depth
2792      */

2793    private void decrementStatementDepth()
2794    {
2795        statementDepth--;
2796    }
2797
2798    /**
2799      * Resets the statementDepth.
2800      */

2801    protected void resetStatementDepth()
2802    {
2803        statementDepth = 0;
2804    }
2805
2806    /**
2807     * Get the name of the system schema.
2808     *
2809     * @return A String containing the name of the system schema.
2810     * @throws StandardException
2811     */

2812    public String JavaDoc getSystemSchemaName() throws StandardException
2813    {
2814        return convertIdentifierCase( SchemaDescriptor.STD_SYSTEM_SCHEMA_NAME);
2815    }
2816    
2817    /**
2818     * Get the name of the SYSIBM schema.
2819     *
2820     * @return A String containing the name of the SYSIBM schema.
2821     * @throws StandardException
2822     */

2823    public String JavaDoc getSysIBMSchemaName() throws StandardException
2824    {
2825        return convertIdentifierCase( SchemaDescriptor.IBM_SYSTEM_SCHEMA_NAME);
2826    }
2827
2828    /**
2829     * Get the name of the SYSCS_DIAG schema.
2830     *
2831     * @return A String containing the name of the SYSIBM schema.
2832     * @throws StandardException
2833     */

2834    public String JavaDoc getSystemDiagSchemaName() throws StandardException
2835    {
2836        return(
2837            convertIdentifierCase(
2838                SchemaDescriptor.STD_SYSTEM_DIAG_SCHEMA_NAME));
2839    }
2840
2841    /**
2842     * Get the name of the SYSCS_UTIL schema.
2843     *
2844     * @return A String containing the name of the SYSIBM schema.
2845     * @throws StandardException
2846     */

2847    public String JavaDoc getSystemUtilSchemaName() throws StandardException
2848    {
2849        return(
2850            convertIdentifierCase(
2851                SchemaDescriptor.STD_SYSTEM_UTIL_SCHEMA_NAME));
2852    }
2853    
2854    /**
2855     * Get the declared global temporary tables schema name.
2856     *
2857     * @return a String containing the declared global temporary tables schema name.
2858     * @throws StandardException
2859     */

2860    public String JavaDoc getDeclaredGlobalTemporaryTablesSchemaName() throws StandardException
2861    {
2862        return convertIdentifierCase( SchemaDescriptor.STD_DECLARED_GLOBAL_TEMPORARY_TABLES_SCHEMA_NAME);
2863    }
2864
2865    public DataDictionary getDataDictionary()
2866    {
2867        DataDictionaryContext ddc =
2868            (DataDictionaryContext) getContextManager().getContext(DataDictionaryContext.CONTEXT_ID);
2869
2870        if (ddc != null)
2871        {
2872            return ddc.getDataDictionary();
2873        }
2874        else
2875        {
2876            return null;
2877        }
2878    }
2879
2880    /**
2881      @see LanguageConnectionContext#setReadOnly
2882      @exception StandardException The operation is disallowed.
2883      */

2884    public void setReadOnly(boolean on) throws StandardException
2885    {
2886        if (!tran.isPristine())
2887            throw StandardException.newException(SQLState.AUTH_SET_CONNECTION_READ_ONLY_IN_ACTIVE_XACT);
2888        authorizer.setReadOnlyConnection(on,true);
2889    }
2890
2891    /**
2892      @see LanguageConnectionContext#isReadOnly
2893      */

2894    public boolean isReadOnly()
2895    {
2896        return authorizer.isReadOnlyConnection();
2897    }
2898
2899    /**
2900      @see LanguageConnectionContext#getAuthorizer
2901     */

2902    public Authorizer getAuthorizer()
2903    {
2904        return authorizer;
2905    }
2906
2907    /** @see LanguageConnectionContext#getAccessFactory */
2908    public AccessFactory getAccessFactory()
2909    {
2910        return af;
2911    }
2912
2913    /**
2914     * Implements ConnectionInfo.lastAutoincrementValue.
2915     * lastAutoincrementValue searches for the last autoincrement value inserted
2916     * into a column specified by the user. The search for the "last" value
2917     * supports nesting levels caused by triggers (Only triggers cause nesting,
2918     * not server side JDBC).
2919     * If lastAutoincrementValue is called from within a trigger, the search
2920     * space for ai-values are those values that are inserted by this trigger as
2921     * well as previous triggers;
2922     * i.e if a SQL statement fires trigger T1, which in turn does something
2923     * that fires trigger t2, and if lastAutoincrementValue is called from
2924     * within t2, then autoincrement values genereated by t1 are visible to
2925     * it. By the same logic, if it is called from within t1, then it does not
2926     * see values inserted by t2.
2927     *
2928     * @see LanguageConnectionContext#lastAutoincrementValue
2929     * @see org.apache.derby.iapi.db.ConnectionInfo#lastAutoincrementValue
2930     */

2931    public Long JavaDoc lastAutoincrementValue(String JavaDoc schemaName, String JavaDoc tableName,
2932                                       String JavaDoc columnName)
2933    {
2934        String JavaDoc aiKey = AutoincrementCounter.makeIdentity(schemaName, tableName, columnName);
2935        
2936        int size = triggerExecutionContexts.size();
2937        // System.out.println(" searching for " + aiKey);
2938
for (int i = size - 1; i >= 0; i--)
2939        {
2940            // first loop through triggers.
2941
InternalTriggerExecutionContext itec =
2942                (InternalTriggerExecutionContext)triggerExecutionContexts.elementAt(i);
2943            Long JavaDoc value = itec.getAutoincrementValue(aiKey);
2944            if (value == null)
2945                continue;
2946
2947            return value;
2948        }
2949        if (autoincrementHT == null)
2950            return null;
2951        return (Long JavaDoc)autoincrementHT.get(aiKey);
2952    }
2953
2954    /**
2955     * @see LanguageConnectionContext#setAutoincrementUpdate
2956     */

2957    public void setAutoincrementUpdate(boolean flag)
2958    {
2959        autoincrementUpdate = flag;
2960    }
2961    
2962    /**
2963     * @see LanguageConnectionContext#getAutoincrementUpdate
2964     */

2965    public boolean getAutoincrementUpdate()
2966    {
2967        return autoincrementUpdate;
2968    }
2969    
2970    /**
2971     * @see LanguageConnectionContext#autoincrementCreateCounter
2972     */

2973    public void autoincrementCreateCounter(String JavaDoc s, String JavaDoc t, String JavaDoc c,
2974                                           Long JavaDoc initialValue, long increment,
2975                                           int position)
2976    {
2977        String JavaDoc key = AutoincrementCounter.makeIdentity(s,t,c);
2978        
2979        if (autoincrementCacheHashtable == null)
2980        {
2981            autoincrementCacheHashtable = new Hashtable JavaDoc();
2982        }
2983
2984        AutoincrementCounter aic =
2985            (AutoincrementCounter)autoincrementCacheHashtable.get(key);
2986        if (aic != null)
2987        {
2988            if (SanityManager.DEBUG)
2989            {
2990                SanityManager.THROWASSERT(
2991                              "Autoincrement Counter already exists:" + key);
2992            }
2993            return;
2994        }
2995        
2996        aic = new AutoincrementCounter(initialValue,
2997                                       increment, 0, s, t, c, position);
2998        autoincrementCacheHashtable.put(key, aic);
2999    }
3000
3001    /**
3002     * returns the <b>next</b> value to be inserted into an autoincrement col.
3003     * This is used internally by the system to generate autoincrement values
3004     * which are going to be inserted into a autoincrement column. This is
3005     * used when as autoincrement column is added to a table by an alter
3006     * table statemenet and during bulk insert.
3007     *
3008     * @param schemaName
3009     * @param tableName
3010     * @param columnName identify the column uniquely in the system.
3011     */

3012    public long nextAutoincrementValue(String JavaDoc schemaName, String JavaDoc tableName,
3013                                       String JavaDoc columnName)
3014            throws StandardException
3015    {
3016        String JavaDoc key = AutoincrementCounter.makeIdentity(schemaName,tableName,
3017                                                       columnName);
3018        
3019        AutoincrementCounter aic =
3020            (AutoincrementCounter)autoincrementCacheHashtable.get(key);
3021
3022        if (aic == null)
3023        {
3024            if (SanityManager.DEBUG)
3025            {
3026                SanityManager.THROWASSERT("counter doesn't exist:" + key);
3027            }
3028            return 0;
3029        }
3030        else
3031        {
3032            return aic.update();
3033        }
3034    }
3035    
3036    /**
3037     * Flush the cache of autoincrement values being kept by the lcc.
3038     * This will result in the autoincrement values being written to the
3039     * SYSCOLUMNS table as well as the mapping used by lastAutoincrementValue
3040     *
3041     * @exception StandardException thrown on error.
3042     * @see LanguageConnectionContext#lastAutoincrementValue
3043     * @see GenericLanguageConnectionContext#lastAutoincrementValue
3044     * @see org.apache.derby.iapi.db.ConnectionInfo#lastAutoincrementValue
3045     */

3046    public void autoincrementFlushCache(UUID tableUUID)
3047        throws StandardException
3048    {
3049        if (autoincrementCacheHashtable == null)
3050            return;
3051
3052        if (autoincrementHT == null)
3053            autoincrementHT = new Hashtable JavaDoc();
3054
3055        DataDictionary dd = getDataDictionary();
3056        for (Enumeration JavaDoc e = autoincrementCacheHashtable.keys();
3057             e.hasMoreElements(); )
3058        {
3059            Object JavaDoc key = e.nextElement();
3060            AutoincrementCounter aic =
3061                (AutoincrementCounter)autoincrementCacheHashtable.get(key);
3062            Long JavaDoc value = aic.getCurrentValue();
3063            aic.flushToDisk(getTransactionExecute(), dd, tableUUID);
3064            if (value != null)
3065            {
3066                autoincrementHT.put(key, value);
3067            }
3068        }
3069        autoincrementCacheHashtable.clear();
3070    }
3071
3072    /**
3073     * Copies an existing hashtable of autoincrement mappings
3074     * into autoincrementHT, the cache of autoincrement values
3075     * kept in the languageconnectioncontext.
3076     */

3077    public void copyHashtableToAIHT(Hashtable JavaDoc from)
3078    {
3079        if (from.isEmpty())
3080            return;
3081        if (autoincrementHT == null)
3082            autoincrementHT = new Hashtable JavaDoc();
3083        
3084        for (Enumeration JavaDoc e = from.keys(); e.hasMoreElements(); )
3085        {
3086            Object JavaDoc key = e.nextElement();
3087            Object JavaDoc value = from.get(key);
3088            autoincrementHT.put(key, value);
3089        }
3090    }
3091    
3092    /**
3093     * @see LanguageConnectionContext#getInstanceNumber
3094     */

3095    public int getInstanceNumber()
3096    {
3097        return instanceNumber;
3098    }
3099
3100    /**
3101     * @see LanguageConnectionContext#getDrdaID
3102     */

3103    public String JavaDoc getDrdaID()
3104    {
3105        return drdaID;
3106    }
3107
3108    /**
3109     * @see LanguageConnectionContext#setDrdaID
3110     */

3111    public void setDrdaID(String JavaDoc drdaID)
3112    {
3113        this.drdaID = drdaID;
3114    }
3115
3116    /**
3117     * @see LanguageConnectionContext#getDbname
3118     */

3119    public String JavaDoc getDbname()
3120    {
3121        return dbname;
3122    }
3123
3124    /**
3125     * @see LanguageConnectionContext#getLastActivation
3126     */

3127    public Activation getLastActivation()
3128    {
3129        return (Activation)acts.lastElement();
3130    }
3131
3132    public StringBuffer JavaDoc appendErrorInfo() {
3133
3134        TransactionController tc = getTransactionExecute();
3135        if (tc == null)
3136            return null;
3137
3138        StringBuffer JavaDoc sb = new StringBuffer JavaDoc(200);
3139
3140        sb.append(LanguageConnectionContext.xidStr);
3141        sb.append(tc.getTransactionIdString());
3142        sb.append("), ");
3143
3144        sb.append(LanguageConnectionContext.lccStr);
3145        sb.append(Integer.toString(getInstanceNumber()));
3146        sb.append("), ");
3147
3148        sb.append(LanguageConnectionContext.dbnameStr);
3149        sb.append(getDbname());
3150        sb.append("), ");
3151
3152        sb.append(LanguageConnectionContext.drdaStr);
3153        sb.append(getDrdaID());
3154        sb.append("), ");
3155
3156        return sb;
3157    }
3158}
3159
Popular Tags