Source Code Cross Referenced for CursorNode.java in  » Database-DBMS » db-derby-10.2 » org » apache » derby » impl » sql » compile » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database DBMS » db derby 10.2 » org.apache.derby.impl.sql.compile 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:
003:           Derby - Class org.apache.derby.impl.sql.compile.CursorNode
004:
005:           Licensed to the Apache Software Foundation (ASF) under one or more
006:           contributor license agreements.  See the NOTICE file distributed with
007:           this work for additional information regarding copyright ownership.
008:           The ASF licenses this file to you under the Apache License, Version 2.0
009:           (the "License"); you may not use this file except in compliance with
010:           the License.  You may obtain a copy of the License at
011:
012:              http://www.apache.org/licenses/LICENSE-2.0
013:
014:           Unless required by applicable law or agreed to in writing, software
015:           distributed under the License is distributed on an "AS IS" BASIS,
016:           WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017:           See the License for the specific language governing permissions and
018:           limitations under the License.
019:
020:         */
021:
022:        package org.apache.derby.impl.sql.compile;
023:
024:        import org.apache.derby.iapi.services.context.ContextManager;
025:
026:        import org.apache.derby.iapi.sql.compile.C_NodeTypes;
027:
028:        import org.apache.derby.iapi.sql.conn.Authorizer;
029:        import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
030:
031:        import org.apache.derby.iapi.error.StandardException;
032:        import org.apache.derby.iapi.reference.SQLState;
033:
034:        import org.apache.derby.iapi.sql.ResultColumnDescriptor;
035:
036:        import org.apache.derby.iapi.sql.dictionary.DataDictionary;
037:        import org.apache.derby.iapi.sql.dictionary.DataDictionaryContext;
038:        import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
039:        import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
040:
041:        import org.apache.derby.iapi.services.sanity.SanityManager;
042:
043:        import org.apache.derby.iapi.services.compiler.MethodBuilder;
044:
045:        import org.apache.derby.impl.sql.compile.ActivationClassBuilder;
046:
047:        import org.apache.derby.impl.sql.CursorInfo;
048:        import org.apache.derby.impl.sql.CursorTableReference;
049:
050:        import java.util.ArrayList;
051:        import java.util.Vector;
052:
053:        /**
054:         * A CursorNode represents a result set that can be returned to a client.
055:         * A cursor can be a named cursor created by the DECLARE CURSOR statement,
056:         * or it can be an unnamed cursor associated with a SELECT statement (more
057:         * precisely, a table expression that returns rows to the client).  In the
058:         * latter case, the cursor does not have a name.
059:         *
060:         * @author Jeff Lichtman
061:         */
062:
063:        public class CursorNode extends DMLStatementNode {
064:            public final static int UNSPECIFIED = 0;
065:            public final static int READ_ONLY = 1;
066:            public final static int UPDATE = 2;
067:
068:            private String name;
069:            private OrderByList orderByList;
070:            private String statementType;
071:            private int updateMode;
072:            private boolean needTarget;
073:
074:            /**
075:             ** There can only be a list of updatable columns when FOR UPDATE
076:             ** is specified as part of the cursor specification.
077:             */
078:            private Vector updatableColumns;
079:            private FromTable updateTable;
080:            private ResultColumnDescriptor[] targetColumnDescriptors;
081:
082:            //If cursor references session schema tables, save the list of those table names in savedObjects in compiler context
083:            //Following is the position of the session table names list in savedObjects in compiler context
084:            //At generate time, we save this position in activation for easy access to session table names list from compiler context
085:            private int indexOfSessionTableNamesInSavedObjects = -1;
086:
087:            /**
088:             * Initializer for a CursorNode
089:             *
090:             * @param statementType	Type of statement (SELECT, UPDATE, INSERT)
091:             * @param resultSet	A ResultSetNode specifying the result set for
092:             *			the cursor
093:             * @param name		The name of the cursor, null if no name
094:             * @param orderByList	The order by list for the cursor, null if no
095:             *			order by list
096:             * @param updateMode	The user-specified update mode for the cursor,
097:             *			for example, CursorNode.READ_ONLY
098:             * @param updatableColumns The list of updatable columns specified by
099:             *			the user in the FOR UPDATE clause, null if no
100:             *			updatable columns specified.  May only be
101:             *			provided if the updateMode parameter is
102:             *			CursorNode.UPDATE.
103:             */
104:
105:            public void init(Object statementType, Object resultSet,
106:                    Object name, Object orderByList, Object updateMode,
107:                    Object updatableColumns) {
108:                init(resultSet);
109:                this .name = (String) name;
110:                this .statementType = (String) statementType;
111:                this .orderByList = (OrderByList) orderByList;
112:
113:                this .updateMode = ((Integer) updateMode).intValue();
114:                this .updatableColumns = (Vector) updatableColumns;
115:
116:                /*
117:                 ** This is a sanity check and not an error since the parser
118:                 ** controls setting updatableColumns and updateMode.
119:                 */
120:                if (SanityManager.DEBUG)
121:                    SanityManager
122:                            .ASSERT(this .updatableColumns == null
123:                                    || this .updatableColumns.size() == 0
124:                                    || this .updateMode == UPDATE,
125:                                    "Can only have explicit updatable columns if update mode is UPDATE");
126:            }
127:
128:            /**
129:             * Convert this object to a String.  See comments in QueryTreeNode.java
130:             * for how this should be done for tree printing.
131:             *
132:             * @return	This object as a String
133:             */
134:
135:            public String toString() {
136:                if (SanityManager.DEBUG) {
137:                    return "name: " + name + "\n" + "updateMode: "
138:                            + updateModeString(updateMode) + "\n"
139:                            + super .toString();
140:                } else {
141:                    return "";
142:                }
143:            }
144:
145:            public String statementToString() {
146:                return statementType;
147:            }
148:
149:            /**
150:             * Support routine for translating an updateMode identifier to a String
151:             *
152:             * @param updateMode	An updateMode identifier
153:             *
154:             * @return	A String representing the update mode.
155:             */
156:
157:            private static String updateModeString(int updateMode) {
158:                if (SanityManager.DEBUG) {
159:                    switch (updateMode) {
160:                    case UNSPECIFIED:
161:                        return "UNSPECIFIED (" + UNSPECIFIED + ")";
162:
163:                    case READ_ONLY:
164:                        return "READ_ONLY (" + READ_ONLY + ")";
165:
166:                    case UPDATE:
167:                        return "UPDATE (" + UPDATE + ")";
168:
169:                    default:
170:                        return "UNKNOWN VALUE (" + updateMode + ")";
171:                    }
172:                } else {
173:                    return "";
174:                }
175:            }
176:
177:            /**
178:             * Prints the sub-nodes of this object.  See QueryTreeNode.java for
179:             * how tree printing is supposed to work.
180:             *
181:             * @param depth		The depth of this node in the tree
182:             */
183:
184:            public void printSubNodes(int depth) {
185:                if (SanityManager.DEBUG) {
186:                    super .printSubNodes(depth);
187:
188:                    printLabel(depth, "orderByList: ");
189:                    if (orderByList != null)
190:                        orderByList.treePrint(depth + 1);
191:                }
192:            }
193:
194:            /**
195:             * Bind this CursorNode.  This means looking up tables and columns and
196:             * getting their types, and figuring out the result types of all
197:             * expressions, as well as doing view resolution, permissions checking,
198:             * etc. It also includes determining whether an UNSPECIFIED cursor
199:             * is updatable or not, and verifying that an UPDATE cursor actually is.
200:             *
201:             * @return	The bound query tree
202:             *
203:             * @exception StandardException		Thrown on error
204:             */
205:
206:            public QueryTreeNode bind() throws StandardException {
207:                DataDictionary dataDictionary;
208:
209:                dataDictionary = getDataDictionary();
210:
211:                // This is how we handle queries like: SELECT A FROM T ORDER BY B.
212:                // We pull up the order by columns (if they don't appear in the SELECT
213:                // LIST) and let the bind() do the job.  Note that the pullup is done
214:                // before the bind() and we may avoid pulling up ORDERBY columns that
215:                // would otherwise be avoided, e.g., "SELECT * FROM T ORDER BY B".
216:                // Pulled-up ORDERBY columns that are duplicates (like the above "SELECT
217:                // *" query will be removed in bindOrderByColumns().
218:                // Finally, given that extra columns may be added to the SELECT list, we
219:                // inject a ProjectRestrictNode so that only the user-specified columns
220:                // will be returned (see genProjectRestrict() in SelectNode.java).
221:                if (orderByList != null) {
222:                    orderByList.pullUpOrderByColumns(resultSet);
223:                }
224:
225:                getCompilerContext().pushCurrentPrivType(getPrivType());
226:                try {
227:                    FromList fromList = (FromList) getNodeFactory().getNode(
228:                            C_NodeTypes.FROM_LIST,
229:                            getNodeFactory().doJoinOrderOptimization(),
230:                            getContextManager());
231:
232:                    /* Check for ? parameters directly under the ResultColums */
233:                    resultSet.rejectParameters();
234:
235:                    super .bind(dataDictionary);
236:
237:                    // bind the query expression
238:                    resultSet.bindResultColumns(fromList);
239:
240:                    // this rejects any untyped nulls in the select list
241:                    // pass in null to indicate that we don't have any
242:                    // types for this node
243:                    resultSet.bindUntypedNullsToResultColumns(null);
244:
245:                    // Reject any XML values in the select list; JDBC doesn't
246:                    // define how we bind these out, so we don't allow it.
247:                    resultSet.rejectXMLValues();
248:
249:                    /* Verify that all underlying ResultSets reclaimed their FromList */
250:                    if (SanityManager.DEBUG) {
251:                        SanityManager
252:                                .ASSERT(
253:                                        fromList.size() == 0,
254:                                        "fromList.size() is expected to be 0, not "
255:                                                + fromList.size()
256:                                                + " on return from RS.bindExpressions()");
257:                    }
258:                } finally {
259:                    getCompilerContext().popCurrentPrivType();
260:                }
261:
262:                // bind the order by
263:                if (orderByList != null) {
264:                    orderByList.bindOrderByColumns(resultSet);
265:                }
266:
267:                // bind the updatability
268:
269:                // if it says it is updatable, verify it.
270:                if (updateMode == UPDATE) {
271:                    int checkedUpdateMode;
272:
273:                    checkedUpdateMode = determineUpdateMode(dataDictionary);
274:                    if (SanityManager.DEBUG)
275:                        SanityManager.DEBUG("DumpUpdateCheck",
276:                                "update mode is UPDATE (" + updateMode
277:                                        + ") checked mode is "
278:                                        + checkedUpdateMode);
279:                    if (updateMode != checkedUpdateMode)
280:                        throw StandardException
281:                                .newException(SQLState.LANG_STMT_NOT_UPDATABLE);
282:                }
283:
284:                // if it doesn't know if it is updatable, determine it
285:                if (updateMode == UNSPECIFIED) {
286:                    // If the statement is opened with CONCUR_READ_ONLY, the upgrade mode is 
287:                    // set to read only.
288:
289:                    // NOTE: THIS IS NOT COMPATIBLE WITH THE ISO/ANSI SQL STANDARD.
290:
291:                    // According to the SQL-standard:
292:                    // If updatability is not specified, a SELECT * FROM T will be implicitely
293:                    // read only in the context of a cursor which is insensitive, scrollable or
294:                    // have an order by clause. Otherwise it is implicitely updatable.
295:
296:                    // In Derby, we make a SELECT * FROM T updatable if the concurrency mode is
297:                    // ResultSet.CONCUR_UPDATE. If we do make all SELECT * FROM T  updatable
298:                    // by default, we cannot use an index on any single-table select, unless it
299:                    // was declared FOR READ ONLY. This would be pretty terrible, so we are
300:                    // breaking the ANSI rules.
301:
302:                    if (getLanguageConnectionContext().getStatementContext()
303:                            .isForReadOnly()) {
304:                        updateMode = READ_ONLY;
305:                    } else {
306:                        updateMode = determineUpdateMode(dataDictionary);
307:                    }
308:
309:                    //if (SanityManager.DEBUG)
310:                    //SanityManager.DEBUG("DumpUpdateCheck","update mode is UNSPECIFIED ("+UNSPECIFIED+") checked mode is "+updateMode);
311:                }
312:
313:                if (updateMode == READ_ONLY) {
314:                    updatableColumns = null; // don't need them any more
315:                }
316:
317:                // bind the update columns
318:                if (updateMode == UPDATE) {
319:                    bindUpdateColumns(updateTable);
320:
321:                    // If the target table is a FromBaseTable, mark the updatable
322:                    // columns.  (I can't think of a way that an updatable table
323:                    // could be anything but a FromBaseTable at this point, but
324:                    // it's better to be careful.
325:                    if (updateTable instanceof  FromTable) {
326:                        ((FromTable) updateTable)
327:                                .markUpdatableByCursor(updatableColumns);
328:                        //make sure that alongwith the FromTable, we keep other ResultSetLists
329:                        //in correct state too. ResultSetMetaData.isWritable looks at this to
330:                        //return the correct value.
331:                        resultSet.getResultColumns()
332:                                .markColumnsInSelectListUpdatableByCursor(
333:                                        updatableColumns);
334:                    }
335:                }
336:
337:                resultSet.renameGeneratedResultNames();
338:
339:                //need to look for SESSION tables only if global temporary tables declared for the connection
340:                if (getLanguageConnectionContext()
341:                        .checkIfAnyDeclaredGlobalTempTablesForThisConnection()) {
342:                    //If this cursor has references to session schema tables, save the names of those tables into compiler context
343:                    //so they can be passed to execution phase.
344:                    ArrayList sessionSchemaTableNames = getSessionSchemaTableNamesForCursor();
345:                    if (sessionSchemaTableNames != null)
346:                        indexOfSessionTableNamesInSavedObjects = getCompilerContext()
347:                                .addSavedObject(sessionSchemaTableNames);
348:                }
349:
350:                return this ;
351:            }
352:
353:            /**
354:             * Return true if the node references SESSION schema tables (temporary or permanent)
355:             *
356:             * @return	true if references SESSION schema tables, else false
357:             *
358:             * @exception StandardException		Thrown on error
359:             */
360:            public boolean referencesSessionSchema() throws StandardException {
361:                //If this node references a SESSION schema table, then return true. 
362:                return resultSet.referencesSessionSchema();
363:            }
364:
365:            //Check if this cursor references any session schema tables. If so, pass those names to execution phase through savedObjects
366:            //This list will be used to check if there are any holdable cursors referencing temporary tables at commit time.
367:            //If yes, then the data in those temporary tables should be preserved even if they are declared with ON COMMIT DELETE ROWS option
368:            protected ArrayList getSessionSchemaTableNamesForCursor()
369:                    throws StandardException {
370:                FromList fromList = resultSet.getFromList();
371:                int fromListSize = fromList.size();
372:                FromTable fromTable;
373:                ArrayList sessionSchemaTableNames = null;
374:
375:                for (int i = 0; i < fromListSize; i++) {
376:                    fromTable = (FromTable) fromList.elementAt(i);
377:                    if (fromTable instanceof  FromBaseTable
378:                            && isSessionSchema(fromTable.getTableDescriptor()
379:                                    .getSchemaDescriptor())) {
380:                        if (sessionSchemaTableNames == null)
381:                            sessionSchemaTableNames = new ArrayList();
382:                        sessionSchemaTableNames.add(fromTable.getTableName()
383:                                .getTableName());
384:                    }
385:                }
386:
387:                return sessionSchemaTableNames;
388:            }
389:
390:            /**
391:             * Take a cursor and determine if it is UPDATE
392:             * or READ_ONLY based on the shape of the cursor specification.
393:             * <p>
394:             * The following conditions make a cursor read only:
395:             * <UL>
396:             * <LI>if it says FOR READ ONLY
397:             * <LI>if it says ORDER BY
398:             * <LI>if its query specification is not read only. At present this
399:             *     is explicitly tested here, with these conditions.  At some future
400:             *     point in time, this checking ought to be moved into the
401:             *     ResultSet nodes themselves.  The conditions for a query spec.
402:             *     not to be read only include:
403:             *     <UL>
404:             *     <LI>if it has a set operation such as UNION or INTERSECT, i.e.
405:             *         does not have a single outermost SELECT
406:             *     <LI>if it does not have exactly 1 table in its FROM list;
407:             *         0 tables would occur if we ever support a SELECT without a
408:             *         FROM e.g., for generating a row without an underlying table
409:             *         (like what we do for an INSERT of a VALUES list); >1 tables
410:             *         occurs when joins are in the tree.
411:             *     <LI>if the table in its FROM list is not a base table (REMIND
412:             *         when views/from subqueries are added, this should be relaxed to
413:             *         be that the table is not updatable)
414:             *     <LI>if it has a GROUP BY or HAVING (NOTE I am assuming that if
415:             *         and aggregate is detected in a SELECT w/o a GROUP BY, one
416:             *         has been added to show that the whole table is a group)
417:             *     <LI> NOTE that cursors are updatable even if none of the columns
418:             *         in the select are updatable -- what they care about is the
419:             *         updatability of the columns of the target table.
420:             *     </UL>
421:             * </UL>
422:             *
423:             * @return the known update mode for the cursor.
424:             *
425:             * @exception StandardException		Thrown on error
426:             */
427:            private int determineUpdateMode(DataDictionary dataDictionary)
428:                    throws StandardException {
429:                SelectNode selectNode;
430:                FromList tables;
431:                FromTable targetTable;
432:
433:                if (updateMode == READ_ONLY) {
434:                    return READ_ONLY;
435:                }
436:
437:                if (orderByList != null) {
438:                    if (SanityManager.DEBUG)
439:                        SanityManager.DEBUG("DumpUpdateCheck",
440:                                "cursor has order by");
441:                    return READ_ONLY;
442:                }
443:
444:                // get the ResultSet to tell us what it thinks it is
445:                // and the target table
446:                if (!resultSet.isUpdatableCursor(dataDictionary)) {
447:                    return READ_ONLY;
448:                }
449:
450:                // The FOR UPDATE clause has two uses:
451:                //
452:                // for positioned cursor updates
453:                //
454:                // to change locking behaviour of the select
455:                // to reduce deadlocks on subsequent updates
456:                // in the same transaction.
457:                //
458:                // We now support this latter case, without requiring
459:                // that the source of the rows be able to implement
460:                // a positioned update.
461:
462:                updateTable = resultSet.getCursorTargetTable();
463:
464:                /* Tell the table that it is the cursor target */
465:                if (updateTable.markAsCursorTargetTable()) {
466:                    /* Cursor is updatable - remember to generate the position code */
467:                    needTarget = true;
468:
469:                    /* We must generate the target column list at bind time
470:                     * because the optimizer may transform the FromBaseTable from
471:                     * a table scan into an index scan.
472:                     */
473:                    genTargetResultColList();
474:                }
475:
476:                return UPDATE;
477:            }
478:
479:            /**
480:             * Optimize a DML statement (which is the only type of statement that
481:             * should need optimizing, I think). This method over-rides the one
482:             * in QueryTreeNode.
483:             *
484:             * This method takes a bound tree, and returns an optimized tree.
485:             * It annotates the bound tree rather than creating an entirely
486:             * new tree.
487:             *
488:             * Throws an exception if the tree is not bound, or if the binding
489:             * is out of date.
490:             *
491:             * @return	An optimized QueryTree
492:             *
493:             * @exception StandardException		Thrown on error
494:             */
495:
496:            public QueryTreeNode optimize() throws StandardException {
497:                // Push the order by list down to the ResultSet
498:                if (orderByList != null) {
499:                    // If we have more than 1 ORDERBY columns, we may be able to
500:                    // remove duplicate columns, e.g., "ORDER BY 1, 1, 2".
501:                    if (orderByList.size() > 1) {
502:                        orderByList.removeDupColumns();
503:                    }
504:
505:                    resultSet.pushOrderByList(orderByList);
506:                    orderByList = null;
507:                }
508:                return super .optimize();
509:            }
510:
511:            /**
512:             * Returns the type of activation this class
513:             * generates.
514:             * 
515:             * @return either (NEED_CURSOR_ACTIVATION
516:             *
517:             * @exception StandardException		Thrown on error
518:             */
519:
520:            int activationKind() {
521:                return NEED_CURSOR_ACTIVATION;
522:            }
523:
524:            /**
525:             * Do code generation for this CursorNode
526:             *
527:             * @param acb	The ActivationClassBuilder for the class being built
528:             * @param mb	The method the generated code is to go into
529:             *
530:             * @exception StandardException		Thrown on error
531:             */
532:
533:            public void generate(ActivationClassBuilder acb, MethodBuilder mb)
534:                    throws StandardException {
535:                if (indexOfSessionTableNamesInSavedObjects != -1) //if this cursor references session schema tables, do following
536:                {
537:                    MethodBuilder constructor = acb.getConstructor();
538:                    constructor.pushThis();
539:                    constructor.push(indexOfSessionTableNamesInSavedObjects);
540:                    constructor
541:                            .putField(
542:                                    org.apache.derby.iapi.reference.ClassName.BaseActivation,
543:                                    "indexOfSessionTableNamesInSavedObjects",
544:                                    "int");
545:                    constructor.endStatement();
546:                }
547:
548:                // generate the parameters
549:                generateParameterValueSet(acb);
550:
551:                // tell the outermost result set that it is the outer
552:                // result set of the statement.
553:                resultSet.markStatementResultSet();
554:
555:                generateAuthorizeCheck(acb, mb,
556:                        org.apache.derby.iapi.sql.conn.Authorizer.SQL_SELECT_OP);
557:
558:                // this will generate an expression that will be a ResultSet
559:                resultSet.generate(acb, mb);
560:
561:                /*
562:                 ** Generate the position code if this cursor is updatable.  This
563:                 ** involves generating methods to get the cursor result set, and
564:                 ** the target result set (which is for the base row).  Also,
565:                 ** generate code to store the cursor result set in a generated
566:                 ** field.
567:                 */
568:                if (needTarget) {
569:                    // PUSHCOMPILE - could be put into a single method
570:                    acb.rememberCursor(mb);
571:                    acb.addCursorPositionCode();
572:                }
573:            }
574:
575:            // class interface
576:
577:            public String getUpdateBaseTableName() {
578:                return (updateTable == null) ? null : updateTable
579:                        .getBaseTableName();
580:            }
581:
582:            public String getUpdateExposedTableName() throws StandardException {
583:                return (updateTable == null) ? null : updateTable
584:                        .getExposedName();
585:            }
586:
587:            public String getUpdateSchemaName() throws StandardException {
588:                //we need to use the base table for the schema name
589:                return (updateTable == null) ? null
590:                        : ((FromBaseTable) updateTable).getTableNameField()
591:                                .getSchemaName();
592:            }
593:
594:            public int getUpdateMode() {
595:                return updateMode;
596:            }
597:
598:            /**
599:             * Return String[] of names from the FOR UPDATE OF List
600:             *
601:             * @return	String[] of names from the FOR UPDATE OF list.
602:             */
603:            private String[] getUpdatableColumns() {
604:                return (updatableColumns == null) ? (String[]) null
605:                        : getUpdateColumnNames();
606:            }
607:
608:            /**
609:            	Positioned update needs to know what the target result set
610:            	looks like. This is generated from the UpdateColumnList
611:            	available for the cursor, to describe the rows coming from
612:            	the target result set under the cursor. This result set contains
613:            	a superset of the updatable columns; the caller must verify that
614:            	only those listed in the FOR UPDATE clause are used.
615:
616:            	@return a result column list containing a description of
617:            	the target table (this may contain non-updatable columns).
618:             * @exception StandardException		Thrown on error
619:             */
620:            private ResultColumnDescriptor[] genTargetResultColList()
621:                    throws StandardException {
622:                ResultColumnList newList;
623:
624:                /*
625:                   updateTable holds the FromTable that is the target.
626:                   copy its ResultColumnList, making BaseColumn references
627:                   for use in the CurrentOfNode, which behaves as if it had
628:                   base columns for the statement it is in.
629:
630:                	updateTable is null if the cursor is not updatable.
631:                 */
632:                if (updateTable == null)
633:                    return null;
634:
635:                if (targetColumnDescriptors != null)
636:                    return targetColumnDescriptors;
637:
638:                newList = (ResultColumnList) getNodeFactory().getNode(
639:                        C_NodeTypes.RESULT_COLUMN_LIST, getContextManager());
640:                ResultColumnList rcl = updateTable.getResultColumns();
641:                int rclSize = rcl.size();
642:                for (int index = 0; index < rclSize; index++) {
643:                    ResultColumn origCol, newCol;
644:                    ValueNode newNode;
645:
646:                    origCol = (ResultColumn) rcl.elementAt(index);
647:
648:                    // Build a ResultColumn/BaseColumnNode pair for the column
649:                    newNode = (ValueNode) getNodeFactory().getNode(
650:                            C_NodeTypes.BASE_COLUMN_NODE,
651:                            origCol.getName(),
652:                            makeTableName(origCol.getSchemaName(), origCol
653:                                    .getTableName()),
654:                            origCol.getTypeServices(), getContextManager());
655:                    newCol = (ResultColumn) getNodeFactory().getNode(
656:                            C_NodeTypes.RESULT_COLUMN,
657:                            origCol.columnDescriptor, newNode,
658:                            getContextManager());
659:
660:                    /* Build the ResultColumnList to return */
661:                    newList.addResultColumn(newCol);
662:                }
663:
664:                // we save the result so we only do this once
665:                targetColumnDescriptors = newList.makeResultDescriptors();
666:                return targetColumnDescriptors;
667:            }
668:
669:            /**
670:             * Returns whether or not this Statement requires a set/clear savepoint
671:             * around its execution.  The following statement "types" do not require them:
672:             *		Cursor	- unnecessary and won't work in a read only environment
673:             *		Xact	- savepoint will get blown away underneath us during commit/rollback
674:             *
675:             * @return boolean	Whether or not this Statement requires a set/clear savepoint
676:             */
677:            public boolean needsSavepoint() {
678:                return false;
679:            }
680:
681:            /**
682:             * Get information about this cursor.  For sps,
683:             * this is info saved off of the original query
684:             * tree (the one for the underlying query).
685:             *
686:             * @return	the cursor info
687:             * @exception StandardException thrown if generation fails
688:             */
689:            public Object getCursorInfo() throws StandardException {
690:                if (!needTarget)
691:                    return null;
692:
693:                return new CursorInfo(updateMode, new CursorTableReference(
694:                        getUpdateExposedTableName(), getUpdateBaseTableName(),
695:                        getUpdateSchemaName()), genTargetResultColList(),
696:                        getUpdatableColumns());
697:            }
698:
699:            /**
700:            	Bind the update columns by their names to the target table
701:            	of the cursor specification.
702:            	Doesn't check for duplicates in the list, although it could...
703:            	REVISIT: If the list is empty, should it expand it out? at present,
704:            	it leaves it empty.
705:            
706:            	@param targetTable	The underlying target table 
707:            
708:            	@exception StandardException		Thrown on error
709:             */
710:            private void bindUpdateColumns(FromTable targetTable)
711:                    throws StandardException {
712:                int size = updatableColumns.size();
713:                TableDescriptor tableDescriptor;
714:                String columnName;
715:                ResultColumnList rcls = resultSet.getResultColumns();
716:
717:                for (int index = 0; index < size; index++) {
718:                    columnName = (String) updatableColumns.elementAt(index);
719:                    tableDescriptor = targetTable.getTableDescriptor();
720:                    if (tableDescriptor.getColumnDescriptor(columnName) == null) {
721:                        throw StandardException.newException(
722:                                SQLState.LANG_COLUMN_NOT_FOUND, columnName);
723:                    }
724:
725:                    ResultColumn rc;
726:                    //make sure that we are not using correlation names for updatable columns. 
727:                    //eg select c11 as col1, 2, c13 as col3 from t1 for update of c11, c12
728:                    //In the eg above, correlation name for c11 will cause exception because Derby does not support correlation name for updatable columns
729:                    //But correlation name for c13 is ok because it is a read only column
730:                    for (int rclsIndex = 0; rclsIndex < rcls.size(); rclsIndex++) {//look through each column in the resultset for cursor
731:                        rc = ((ResultColumn) rcls.elementAt(rclsIndex));
732:                        if (rc.getSourceTableName() == null) //continue to look at the next column because this is derived column in the select list
733:                            continue;
734:                        if (rc.getExpression() != null
735:                                && rc.getExpression().getColumnName().equals(
736:                                        columnName)
737:                                && !rc.getName().equals(columnName)) {
738:                            throw StandardException
739:                                    .newException(
740:                                            SQLState.LANG_CORRELATION_NAME_FOR_UPDATABLE_COLUMN_DISALLOWED_IN_CURSOR,
741:                                            columnName);
742:                        }
743:                    }
744:                }
745:            }
746:
747:            /**
748:             * Get an array of strings for each updatable column
749:             * in this list.
750:             *
751:             * @return an array of strings
752:             */
753:            private String[] getUpdateColumnNames() {
754:                int size = updatableColumns.size();
755:                if (size == 0) {
756:                    return (String[]) null;
757:                }
758:
759:                String[] names = new String[size];
760:
761:                updatableColumns.copyInto(names);
762:
763:                return names;
764:            }
765:
766:            public String getXML() {
767:                return null;
768:            }
769:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.