📄 selectnode.java
字号:
* Bind the tables in this SelectNode. This includes getting their * TableDescriptors from the DataDictionary and numbering the FromTables. * NOTE: Because this node represents the top of a new query block, we bind * both the non VTI and VTI tables under this node in this method call. * * @param dataDictionary The DataDictionary to use for binding * @param fromListParam FromList to use/append to. * * @return ResultSetNode * * @exception StandardException Thrown on error */ public ResultSetNode bindNonVTITables(DataDictionary dataDictionary, FromList fromListParam) throws StandardException { int fromListParamSize = fromListParam.size(); int fromListSize = fromList.size(); int nestingLevel; FromList fromListClone = (FromList) getNodeFactory().getNode( C_NodeTypes.FROM_LIST, getNodeFactory().doJoinOrderOptimization(), getContextManager()); wherePredicates = (PredicateList) getNodeFactory().getNode( C_NodeTypes.PREDICATE_LIST, getContextManager()); preJoinFL = (FromList) getNodeFactory().getNode( C_NodeTypes.FROM_LIST, getNodeFactory().doJoinOrderOptimization(), getContextManager()); /* Set the nesting level in the fromList */ if (fromListParam.size() == 0) { nestingLevel = 0; } else { nestingLevel = ((FromTable) fromListParam.elementAt(0)).getLevel() + 1; } fromList.setLevel(nestingLevel); /* Splice a clone of our FromList on to the beginning of fromListParam, before binding * the tables, for correlated column resolution in VTIs. */ for (int index = 0; index < fromListSize; index++) { fromListParam.insertElementAt(fromList.elementAt(index), 0); } // Now bind our from list fromList.bindTables(dataDictionary, fromListParam); /* Restore fromListParam */ for (int index = 0; index < fromListSize; index++) { fromListParam.removeElementAt(0); } return this; } /** * Bind the expressions in this SelectNode. This means binding the * sub-expressions, as well as figuring out what the return type is * for each expression. * * @param fromListParam FromList to use/append to. * * @return Nothing * * @exception StandardException Thrown on error */ public void bindExpressions(FromList fromListParam) throws StandardException { int fromListParamSize = fromListParam.size(); int fromListSize = fromList.size(); int numDistinctAggs; if (SanityManager.DEBUG) SanityManager.ASSERT(fromList != null && resultColumns != null, "Both fromList and resultColumns are expected to be non-null"); /* NOTE - a lot of this code would be common to bindTargetExpression(), * so we use a private boolean to share the code instead of duplicating * it. bindTargetExpression() is responsible for toggling the boolean. */ if (! bindTargetListOnly) { /* Bind the expressions in FromSubquerys, JoinNodes, etc. */ fromList.bindExpressions(); } selectSubquerys = (SubqueryList) getNodeFactory().getNode( C_NodeTypes.SUBQUERY_LIST, getContextManager()); selectAggregates = new Vector(); /* Splice our FromList on to the beginning of fromListParam, before binding * the expressions, for correlated column resolution. */ for (int index = 0; index < fromListSize; index++) { fromListParam.insertElementAt(fromList.elementAt(index), index); } resultColumns.setClause(ValueNode.IN_SELECT_LIST); resultColumns.bindExpressions(fromListParam, selectSubquerys, selectAggregates); /* We're done if we're only binding the target list. * (After we restore the fromList, of course.) */ if (bindTargetListOnly) { for (int index = 0; index < fromListSize; index++) { fromListParam.removeElementAt(0); } return; } whereAggregates = new Vector(); whereSubquerys = (SubqueryList) getNodeFactory().getNode( C_NodeTypes.SUBQUERY_LIST, getContextManager()); if (whereClause != null) { whereClause = whereClause.bindExpression(fromListParam, whereSubquerys, whereAggregates); /* RESOLVE - Temporarily disable aggregates in the HAVING clause. ** (We may remove them in the parser anyway.) ** RESOLVE - Disable aggregates in the WHERE clause. Someday ** Aggregates will be allowed iff they are in a subquery ** of the having clause and they correlate to an outer ** query block. For now, aggregates are not supported ** in the WHERE clause at all. ** Note: a similar check is made in JoinNode. */ if ((whereAggregates.size() > 0) && !generatedForHavingClause) { throw StandardException.newException(SQLState.LANG_NO_AGGREGATES_IN_WHERE_CLAUSE); } /* If whereClause is a parameter, (where ?), then we should catch it and throw exception */ if (whereClause.isParameterNode()) { throw StandardException.newException(SQLState.LANG_NON_BOOLEAN_WHERE_CLAUSE, "PARAMETER" ); } whereClause = whereClause.checkIsBoolean(); } /* Restore fromList */ for (int index = 0; index < fromListSize; index++) { fromListParam.removeElementAt(0); } if (SanityManager.DEBUG) { SanityManager.ASSERT(fromListParam.size() == fromListParamSize, "fromListParam.size() = " + fromListParam.size() + ", expected to be restored to " + fromListParamSize); SanityManager.ASSERT(fromList.size() == fromListSize, "fromList.size() = " + fromList.size() + ", expected to be restored to " + fromListSize); } /* If query is grouped, bind the group by list. */ if (groupByList != null) { Vector gbAggregateVector = new Vector(); groupByList.bindGroupByColumns(this, gbAggregateVector); /* ** There should be no aggregates in the Group By list. ** We don't expect any, but just to be on the safe side ** we will check under sanity. */ if (SanityManager.DEBUG) { SanityManager.ASSERT(gbAggregateVector.size() == 0, "Unexpected Aggregate vector generated by Group By clause"); } } /* If ungrouped query with aggregates in SELECT list, verify * that all result columns are valid aggregate expressions - * no column references outside of an aggregate. * If grouped query with aggregates in SELECT list, verify that all * result columns are either grouping columns or valid * grouped aggregate expressions - the only column references allowed * outside of an aggregage are columns in the group by list. */ if (groupByList != null || selectAggregates.size() > 0) { VerifyAggregateExpressionsVisitor visitor = new VerifyAggregateExpressionsVisitor(groupByList); resultColumns.accept(visitor); } /* ** RESOLVE: for now, only one distinct aggregate is supported ** in the select list. */ numDistinctAggs = numDistinctAggregates(selectAggregates); if (numDistinctAggs > 1) { throw StandardException.newException(SQLState.LANG_USER_AGGREGATE_MULTIPLE_DISTINCTS); } } /** * Bind the expressions in this ResultSetNode if it has tables. This means binding the * sub-expressions, as well as figuring out what the return type is for * each expression. * * @param fromListParam FromList to use/append to. * * @return Nothing * * @exception StandardException Thrown on error */ public void bindExpressionsWithTables(FromList fromListParam) throws StandardException { /* We have tables, so simply call bindExpressions() */ bindExpressions(fromListParam); } /** * Bind the expressions in the target list. This means binding the * sub-expressions, as well as figuring out what the return type is * for each expression. This is useful for EXISTS subqueries, where we * need to validate the target list before blowing it away and replacing * it with a SELECT true. * * @return Nothing * * @exception StandardException Thrown on error */ public void bindTargetExpressions(FromList fromListParam) throws StandardException { bindTargetListOnly = true; bindExpressions(fromListParam); bindTargetListOnly = false; } /** * Bind the result columns of this ResultSetNode when there is no * base table to bind them to. This is useful for SELECT statements, * where the result columns get their types from the expressions that * live under them. * * @param fromListParam FromList to use/append to. * * @return Nothing * * @exception StandardException Thrown on error */ public void bindResultColumns(FromList fromListParam) throws StandardException { /* We first bind the resultColumns for any FromTable which * needs its own binding, such as JoinNodes. * We pass through the fromListParam without adding our fromList * to it, since the elements in our fromList can only be correlated * with outer query blocks. */ fromList.bindResultColumns(fromListParam); super.bindResultColumns(fromListParam); /* Only 1012 elements allowed in select list */ if (resultColumns.size() > Limits.DB2_MAX_ELEMENTS_IN_SELECT_LIST) { throw StandardException.newException(SQLState.LANG_TOO_MANY_ELEMENTS); } /* Fix nullability in case of any outer joins in the fromList */ if (fromList.hasOuterJoins()) resultColumns.setNullability(true); } /** * Bind the result columns for this ResultSetNode to a base table. * This is useful for INSERT and UPDATE statements, where the * result columns get their types from the table being updated or * inserted into. * If a result column list is specified, then the verification that the * result column list does not contain any duplicates will be done when * binding them by name. * * @param targetTableDescriptor The TableDescriptor for the table being * updated or inserted into * @param targetColumnList For INSERT statements, the user * does not have to supply column * names (for example, "insert into t * values (1,2,3)". When this * parameter is null, it means that * the user did not supply column * names, and so the binding should * be done based on order. When it * is not null, it means do the binding * by name, not position. * @param statement Calling DMLStatementNode (Insert or Update) * @param fromListParam FromList to use/append to. * * @return Nothing * * @exception StandardException Thrown on error */ public void bindResultColumns(TableDescriptor targetTableDescriptor, FromVTI targetVTI, ResultColumnList targetColumnList, DMLStatementNode statement, FromList fromListParam) throws StandardException { /* We first bind the resultColumns for any FromTable which * needs its own binding, such as JoinNodes. * We pass through the fromListParam without adding our fromList * to it, since the elements in our fromList can only be correlated * with outer query blocks. */ fromList.bindResultColumns(fromListParam); super.bindResultColumns(targetTableDescriptor, targetVTI, targetColumnList, statement, fromListParam); } /** * Push an expression into this SELECT (and possibly down into * one of the tables in the FROM list). This is useful when * trying to push predicates into unflattened views or * derived tables. * * @param predicate The predicate that we attempt to push * * @return None * * @exception StandardException Thrown on error */ void pushExpressionsIntoSelect(Predicate predicate) throws StandardException { wherePredicates.pullExpressions(referencedTableMap.size(), predicate.getAndNode()); fromList.pushPredicates(wherePredicates); } /** * Verify that a SELECT * is valid for this type of subquery. * * @param outerFromList The FromList from the outer query block(s) * @param subqueryType The subquery type * * @return None * * @exception StandardException Thrown on error */ public void verifySelectStarSubquery(FromList outerFromList, int subqueryType) throws StandardException { if (! ((ResultColumn) resultColumns.elementAt(0) instanceof AllResultColumn) ) { return; } /* Select * always okay when SelectNode generated to wrap * GROUP BY or HAVING. */ if (generatedForGroupByClause || generatedForHavingClause) { return; } /* Select * currently only valid for EXISTS/NOT EXISTS. * NOT EXISTS does not appear prior to preprocessing. */ if (subqueryType != SubqueryNode.EXISTS_SUBQUERY) { throw StandardException.newException(SQLState.LANG_CANT_SELECT_STAR_SUBQUERY); } /* If the AllResultColumn is qualified, then we have to verify * that the qualification is a valid exposed name. * NOTE: The exposed name can come from an outer query block. */ String fullTableName; fullTableName = ((AllResultColumn) resultColumns.elementAt(0)).getFullTableName(); if (fullTableName != null) { if (fromList.getFromTableByName(fullTableName, null, true) == null && outerFromList.getFromTableByName(fullTableName, null, true) == null) { if (fromList.getFromTableByName(fullTableName, null, false) == null && outerFromList.getFromTableByName(fullTableName, null, false) == null) { throw StandardException.newException(SQLState.LANG_EXPOSED_NAME_NOT_FOUND, fullTableName); } } } } /**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -