📄 fromlist.java
字号:
if (fromTable instanceof HalfOuterJoinNode) return true; } return false; } /** * Expand a "*" into the appropriate ResultColumnList. If the "*" * is unqualified it will expand into a list of all columns in all * of the base tables in the from list, otherwise it will expand * into a list of all of the columns in the base table that matches * the qualification. * * @param allTableName The qualification on the "*" as a String. * * @return ResultColumnList representing expansion * * @exception StandardException Thrown on error */ public ResultColumnList expandAll(TableName allTableName) throws StandardException { ResultColumnList resultColumnList = null; ResultColumnList tempRCList = null; boolean matchfound = false; FromTable fromTable; /* Expand the "*" for the table that matches, if it is qualified * (allTableName is not null) or for all tables in the list if the * "*" is not qualified (allTableName is null). */ int size = size(); for (int index = 0; index < size; index++) { fromTable = (FromTable) elementAt(index); fromTable.setAllColumnsProjected(true); /* We let the FromTable decide if there is a match on * the exposed name. (A JoinNode will not have an * exposed name, so it will need to pass the info to its * left and right children.) */ tempRCList = fromTable.getAllResultColumns(allTableName); if (tempRCList == null) { continue; } /* Expand the column list and append to the list that * we will return. */ if (resultColumnList == null) { resultColumnList = tempRCList; } else { resultColumnList.nondestructiveAppend(tempRCList); } /* If the "*" is qualified, then we can stop the * expansion as soon as we find the matching table. */ if (allTableName != null) { matchfound = true; } } /* Give an error if the qualification name did not match * an exposed name */ if (resultColumnList == null) { throw StandardException.newException(SQLState.LANG_EXPOSED_NAME_NOT_FOUND, allTableName); } return resultColumnList; } /** * Bind a column reference to one of the tables in this FromList. The column name * must be unique within the tables in the FromList. An exception is thrown * if a column name is not unique. * * NOTE: Callers are responsible for ordering the FromList by nesting level, * with tables at the deepest (current) nesting level first. We will try to * match against all FromTables at a given nesting level. If no match is * found at a nesting level, then we proceed to the next level. We stop * walking the list when the nesting level changes and we have found a match. * * NOTE: If the ColumnReference is qualified, then we will stop the search * at the first nesting level where there is a match on the exposed table name. * For example, s (a, b, c), t (d, e, f) * select * from s where exists (select * from t s where s.c = a) * will not find a match for s.c, which is the expected ANSI behavior. * * bindTables() must have already been called on this FromList before * calling this method. * * @param columnReference The ColumnReference describing the column to bind * * @return ResultColumn The matching ResultColumn * * @exception StandardException Thrown on error */ public ResultColumn bindColumnReference(ColumnReference columnReference) throws StandardException { boolean columnNameMatch = false; boolean tableNameMatch = false; FromTable fromTable; int currentLevel = -1; int previousLevel = -1; ResultColumn matchingRC = null; ResultColumn resultColumn; String crTableName = columnReference.getTableName(); /* ** Find the first table with matching column name. If there ** is more than one table with a matching column name at the same ** nesting level, give an error. */ int size = size(); for (int index = 0; index < size; index++) { fromTable = (FromTable) elementAt(index); /* We can stop if we've found a matching column or table name * at the previous nesting level. */ currentLevel = fromTable.getLevel(); if (previousLevel != currentLevel) { if (columnNameMatch) { break; } if (tableNameMatch) { break; } } /* Simpler to always set previousLevel then to test and set */ previousLevel = currentLevel; resultColumn = fromTable.getMatchingColumn(columnReference); if (resultColumn != null) { if (! columnNameMatch) { /* TableNumbers are set in the CR in the underlying * FromTable. This ensures that they get the table * number from the underlying table, not the join node. * This is important for beging able to push predicates * down through join nodes. */ matchingRC = resultColumn; columnReference.setSource(resultColumn); columnReference.setType(resultColumn.getTypeServices()); /* Set the nesting level at which the CR appears and the nesting level * of its source RC. */ columnReference.setNestingLevel(((FromTable) elementAt(0)).getLevel()); columnReference.setSourceLevel(currentLevel); columnNameMatch = true; } else { throw StandardException.newException(SQLState.LANG_AMBIGUOUS_COLUMN_NAME, columnReference.getSQLColumnName()); } } /* Remember if we get a match on the exposed table name, so that * we can stop at the beginning of the next level. */ tableNameMatch = tableNameMatch || (crTableName != null && crTableName.equals(fromTable.getExposedName()) ); } return matchingRC; } /** * Check for (and reject) all ? parameters directly under the ResultColumns. * This is done for SELECT statements. * * @return Nothing * * @exception StandardException Thrown if a ? parameter found * directly under a ResultColumn */ public void rejectParameters() throws StandardException { FromTable fromTable; int size = size(); for (int index = 0; index < size; index++) { fromTable = (FromTable) elementAt(index); fromTable.rejectParameters(); } } // This method reorders LOJs in the FROM clause. // For now, we process only a LOJ. For example, "... from LOJ_1, LOJ2 ..." // will not be processed. public boolean LOJ_reorderable(int numTables) throws StandardException { boolean anyChange = false; if (size() > 1) return anyChange; FromTable ft = (FromTable) elementAt(0); anyChange = ft.LOJ_reorderable(numTables); return anyChange; } /** * Preprocess the query tree - 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 Flatten those FromSubqueries which can be flattened. * o Ensuring that a ProjectRestrictNode is generated on top of every * FromBaseTable and generated in place of every FromSubquery which * could not be flattened. * 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 * * @return Nothing. * * @exception StandardException Thrown on error */ public void preprocess(int numTables, GroupByList gbl, ValueNode predicateTree) throws StandardException { int size = size(); /* Preprocess each FromTable in the list */ for (int index = 0; index < size; index++) { FromTable ft = (FromTable) elementAt(index); /* Transform any outer joins to inner joins where appropriate */ ft = ft.transformOuterJoins(predicateTree, numTables); /* Preprocess this FromTable */ setElementAt(ft.preprocess(numTables, gbl, this), index); } } /** * Flatten all the FromTables that are flattenable. * RESOLVE - right now we just flatten FromSubqueries. We * should also flatten flattenable JoinNodes here. * * @param rcl The RCL from the outer query * @param predicateList The PredicateList from the outer query * @param sql The SubqueryList from the outer query * @param gbl The group by list, if any * * @exception StandardException Thrown on error */ public void flattenFromTables(ResultColumnList rcl, PredicateList predicateList, SubqueryList sql, GroupByList gbl) throws StandardException { boolean flattened = true; Vector flattenedTableNumbers = new Vector(); if (SanityManager.DEBUG) { SanityManager.ASSERT(rcl != null, "rcl is expected to be non-null"); SanityManager.ASSERT(predicateList != null, "predicateList is expected to be non-null"); SanityManager.ASSERT(sql != null, "sql is expected to be non-null"); } /* Loop until all flattenable entries are flattened. * We restart the inner loop after flattening an in place * to simplify the logic and so that we don't have to worry * about walking a list while we are modifying it. */ while (flattened) { flattened = false; for (int index = 0; index < size() && ! flattened; index++) { FromTable ft = (FromTable) elementAt(index); /* Flatten FromSubquerys and flattenable JoinNodes */ if ((ft instanceof FromSubquery) || ft.isFlattenableJoinNode()) { //save the table number of the node to be flattened flattenedTableNumbers.addElement(new Integer(ft.getTableNumber())); /* Remove the node from the list and insert its * FromList here. */ FromList flatteningFL = ft.flatten( rcl, predicateList, sql, gbl); if (SanityManager.DEBUG) { SanityManager.ASSERT(flatteningFL == null || flatteningFL.size() > 0, "flatteningFL expected to be null or size > 0"); } if (flatteningFL != null) { setElementAt(flatteningFL.elementAt(0), index); int innerSize = flatteningFL.size(); for (int inner = 1; inner < innerSize; inner++) { insertElementAt(flatteningFL.elementAt(inner), index + inner); } } else { /* ** If flatten returns null, that means it wants to ** be removed from the FromList. */ removeElementAt(index); } flattened = true; } } } /* fix up dependency maps for exists base tables since they might have a * dependency on this join node */ if (flattenedTableNumbers.size() > 0) { for (int i = 0; i < size(); i++) { FromTable ft = (FromTable) elementAt(i); if (ft instanceof ProjectRestrictNode) { ResultSetNode rst = ((ProjectRestrictNode)ft).getChildResult(); if (rst instanceof FromBaseTable) { ((FromBaseTable)rst).clearDependency(flattenedTableNumbers); } } } } } /** * Categorize and push the predicates that are pushable. * * @param predicateList The query's PredicateList * * @exception StandardException Thrown on error */ void pushPredicates(PredicateList predicateList) throws StandardException { if (SanityManager.DEBUG) { SanityManager.ASSERT(predicateList != null, "predicateList is expected to be non-null"); } /* We can finally categorize each Predicate and try to push them down. * NOTE: The PredicateList may be empty, but that's okay, we still * call pushExpressions() for each entry in the FromList because that's * where any outer join conditions will get pushed down. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -