KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > impl > sql > GenericStatement


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.GenericStatement
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;
23
24 import org.apache.derby.iapi.services.stream.HeaderPrintWriter;
25
26 import org.apache.derby.iapi.reference.JDBC20Translation;
27 import org.apache.derby.iapi.reference.JDBC30Translation;
28 import org.apache.derby.iapi.reference.SQLState;
29
30 import org.apache.derby.iapi.sql.Activation;
31 import org.apache.derby.iapi.types.DataTypeDescriptor;
32 import org.apache.derby.iapi.sql.ResultSet;
33 import org.apache.derby.iapi.sql.Statement;
34 import org.apache.derby.iapi.sql.PreparedStatement;
35 import org.apache.derby.iapi.sql.execute.ConstantAction;
36 import org.apache.derby.iapi.sql.execute.ExecutionContext;
37 import org.apache.derby.iapi.sql.execute.ExecPreparedStatement;
38 import org.apache.derby.iapi.sql.ParameterValueSet;
39
40 import org.apache.derby.iapi.sql.conn.LanguageConnectionFactory;
41 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
42 import org.apache.derby.iapi.sql.conn.StatementContext;
43
44 import org.apache.derby.iapi.sql.depend.Dependent;
45
46 import org.apache.derby.iapi.sql.compile.CompilerContext;
47 import org.apache.derby.iapi.sql.compile.NodeFactory;
48 import org.apache.derby.iapi.sql.compile.Parser;
49
50 import org.apache.derby.impl.sql.compile.QueryTreeNode;
51 import org.apache.derby.impl.sql.conn.GenericLanguageConnectionContext;
52
53 import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
54 import org.apache.derby.iapi.sql.dictionary.DataDictionaryContext;
55 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
56
57 import org.apache.derby.iapi.services.compiler.JavaFactory;
58 import org.apache.derby.iapi.services.uuid.UUIDFactory;
59 import org.apache.derby.iapi.util.ByteArray;
60
61 import org.apache.derby.iapi.error.StandardException;
62
63 import org.apache.derby.iapi.services.monitor.Monitor;
64
65 import org.apache.derby.iapi.services.context.Context;
66 import org.apache.derby.iapi.services.context.ContextService;
67 import org.apache.derby.iapi.services.context.ContextManager;
68 import org.apache.derby.iapi.services.sanity.SanityManager;
69
70 import org.apache.derby.iapi.services.loader.GeneratedClass;
71
72 import java.sql.Timestamp JavaDoc;
73 import java.sql.SQLWarning JavaDoc;
74
75 public class GenericStatement
76     implements Statement {
77
78     // these fields define the identity of the statement
79
private final SchemaDescriptor compilationSchema;
80     private final String JavaDoc statementText;
81         private final boolean isForReadOnly;
82     private int prepareIsolationLevel;
83     private GenericPreparedStatement preparedStmt;
84
85     /**
86      * Constructor for a Statement given the text of the statement in a String
87      * @param compilationSchema schema
88      * @param statementText The text of the statement
89      * @param isForReadOnly if the statement is opened with level CONCUR_READ_ONLY
90      */

91
92     public GenericStatement(SchemaDescriptor compilationSchema, String JavaDoc statementText, boolean isForReadOnly)
93     {
94         this.compilationSchema = compilationSchema;
95         this.statementText = statementText;
96         this.isForReadOnly = isForReadOnly;
97     }
98
99     /*
100      * Statement interface
101      */

102
103     
104     /* RESOLVE: may need error checking, debugging code here */
105     public PreparedStatement prepare(LanguageConnectionContext lcc) throws StandardException
106     {
107         /*
108         ** Note: don't reset state since this might be
109         ** a recompilation of an already prepared statement.
110         */

111         return prepMinion(lcc, true, (Object JavaDoc[]) null, (SchemaDescriptor) null, false);
112     }
113     public PreparedStatement prepare(LanguageConnectionContext lcc, boolean forMetaData) throws StandardException
114     {
115         /*
116         ** Note: don't reset state since this might be
117         ** a recompilation of an already prepared statement.
118         */

119         return prepMinion(lcc, true, (Object JavaDoc[]) null, (SchemaDescriptor) null, forMetaData);
120     }
121
122     private PreparedStatement prepMinion(LanguageConnectionContext lcc, boolean cacheMe, Object JavaDoc[] paramDefaults,
123         SchemaDescriptor spsSchema, boolean internalSQL)
124         throws StandardException
125     {
126                           
127         long beginTime = 0;
128         long parseTime = 0;
129         long bindTime = 0;
130         long optimizeTime = 0;
131         long generateTime = 0;
132         Timestamp JavaDoc beginTimestamp = null;
133         Timestamp JavaDoc endTimestamp = null;
134         StatementContext statementContext = null;
135
136         // verify it isn't already prepared...
137
// if it is, and is valid, simply return that tree.
138
// if it is invalid, we will recompile now.
139
if (preparedStmt != null) {
140             if (preparedStmt.upToDate())
141                 return preparedStmt;
142         }
143
144         // Clear the optimizer trace from the last statement
145
if (lcc.getOptimizerTrace())
146             lcc.setOptimizerTraceOutput(getSource() + "\n");
147
148         beginTime = getCurrentTimeMillis(lcc);
149         /* beginTimestamp only meaningful if beginTime is meaningful.
150          * beginTime is meaningful if STATISTICS TIMING is ON.
151          */

152         if (beginTime != 0)
153         {
154             beginTimestamp = new Timestamp JavaDoc(beginTime);
155         }
156
157         /** set the prepare Isolaton from the LanguageConnectionContext now as
158          * we need to consider it in caching decisions
159          */

160         prepareIsolationLevel = lcc.getPrepareIsolationLevel();
161
162         /* a note on statement caching:
163          *
164          * A GenericPreparedStatement (GPS) is only added it to the cache if the
165          * parameter cacheMe is set to TRUE when the GPS is created.
166          *
167          * Earlier only CacheStatement (CS) looked in the statement cache for a
168          * prepared statement when prepare was called. Now the functionality
169          * of CS has been folded into GenericStatement (GS). So we search the
170          * cache for an existing PreparedStatement only when cacheMe is TRUE.
171          * i.e if the user calls prepare with cacheMe set to TRUE:
172          * then we
173          * a) look for the prepared statement in the cache.
174          * b) add the prepared statement to the cache.
175          *
176          * In cases where the statement cache has been disabled (by setting the
177          * relevant cloudscape property) then the value of cacheMe is irrelevant.
178          */

179         boolean foundInCache = false;
180         if (preparedStmt == null)
181         {
182             if (cacheMe)
183                 preparedStmt = (GenericPreparedStatement)((GenericLanguageConnectionContext)lcc).lookupStatement(this);
184
185             if (preparedStmt == null)
186             {
187                 preparedStmt = new GenericPreparedStatement(this);
188             }
189             else
190             {
191                 foundInCache = true;
192             }
193         }
194
195         // if anyone else also has this prepared statement,
196
// we don't want them trying to compile with it while
197
// we are. So, we synchronize on it and re-check
198
// its validity first.
199
// this is a no-op if and until there is a central
200
// cache of prepared statement objects...
201
synchronized (preparedStmt)
202         {
203
204             for (;;) {
205
206                 if (foundInCache) {
207                     if (preparedStmt.referencesSessionSchema()) {
208                         // cannot use this state since it is private to a connection.
209
// switch to a new statement.
210
foundInCache = false;
211                         preparedStmt = new GenericPreparedStatement(this);
212                         break;
213                     }
214                 }
215
216                 // did it get updated while we waited for the lock on it?
217
if (preparedStmt.upToDate()) {
218                     return preparedStmt;
219                 }
220
221                 if (!preparedStmt.compilingStatement) {
222                     break;
223                 }
224
225                 try {
226                     preparedStmt.wait();
227                 } catch (InterruptedException JavaDoc ie) {
228                     throw StandardException.interrupt(ie);
229                 }
230             }
231
232             preparedStmt.compilingStatement = true;
233             preparedStmt.setActivationClass(null);
234         }
235
236         try {
237
238             HeaderPrintWriter istream = lcc.getLogStatementText() ? Monitor.getStream() : null;
239
240             /*
241             ** For stored prepared statements, we want all
242             ** errors, etc in the context of the underlying
243             ** EXECUTE STATEMENT statement, so don't push/pop
244             ** another statement context unless we don't have
245             ** one. We won't have one if it is an internal
246             ** SPS (e.g. jdbcmetadata).
247             */

248             if (!preparedStmt.isStorable() || lcc.getStatementDepth() == 0)
249             {
250                 // since this is for compilation only, set atomic
251
// param to true and timeout param to 0
252
statementContext = lcc.pushStatementContext(true, isForReadOnly, getSource(),
253                                                             null, false, 0L);
254             }
255
256
257
258             /*
259             ** RESOLVE: we may ultimately wish to pass in
260             ** whether we are a jdbc metadata query or not to
261             ** get the CompilerContext to make the createDependency()
262             ** call a noop.
263             */

264             CompilerContext cc = lcc.pushCompilerContext(compilationSchema);
265             
266             if (prepareIsolationLevel !=
267                 ExecutionContext.UNSPECIFIED_ISOLATION_LEVEL)
268             {
269                 cc.setScanIsolationLevel(prepareIsolationLevel);
270             }
271
272
273             // Look for stored statements that are in a system schema
274
// and with a match compilation schema. If so, allow them
275
// to compile using internal SQL constructs.
276

277             if (internalSQL ||
278                 (spsSchema != null) && (spsSchema.isSystemSchema()) &&
279                     (spsSchema.equals(compilationSchema))) {
280                         cc.setReliability(CompilerContext.INTERNAL_SQL_LEGAL);
281             }
282
283             try
284             {
285                 // Statement logging if lcc.getLogStatementText() is true
286
if (istream != null)
287                 {
288                     String JavaDoc xactId = lcc.getTransactionExecute().getActiveStateTxIdString();
289                     istream.printlnWithHeader(LanguageConnectionContext.xidStr +
290                                               xactId +
291                                               "), " +
292                                               LanguageConnectionContext.lccStr +
293                                                   lcc.getInstanceNumber() +
294                                               "), " +
295                                               LanguageConnectionContext.dbnameStr +
296                                                   lcc.getDbname() +
297                                               "), " +
298                                               LanguageConnectionContext.drdaStr +
299                                                   lcc.getDrdaID() +
300                                               "), Begin compiling prepared statement: " +
301                                               getSource() +
302                                               " :End prepared statement");
303                 }
304
305                 Parser p = cc.getParser();
306
307                 cc.setCurrentDependent(preparedStmt);
308
309                 //Only top level statements go through here, nested statement
310
//will invoke this method from other places
311
QueryTreeNode qt = p.parseStatement(statementText, paramDefaults);
312
313                 parseTime = getCurrentTimeMillis(lcc);
314
315                 if (SanityManager.DEBUG)
316                 {
317                     if (SanityManager.DEBUG_ON("DumpParseTree"))
318                     {
319                         qt.treePrint();
320                     }
321
322                     if (SanityManager.DEBUG_ON("StopAfterParsing"))
323                     {
324                         throw StandardException.newException(SQLState.LANG_STOP_AFTER_PARSING);
325                     }
326                 }
327
328                 /*
329                 ** Tell the data dictionary that we are about to do
330                 ** a bunch of "get" operations that must be consistent with
331                 ** each other.
332                 */

333                 
334                 DataDictionary dataDictionary = lcc.getDataDictionary();
335
336                 int ddMode = dataDictionary == null ? 0 : dataDictionary.startReading(lcc);
337
338                 try
339                 {
340                     // start a nested transaction -- all locks acquired by bind
341
// and optimize will be released when we end the nested
342
// transaction.
343
lcc.beginNestedTransaction(true);
344
345                     qt = qt.bind();
346                     bindTime = getCurrentTimeMillis(lcc);
347
348                     if (SanityManager.DEBUG)
349                     {
350                         if (SanityManager.DEBUG_ON("DumpBindTree"))
351                         {
352                             qt.treePrint();
353                         }
354
355                         if (SanityManager.DEBUG_ON("StopAfterBinding")) {
356                             throw StandardException.newException(SQLState.LANG_STOP_AFTER_BINDING);
357                         }
358                     }
359
360                     //Derby424 - In order to avoid caching select statements referencing
361
// any SESSION schema objects (including statements referencing views
362
// in SESSION schema), we need to do the SESSION schema object check
363
// here.
364
//a specific eg for statement referencing a view in SESSION schema
365
//CREATE TABLE t28A (c28 int)
366
//INSERT INTO t28A VALUES (280),(281)
367
//CREATE VIEW SESSION.t28v1 as select * from t28A
368
//SELECT * from SESSION.t28v1 should show contents of view and we
369
// should not cache this statement because a user can later define
370
// a global temporary table with the same name as the view name.
371
//Following demonstrates that
372
//DECLARE GLOBAL TEMPORARY TABLE SESSION.t28v1(c21 int, c22 int) not
373
// logged
374
//INSERT INTO SESSION.t28v1 VALUES (280,1),(281,2)
375
//SELECT * from SESSION.t28v1 should show contents of global temporary
376
//table and not the view. Since this select statement was not cached
377
// earlier, it will be compiled again and will go to global temporary
378
// table to fetch data. This plan will not be cached either because
379
// select statement is using SESSION schema object.
380
//
381
//Following if statement makes sure that if the statement is
382
// referencing SESSION schema objects, then we do not want to cache it.
383
// We will remove the entry that was made into the cache for
384
//this statement at the beginning of the compile phase.
385
//The reason we do this check here rather than later in the compile
386
// phase is because for a view, later on, we loose the information that
387
// it was referencing SESSION schema because the reference
388
//view gets replaced with the actual view definition. Right after
389
// binding, we still have the information on the view and that is why
390
// we do the check here.
391
if (preparedStmt.referencesSessionSchema(qt)) {
392                         if (foundInCache)
393                             ((GenericLanguageConnectionContext)lcc).removeStatement(this);
394                     }
395                     
396                     qt = qt.optimize();
397
398                     optimizeTime = getCurrentTimeMillis(lcc);
399
400                     // Statement logging if lcc.getLogStatementText() is true
401
if (istream != null)
402                     {
403                         String JavaDoc xactId = lcc.getTransactionExecute().getActiveStateTxIdString();
404                         istream.printlnWithHeader(LanguageConnectionContext.xidStr +
405                                                   xactId +
406                                                   "), " +
407                                                   LanguageConnectionContext.lccStr +
408                                                   lcc.getInstanceNumber() +
409                                                   "), " +
410                                                   LanguageConnectionContext.dbnameStr +
411                                                   lcc.getDbname() +
412                                                   "), " +
413                                                   LanguageConnectionContext.drdaStr +
414                                                   lcc.getDrdaID() +
415                                                   "), End compiling prepared statement: " +
416                                                   getSource() +
417                                                   " :End prepared statement");
418                     }
419                 }
420
421                 catch (StandardException se)
422                 {
423                     lcc.commitNestedTransaction();
424
425                     // Statement logging if lcc.getLogStatementText() is true
426
if (istream != null)
427                     {
428                         String JavaDoc xactId = lcc.getTransactionExecute().getActiveStateTxIdString();
429                         istream.printlnWithHeader(LanguageConnectionContext.xidStr +
430                                                   xactId +
431                                                   "), " +
432                                                   LanguageConnectionContext.lccStr +
433                                                   lcc.getInstanceNumber() +
434                                                   "), " +
435                                                   LanguageConnectionContext.dbnameStr +
436                                                   lcc.getDbname() +
437                                                   "), " +
438                                                   LanguageConnectionContext.drdaStr +
439                                                   lcc.getDrdaID() +
440                                                   "), Error compiling prepared statement: " +
441                                                   getSource() +
442                                                   " :End prepared statement");
443                     }
444                     throw se;
445                 }
446
447                 finally
448                 {
449                     /* Tell the data dictionary that we are done reading */
450                     if (dataDictionary != null)
451                     dataDictionary.doneReading(ddMode, lcc);
452                 }
453
454                 /* we need to move the commit of nested sub-transaction
455                  * after we mark PS valid, during compilation, we might need
456                  * to get some lock to synchronize with another thread's DDL
457                  * execution, in particular, the compilation of insert/update/
458                  * delete vs. create index/constraint (see Beetle 3976). We
459                  * can't release such lock until after we mark the PS valid.
460                  * Otherwise we would just erase the DDL's invalidation when
461                  * we mark it valid.
462                  */

463                 try // put in try block, commit sub-transaction if bad
464
{
465                     if (SanityManager.DEBUG)
466                     {
467                         if (SanityManager.DEBUG_ON("DumpOptimizedTree"))
468                         {
469                             qt.treePrint();
470                         }
471
472                         if (SanityManager.DEBUG_ON("StopAfterOptimizing"))
473                         {
474                             throw StandardException.newException(SQLState.LANG_STOP_AFTER_OPTIMIZING);
475                         }
476                     }
477
478                     GeneratedClass ac = qt.generate(preparedStmt.getByteCodeSaver());
479
480                     generateTime = getCurrentTimeMillis(lcc);
481                     /* endTimestamp only meaningful if generateTime is meaningful.
482                      * generateTime is meaningful if STATISTICS TIMING is ON.
483                      */

484                     if (generateTime != 0)
485                     {
486                         endTimestamp = new Timestamp JavaDoc(generateTime);
487                     }
488
489                     if (SanityManager.DEBUG)
490                     {
491                         if (SanityManager.DEBUG_ON("StopAfterGenerating"))
492                         {
493                             throw StandardException.newException(SQLState.LANG_STOP_AFTER_GENERATING);
494                         }
495                     }
496
497                     /*
498                         copy over the compile-time created objects
499                         to the prepared statement. This always happens
500                         at the end of a compile, so there is no need
501                         to erase the previous entries on a re-compile --
502                         this erases as it replaces. Set the activation
503                         class in case it came from a StorablePreparedStatement
504                     */

505                     preparedStmt.setConstantAction( qt.makeConstantAction() );
506                     preparedStmt.setSavedObjects( cc.getSavedObjects() );
507                     preparedStmt.setRequiredPermissionsList(cc.getRequiredPermissionsList());
508                     preparedStmt.setActivationClass(ac);
509                     preparedStmt.setNeedsSavepoint(qt.needsSavepoint());
510                     preparedStmt.setCursorInfo((CursorInfo)cc.getCursorInfo());
511                     preparedStmt.setIsAtomic(qt.isAtomic());
512                     preparedStmt.setExecuteStatementNameAndSchema(
513                                                 qt.executeStatementName(),
514                                                 qt.executeSchemaName()
515                                                 );
516                     preparedStmt.setSPSName(qt.getSPSName());
517                     preparedStmt.completeCompile(qt);
518                     preparedStmt.setCompileTimeWarnings(cc.getWarnings());
519                 }
520                 catch (StandardException e) // hold it, throw it
521
{
522                     lcc.commitNestedTransaction();
523                     throw e;
524                 }
525
526                 if (lcc.getRunTimeStatisticsMode())
527                 {
528                     preparedStmt.setCompileTimeMillis(
529                         parseTime - beginTime, //parse time
530
bindTime - parseTime, //bind time
531
optimizeTime - bindTime, //optimize time
532
generateTime - optimizeTime, //generate time
533
getElapsedTimeMillis(beginTime),
534                         beginTimestamp,
535                         endTimestamp);
536                 }
537
538             }
539             finally // for block introduced by pushCompilerContext()
540
{
541                 lcc.popCompilerContext( cc );
542             }
543         }
544         catch (StandardException se)
545         {
546             if (foundInCache)
547                 ((GenericLanguageConnectionContext)lcc).removeStatement(this);
548             throw se;
549         }
550         finally
551         {
552             synchronized (preparedStmt) {
553                 preparedStmt.compilingStatement = false;
554                 preparedStmt.notifyAll();
555             }
556         }
557
558         lcc.commitNestedTransaction();
559
560         if (statementContext != null)
561             lcc.popStatementContext(statementContext, null);
562
563         return preparedStmt;
564     }
565
566     /**
567      * Generates an execution plan given a set of named parameters.
568      * Does so for a storable prepared statement.
569      *
570      * @param paramDefaults Parameter defaults
571      *
572      * @return A PreparedStatement that allows execution of the execution
573      * plan.
574      * @exception StandardException Thrown if this is an
575      * execution-only version of the module (the prepare() method
576      * relies on compilation).
577      */

578     public PreparedStatement prepareStorable(
579                 LanguageConnectionContext lcc,
580                 PreparedStatement ps,
581                 Object JavaDoc[] paramDefaults,
582                 SchemaDescriptor spsSchema,
583                 boolean internalSQL)
584         throws StandardException
585     {
586         if (ps == null)
587             ps = new GenericStorablePreparedStatement(this);
588         else
589             ((GenericPreparedStatement) ps).statement = this;
590
591         this.preparedStmt = (GenericPreparedStatement) ps;
592         return prepMinion(lcc, false, paramDefaults, spsSchema, internalSQL);
593     }
594
595     public String JavaDoc getSource() {
596         return statementText;
597     }
598
599     public String JavaDoc getCompilationSchema() {
600         return compilationSchema.getDescriptorName();
601     }
602
603     private static long getCurrentTimeMillis(LanguageConnectionContext lcc)
604     {
605         if (lcc.getStatisticsTiming())
606         {
607             return System.currentTimeMillis();
608         }
609         else
610         {
611             return 0;
612         }
613     }
614
615     private static long getElapsedTimeMillis(long beginTime)
616     {
617         if (beginTime != 0)
618         {
619             return System.currentTimeMillis() - beginTime;
620         }
621         else
622         {
623             return 0;
624         }
625     }
626
627     /*
628     ** Identity
629     */

630
631     public boolean equals(Object JavaDoc other) {
632
633         if (other instanceof GenericStatement) {
634
635             GenericStatement os = (GenericStatement) other;
636
637             return statementText.equals(os.statementText) && isForReadOnly==os.isForReadOnly
638                 && compilationSchema.equals(os.compilationSchema) &&
639                 (prepareIsolationLevel == os.prepareIsolationLevel);
640         }
641
642         return false;
643     }
644
645     public int hashCode() {
646
647         return statementText.hashCode();
648     }
649 }
650
Popular Tags