/** * Bind the tables in this DML statement. * * @param dataDictionary The data dictionary to use to look up the tables * @exception StandardException Thrown on error */ protected void bindTables(DataDictionary dataDictionary) throws StandardException { /* Bind the tables in the resultSet * (DMLStatementNode is above all ResultSetNodes, so table numbering * will begin at 0.) * In case of referential action on delete , the table numbers can be * > 0 because the nodes are create for dependent tables also in the * the same context. */ resultSet = resultSet.bindNonVTITables( dataDictionary, (FromList) getNodeFactory() .getNode( C_NodeTypes.FROM_LIST, getNodeFactory().doJoinOrderOptimization(), getContextManager())); resultSet = resultSet.bindVTITables( (FromList) getNodeFactory() .getNode( C_NodeTypes.FROM_LIST, getNodeFactory().doJoinOrderOptimization(), getContextManager())); }
/** * Extract out and return the subquery, with a PRN on top. (See FromSubquery.preprocess() for more * details.) * * @param numTables The number of tables in the DML Statement * @return ResultSetNode at top of extracted tree. * @exception StandardException Thrown on error */ public ResultSetNode extractSubquery(int numTables) throws StandardException { JBitSet newJBS; ResultSetNode newPRN; newPRN = (ResultSetNode) getNodeFactory() .getNode( C_NodeTypes.PROJECT_RESTRICT_NODE, subquery, /* Child ResultSet */ resultColumns, /* Projection */ null, /* Restriction */ null, /* Restriction as PredicateList */ null, /* Subquerys in Projection */ null, /* Subquerys in Restriction */ tableProperties, getContextManager()); /* Set up the PRN's referencedTableMap */ newJBS = new JBitSet(numTables); newJBS.set(tableNumber); newPRN.setReferencedTableMap(newJBS); ((FromTable) newPRN).setTableNumber(tableNumber); return newPRN; }
/** * Flatten this FSqry into the outer query block. The steps in flattening are: o Mark all * ResultColumns as redundant, so that they are "skipped over" at generate(). o Append the * wherePredicates to the outer list. o Return the fromList so that the caller will merge the 2 * lists RESOLVE - FSqrys with subqueries are currently not flattenable. Some of them can be * flattened, however. We need to merge the subquery list when we relax this restriction. * * <p>NOTE: This method returns NULL when flattening RowResultSetNodes (the node for a VALUES * clause). The reason is that no reference is left to the RowResultSetNode after flattening is * done - the expressions point directly to the ValueNodes in the RowResultSetNode's * ResultColumnList. * * @param rcl The RCL from the outer query * @param outerPList PredicateList to append wherePredicates to. * @param sql The SubqueryList from the outer query * @param gbl The group by list, if any * @param havingClause The HAVING clause, if any * @return FromList The fromList from the underlying SelectNode. * @exception StandardException Thrown on error */ public FromList flatten( ResultColumnList rcl, PredicateList outerPList, SubqueryList sql, GroupByList gbl, ValueNode havingClause) throws StandardException { FromList fromList = null; SelectNode selectNode; resultColumns.setRedundant(); subquery.getResultColumns().setRedundant(); /* ** RESOLVE: Each type of result set should know how to remap itself. */ if (subquery instanceof SelectNode) { selectNode = (SelectNode) subquery; fromList = selectNode.getFromList(); // selectNode.getResultColumns().setRedundant(); if (selectNode.getWherePredicates().size() > 0) { outerPList.destructiveAppend(selectNode.getWherePredicates()); } if (selectNode.getWhereSubquerys().size() > 0) { sql.destructiveAppend(selectNode.getWhereSubquerys()); } } else if (!(subquery instanceof RowResultSetNode)) { if (SanityManager.DEBUG) { SanityManager.THROWASSERT( "subquery expected to be either a SelectNode or a RowResultSetNode, but is a " + subquery.getClass().getName()); } } /* Remap all ColumnReferences from the outer query to this node. * (We replace those ColumnReferences with clones of the matching * expression in the SELECT's RCL. */ rcl.remapColumnReferencesToExpressions(); outerPList.remapColumnReferencesToExpressions(); if (gbl != null) { gbl.remapColumnReferencesToExpressions(); } if (havingClause != null) { havingClause.remapColumnReferencesToExpressions(); } return fromList; }
/** * Prints the sub-nodes of this object. See QueryTreeNode.java for how tree printing is supposed * to work. * * @param depth The depth of this node in the tree */ public void printSubNodes(int depth) { if (SanityManager.DEBUG) { super.printSubNodes(depth); if (subquery != null) { printLabel(depth, "subquery: "); subquery.treePrint(depth + 1); } if (orderByList != null) { printLabel(depth, "orderByList: "); orderByList.treePrint(depth + 1); } if (offset != null) { printLabel(depth, "offset: "); offset.treePrint(depth + 1); } if (fetchFirst != null) { printLabel(depth, "fetchFirst: "); fetchFirst.treePrint(depth + 1); } } }
private ResultSetNode wrapRowCountNode( ResultSetNode resultSet, ValueNode offset, ValueNode fetchFirst) throws StandardException { ResultSetNode topRS = resultSet; ResultColumnList selectRCs = topRS.getResultColumns().copyListAndObjects(); selectRCs.genVirtualColumnNodes(topRS, topRS.getResultColumns()); return (RowCountNode) getNodeFactory() .getNode( C_NodeTypes.ROW_COUNT_NODE, topRS, selectRCs, offset, fetchFirst, getContextManager()); }
/** * Prints the sub-nodes of this object. See QueryTreeNode.java for how tree printing is supposed * to work. * * @param depth The depth of this node in the tree */ public void printSubNodes(int depth) { if (SanityManager.DEBUG) { super.printSubNodes(depth); if (resultSet != null) { printLabel(depth, "resultSet: "); resultSet.treePrint(depth + 1); } } }
/** * Bind this subquery that appears in the FROM list. * * @param dataDictionary The DataDictionary to use for binding * @param fromListParam FromList to use/append to. * @return ResultSetNode The bound FromSubquery. * @exception StandardException Thrown on error */ public ResultSetNode bindNonVTITables(DataDictionary dataDictionary, FromList fromListParam) throws StandardException { /* Assign the tableNumber */ if (tableNumber == -1) // allow re-bind, in which case use old number tableNumber = getCompilerContext().getNextTableNumber(); subquery = subquery.bindNonVTITables(dataDictionary, fromListParam); return this; }
/** * Add any new ResultSetNodes that are necessary to the tree. We wait until after optimization to * do this in order to make it easier on the optimizer. * * @return (Potentially new) head of the ResultSetNode tree. * @exception StandardException Thrown on error */ private ResultSetNode addNewNodes() throws StandardException { /* Only call addNewNodes() once */ if (addNewNodesCalled) { return this; } addNewNodesCalled = true; ResultSetNode treeTop = this; if (orderByList != null) { // Generate an order by node on top of the intersect/except treeTop = (ResultSetNode) getNodeFactory() .getNode( C_NodeTypes.ORDER_BY_NODE, treeTop, orderByList, tableProperties, getContextManager()); } if (offset != null || fetchFirst != null) { ResultColumnList newRcl = treeTop.getResultColumns().copyListAndObjects(); newRcl.genVirtualColumnNodes(treeTop, treeTop.getResultColumns()); treeTop = (ResultSetNode) getNodeFactory() .getNode( C_NodeTypes.ROW_COUNT_NODE, treeTop, newRcl, offset, fetchFirst, Boolean.valueOf(hasJDBClimitClause), getContextManager()); } return treeTop; } // end of addNewNodes
/** * Accept a visitor, and call v.visit() on child nodes as necessary. * * @param v the visitor * @exception StandardException on error */ public Visitable accept(Visitor v) throws StandardException { if (v.skipChildren(this)) { return v.visit(this); } if (resultSet != null && !v.stopTraversal()) { resultSet = (ResultSetNode) resultSet.accept(v); } return this; }
/** @see QueryTreeNode#acceptChildren */ void acceptChildren(Visitor v) throws StandardException { super.acceptChildren(v); subquery.accept(v); if (orderByList != null) { orderByList.accept(v); } if (offset != null) { offset.accept(v); } if (fetchFirst != null) { fetchFirst.accept(v); } }
/** * Bind the expressions in the underlying ResultSets with tables. * * @exception StandardException Thrown on error */ protected void bindExpressionsWithTables() throws StandardException { FromList fromList = (FromList) getNodeFactory() .getNode( C_NodeTypes.FROM_LIST, getNodeFactory().doJoinOrderOptimization(), getContextManager()); /* Bind the expressions under the resultSet */ resultSet.bindExpressionsWithTables(fromList); /* Verify that all underlying ResultSets reclaimed their FromList */ if (SanityManager.DEBUG) SanityManager.ASSERT( fromList.size() == 0, "fromList.size() is expected to be 0, not " + fromList.size() + " on return from RS.bindExpressions()"); }
private void pushOrderingDown(ResultSetNode rsn) throws StandardException { ContextManager cm = getContextManager(); NodeFactory nf = getNodeFactory(); OrderByList orderByList = (OrderByList) nf.getNode(C_NodeTypes.ORDER_BY_LIST, cm); for (int i = 0; i < intermediateOrderByColumns.length; i++) { OrderByColumn orderByColumn = (OrderByColumn) nf.getNode( C_NodeTypes.ORDER_BY_COLUMN, nf.getNode( C_NodeTypes.INT_CONSTANT_NODE, ReuseFactory.getInteger(intermediateOrderByColumns[i] + 1), cm), cm); if (intermediateOrderByDirection[i] < 0) orderByColumn.setDescending(); if (intermediateOrderByNullsLow[i]) orderByColumn.setNullsOrderedLow(); orderByList.addOrderByColumn(orderByColumn); } orderByList.bindOrderByColumns(rsn); rsn.pushOrderByList(orderByList); } // end of pushOrderingDown
/** * Bind this CreateTableNode. This means doing any static error checking that can be done before * actually creating the base table or declaring the global temporary table. For eg, verifying * that the TableElementList does not contain any duplicate column names. * * @exception StandardException Thrown on error */ public void bindStatement() throws StandardException { DataDictionary dataDictionary = getDataDictionary(); int numPrimaryKeys = 0; int numCheckConstraints = 0; int numReferenceConstraints = 0; int numUniqueConstraints = 0; int numGenerationClauses = 0; SchemaDescriptor sd = getSchemaDescriptor(tableType != TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE, true); if (queryExpression != null) { FromList fromList = (FromList) getNodeFactory() .getNode( C_NodeTypes.FROM_LIST, getNodeFactory().doJoinOrderOptimization(), getContextManager()); CompilerContext cc = getCompilerContext(); ProviderList prevAPL = cc.getCurrentAuxiliaryProviderList(); ProviderList apl = new ProviderList(); try { cc.setCurrentAuxiliaryProviderList(apl); cc.pushCurrentPrivType(Authorizer.SELECT_PRIV); /* Bind the tables in the queryExpression */ queryExpression = queryExpression.bindNonVTITables(dataDictionary, fromList); queryExpression = queryExpression.bindVTITables(fromList); /* Bind the expressions under the resultSet */ queryExpression.bindExpressions(fromList); /* Bind the query expression */ queryExpression.bindResultColumns(fromList); /* Reject any untyped nulls in the RCL */ /* e.g. CREATE TABLE t1 (x) AS VALUES NULL WITH NO DATA */ queryExpression.bindUntypedNullsToResultColumns(null); } finally { cc.popCurrentPrivType(); cc.setCurrentAuxiliaryProviderList(prevAPL); } /* If there is an RCL for the table definition then copy the * names to the queryExpression's RCL after verifying that * they both have the same size. */ ResultColumnList qeRCL = queryExpression.getResultColumns(); if (resultColumns != null) { if (resultColumns.size() != qeRCL.visibleSize()) { throw StandardException.newException( SQLState.LANG_TABLE_DEFINITION_R_C_L_MISMATCH, getFullName()); } qeRCL.copyResultColumnNames(resultColumns); } int schemaCollationType = sd.getCollationType(); /* Create table element list from columns in query expression */ tableElementList = new TableElementList(); for (int index = 0; index < qeRCL.size(); index++) { ResultColumn rc = (ResultColumn) qeRCL.elementAt(index); if (rc.isGenerated()) { continue; } /* Raise error if column name is system generated. */ if (rc.isNameGenerated()) { throw StandardException.newException(SQLState.LANG_TABLE_REQUIRES_COLUMN_NAMES); } DataTypeDescriptor dtd = rc.getExpression().getTypeServices(); if ((dtd != null) && !dtd.isUserCreatableType()) { throw StandardException.newException( SQLState.LANG_INVALID_COLUMN_TYPE_CREATE_TABLE, dtd.getFullSQLTypeName(), rc.getName()); } // DERBY-2879 CREATE TABLE AS <subquery> does not maintain the // collation for character types. // eg for a territory based collation database // create table t as select tablename from sys.systables with no data; // Derby at this point does not support for a table's character // columns to have a collation different from it's schema's // collation. Which means that in a territory based database, // the query above will cause table t's character columns to // have collation of UCS_BASIC but the containing schema of t // has collation of territory based. This is not supported and // hence we will throw an exception below for the query above in // a territory based database. if (dtd.getTypeId().isStringTypeId() && dtd.getCollationType() != schemaCollationType) { throw StandardException.newException( SQLState.LANG_CAN_NOT_CREATE_TABLE, dtd.getCollationName(), DataTypeDescriptor.getCollationName(schemaCollationType)); } ColumnDefinitionNode column = (ColumnDefinitionNode) getNodeFactory() .getNode( C_NodeTypes.COLUMN_DEFINITION_NODE, rc.getName(), null, rc.getType(), null, getContextManager()); tableElementList.addTableElement(column); } } else { // Set the collation type and collation derivation of all the // character type columns. Their collation type will be same as the // collation of the schema they belong to. Their collation // derivation will be "implicit". // Earlier we did this in makeConstantAction but that is little too // late (DERBY-2955) // eg // CREATE TABLE STAFF9 (EMPNAME CHAR(20), // CONSTRAINT STAFF9_EMPNAME CHECK (EMPNAME NOT LIKE 'T%')) // For the query above, when run in a territory based db, we need // to have the correct collation set in bind phase of create table // so that when LIKE is handled in LikeEscapeOperatorNode, we have // the correct collation set for EMPNAME otherwise it will throw an // exception for 'T%' having collation of territory based and // EMPNAME having the default collation of UCS_BASIC tableElementList.setCollationTypesOnCharacterStringColumns( getSchemaDescriptor(tableType != TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE, true)); } tableElementList.validate(this, dataDictionary, (TableDescriptor) null); /* Only 1012 columns allowed per table */ if (tableElementList.countNumberOfColumns() > Limits.DB2_MAX_COLUMNS_IN_TABLE) { throw StandardException.newException( SQLState.LANG_TOO_MANY_COLUMNS_IN_TABLE_OR_VIEW, String.valueOf(tableElementList.countNumberOfColumns()), getRelativeName(), String.valueOf(Limits.DB2_MAX_COLUMNS_IN_TABLE)); } numPrimaryKeys = tableElementList.countConstraints(DataDictionary.PRIMARYKEY_CONSTRAINT); /* Only 1 primary key allowed per table */ if (numPrimaryKeys > 1) { throw StandardException.newException( SQLState.LANG_TOO_MANY_PRIMARY_KEY_CONSTRAINTS, getRelativeName()); } /* Check the validity of all check constraints */ numCheckConstraints = tableElementList.countConstraints(DataDictionary.CHECK_CONSTRAINT); numReferenceConstraints = tableElementList.countConstraints(DataDictionary.FOREIGNKEY_CONSTRAINT); numUniqueConstraints = tableElementList.countConstraints(DataDictionary.UNIQUE_CONSTRAINT); numGenerationClauses = tableElementList.countGenerationClauses(); // temp tables can't have primary key or check or foreign key or unique constraints defined on // them if ((tableType == TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE) && (numPrimaryKeys > 0 || numCheckConstraints > 0 || numReferenceConstraints > 0 || numUniqueConstraints > 0)) throw StandardException.newException( SQLState.LANG_NOT_ALLOWED_FOR_DECLARED_GLOBAL_TEMP_TABLE); // each of these constraints have a backing index in the back. We need to make sure that a table // never has more // more than 32767 indexes on it and that is why this check. if ((numPrimaryKeys + numReferenceConstraints + numUniqueConstraints) > Limits.DB2_MAX_INDEXES_ON_TABLE) { throw StandardException.newException( SQLState.LANG_TOO_MANY_INDEXES_ON_TABLE, String.valueOf(numPrimaryKeys + numReferenceConstraints + numUniqueConstraints), getRelativeName(), String.valueOf(Limits.DB2_MAX_INDEXES_ON_TABLE)); } if ((numCheckConstraints > 0) || (numGenerationClauses > 0) || (numReferenceConstraints > 0)) { /* In order to check the validity of the check constraints and * generation clauses * we must goober up a FromList containing a single table, * the table being created, with an RCL containing the * new columns and their types. This will allow us to * bind the constraint definition trees against that * FromList. When doing this, we verify that there are * no nodes which can return non-deterministic results. */ FromList fromList = makeFromList(null, tableElementList, true); FormatableBitSet generatedColumns = new FormatableBitSet(); /* Now that we've finally goobered stuff up, bind and validate * the check constraints and generation clauses. */ if (numGenerationClauses > 0) { tableElementList.bindAndValidateGenerationClauses(sd, fromList, generatedColumns, null); } if (numCheckConstraints > 0) { tableElementList.bindAndValidateCheckConstraints(fromList); } if (numReferenceConstraints > 0) { tableElementList.validateForeignKeysOnGenerationClauses(fromList, generatedColumns); } } if (numPrimaryKeys > 0) { tableElementList.validatePrimaryKeyNullability(); } }
/** * Check for (and reject) ? parameters directly under the ResultColumns. This is done for SELECT * statements. For FromSubquery, we simply pass the check through to the subquery. * * @exception StandardException Thrown if a ? parameter found directly under a ResultColumn */ public void rejectParameters() throws StandardException { subquery.rejectParameters(); }
/** * Bind the expressions in this FromSubquery. This means binding the sub-expressions, as well as * figuring out what the return type is for each expression. * * @exception StandardException Thrown on error */ public void bindExpressions(FromList fromListParam) throws StandardException { FromList emptyFromList = (FromList) getNodeFactory() .getNode( C_NodeTypes.FROM_LIST, getNodeFactory().doJoinOrderOptimization(), getContextManager()); ResultColumnList derivedRCL = resultColumns; ResultColumnList subqueryRCL; FromList nestedFromList; /* From subqueries cannot be correlated, so we pass an empty FromList * to subquery.bindExpressions() and .bindResultColumns() */ if (orderByList != null) { orderByList.pullUpOrderByColumns(subquery); } nestedFromList = emptyFromList; CompilerContext compilerContext = getCompilerContext(); if (origCompilationSchema != null) { // View expansion needs the definition time schema compilerContext.pushCompilationSchema(origCompilationSchema); } try { subquery.bindExpressions(nestedFromList); subquery.bindResultColumns(nestedFromList); } finally { if (origCompilationSchema != null) { compilerContext.popCompilationSchema(); } } if (orderByList != null) { orderByList.bindOrderByColumns(subquery); } bindOffsetFetch(offset, fetchFirst); /* NOTE: If the size of the derived column list is less than * the size of the subquery's RCL and the derived column list is marked * for allowing a size mismatch, then we have a select * view * on top of a table that has had columns added to it via alter table. * In this case, we trim out the columns that have been added to * the table since the view was created. */ subqueryRCL = subquery.getResultColumns(); if (resultColumns != null && resultColumns.getCountMismatchAllowed() && resultColumns.size() < subqueryRCL.size()) { for (int index = subqueryRCL.size() - 1; index >= resultColumns.size(); index--) { subqueryRCL.removeElementAt(index); } } /* * Create RCL based on subquery, adding a level of VCNs. */ ResultColumnList newRcl = subqueryRCL.copyListAndObjects(); newRcl.genVirtualColumnNodes(subquery, subquery.getResultColumns()); resultColumns = newRcl; /* Propagate the name info from the derived column list */ if (derivedRCL != null) { resultColumns.propagateDCLInfo(derivedRCL, correlationName); } }
/** * Make a ResultDescription for use in a PreparedStatement. * * <p>ResultDescriptions are visible to JDBC only for cursor statements. For other types of * statements, they are only used internally to get descriptions of the base tables being * affected. For example, for an INSERT statement, the ResultDescription describes the rows in the * table being inserted into, which is useful when the values being inserted are of a different * type or length than the columns in the base table. * * @return A ResultDescription for this DML statement */ public ResultDescription makeResultDescription() { ResultColumnDescriptor[] colDescs = resultSet.makeResultDescriptors(); String statementType = statementToString(); return getExecutionFactory().getResultDescription(colDescs, statementType); }
/** * Preprocess a ResultSetNode - this currently means: o Generating a referenced table map for each * ResultSetNode. o Putting the WHERE and HAVING clauses in conjunctive normal form (CNF). o * Converting the WHERE and HAVING clauses into PredicateLists and classifying them. o Ensuring * that a ProjectRestrictNode is generated on top of every FromBaseTable and generated in place of * every FromSubquery. o Pushing single table predicates down to the new ProjectRestrictNodes. * * @param numTables The number of tables in the DML Statement * @param gbl The group by list, if any * @param fromList The from list, if any * @return ResultSetNode at top of preprocessed tree. * @exception StandardException Thrown on error */ public ResultSetNode preprocess(int numTables, GroupByList gbl, FromList fromList) throws StandardException { // Push the order by list down to the ResultSet if (orderByList != null) { // If we have more than 1 ORDERBY columns, we may be able to // remove duplicate columns, e.g., "ORDER BY 1, 1, 2". if (orderByList.size() > 1) { orderByList.removeDupColumns(); } subquery.pushOrderByList(orderByList); orderByList = null; } subquery.pushOffsetFetchFirst(offset, fetchFirst, hasJDBClimitClause); /* We want to chop out the FromSubquery from the tree and replace it * with a ProjectRestrictNode. One complication is that there may be * ColumnReferences above us which point to the FromSubquery's RCL. * What we want to return is a tree with a PRN with the * FromSubquery's RCL on top. (In addition, we don't want to be * introducing any redundant ProjectRestrictNodes.) * Another complication is that we want to be able to only push * projections and restrictions down to this ProjectRestrict, but * we want to be able to push them through as well. * So, we: * o call subquery.preprocess() which returns a tree with * a SelectNode or a RowResultSetNode on top. * o If the FSqry is flattenable(), then we return (so that the * caller can then call flatten()), otherwise we: * o generate a PRN, whose RCL is the FSqry's RCL, on top of the result. * o create a referencedTableMap for the PRN which represents * the FSqry's tableNumber, since ColumnReferences in the outer * query block would be referring to that one. * (This will allow us to push restrictions down to the PRN.) */ subquery = subquery.preprocess(numTables, gbl, fromList); /* Return if the FSqry is flattenable() * NOTE: We can't flatten a FromSubquery if there is a group by list * because the group by list must be ColumnReferences. For: * select c1 from v1 group by c1, * where v1 is select 1 from t1 * The expression under the last redundant ResultColumn is an IntConstantNode, * not a ColumnReference. * We also do not flatten a subquery if tableProperties is non-null, * as the user is specifying 1 or more properties for the derived table, * which could potentially be lost on the flattening. * RESOLVE - this is too restrictive. */ if ((gbl == null || gbl.size() == 0) && tableProperties == null && subquery.flattenableInFromSubquery(fromList)) { /* Set our table map to the subquery's table map. */ setReferencedTableMap(subquery.getReferencedTableMap()); return this; } return extractSubquery(numTables); }
/** * This overload variant of optimizeStatement is used by subclass CursorNode (as well as a minion * for the no-arg variant). * * @param offset Any OFFSET row count, or null * @param fetchFirst Any FETCH FIRST row count or null * @exception StandardException Thrown on error * @see DMLStatementNode#optimizeStatement() */ protected void optimizeStatement(ValueNode offset, ValueNode fetchFirst) throws StandardException { resultSet = resultSet.preprocess(getCompilerContext().getNumTables(), null, (FromList) null); resultSet = resultSet.optimize(getDataDictionary(), null, 1.0d); resultSet = resultSet.modifyAccessPaths(); // Any OFFSET/FETCH FIRST narrowing must be done *after* any rewrite of // the query tree (if not, underlying GROUP BY fails), but *before* the // final scroll insensitive result node set is added - that one needs // to sit on top - so now is the time. // // This example statement fails if we wrap *before* the optimization // above: // select max(a) from t1 group by b fetch first row only // // A java.sql.ResultSet#previous on a scrollable result set will fail // if we don't wrap *after* the ScrollInsensitiveResultSetNode below. // // We need only wrap the RowCountNode set if at least one of the // clauses is present. if (offset != null || fetchFirst != null) { resultSet = wrapRowCountNode(resultSet, offset, fetchFirst); } /* If this is a cursor, then we * need to generate a new ResultSetNode to enable the scrolling * on top of the tree before modifying the access paths. */ if (this instanceof CursorNode) { ResultColumnList siRCList; ResultColumnList childRCList; ResultSetNode siChild = resultSet; /* We get a shallow copy of the ResultColumnList and its * ResultColumns. (Copy maintains ResultColumn.expression for now.) */ siRCList = resultSet.getResultColumns(); childRCList = siRCList.copyListAndObjects(); resultSet.setResultColumns(childRCList); /* Replace ResultColumn.expression with new VirtualColumnNodes * in the ScrollInsensitiveResultSetNode's ResultColumnList. (VirtualColumnNodes include * pointers to source ResultSetNode, this, and source ResultColumn.) */ siRCList.genVirtualColumnNodes(resultSet, childRCList); /* Finally, we create the new ScrollInsensitiveResultSetNode */ resultSet = (ResultSetNode) getNodeFactory() .getNode( C_NodeTypes.SCROLL_INSENSITIVE_RESULT_SET_NODE, resultSet, siRCList, null, getContextManager()); // Propagate the referenced table map if it's already been created if (siChild.getReferencedTableMap() != null) { resultSet.setReferencedTableMap((JBitSet) siChild.getReferencedTableMap().clone()); } } }
/** * Search to see if a query references the specifed table name. * * @param name Table name (String) to search for. * @param baseTable Whether or not name is for a base table * @return true if found, else false * @exception StandardException Thrown on error */ public boolean referencesTarget(String name, boolean baseTable) throws StandardException { return subquery.referencesTarget(name, baseTable); }
/** * Return true if the node references SESSION schema tables (temporary or permanent) * * @return true if references SESSION schema tables, else false * @exception StandardException Thrown on error */ public boolean referencesSessionSchema() throws StandardException { return subquery.referencesSessionSchema(); }
/** * Bind any untyped null nodes to the types in the given ResultColumnList. * * @param bindingRCL The ResultColumnList with the types to bind to. * @exception StandardException Thrown on error */ public void bindUntypedNullsToResultColumns(ResultColumnList bindingRCL) throws StandardException { subquery.bindUntypedNullsToResultColumns(bindingRCL); }
/** * Bind this subquery that appears in the FROM list. * * @param fromListParam FromList to use/append to. * @return ResultSetNode The bound FromSubquery. * @exception StandardException Thrown on error */ public ResultSetNode bindVTITables(FromList fromListParam) throws StandardException { subquery = subquery.bindVTITables(fromListParam); return this; }
/** * Decrement (query block) level (0-based) for this FromTable. This is useful when flattening a * subquery. * * @param decrement The amount to decrement by. */ void decrementLevel(int decrement) { super.decrementLevel(decrement); subquery.decrementLevel(decrement); }