📄 selectnode.java
字号:
if (whereSubquerys != null && whereSubquerys.size() > 0) { whereSubquerys.optimize(dataDictionary, costEstimate.rowCount()); } return this; } /** * Modify the access paths according to the decisions the optimizer * made. This can include adding project/restrict nodes, * index-to-base-row nodes, etc. * * @param predList A list of optimizable predicates that should * be pushed to this ResultSetNode, as determined by optimizer. * @return The modified query tree * @exception StandardException Thrown on error */ public ResultSetNode modifyAccessPaths(PredicateList predList) throws StandardException { // Take the received list of predicates and propagate them to the // predicate list for this node's optimizer. Then, when we call // optimizer.modifyAccessPaths(), the optimizer will have the // predicates and can push them down as necessary, according // the join order that it has chosen. if (SanityManager.DEBUG) { SanityManager.ASSERT(optimizer != null, "SelectNode's optimizer not expected to be null when " + "modifying access paths."); } ((OptimizerImpl)optimizer).addPredicatesToList(predList); return modifyAccessPaths(); } /** * Modify the access paths according to the choices the optimizer made. * * @return A QueryTree with the necessary modifications made * * @exception StandardException Thrown on error */ public ResultSetNode modifyAccessPaths() throws StandardException { int origFromListSize = fromList.size(); ResultColumnList leftRCList; ResultColumnList rightRCList; ResultSetNode leftResultSet; ResultSetNode rightResultSet; /* ** Modify the access path for each Optimizable, as necessary ** ** This should be the same optimizer we got above. */ optimizer.modifyAccessPaths(); // Load the costEstimate for the final "best" join order. costEstimate = optimizer.getFinalCost(); if (SanityManager.DEBUG) { // When we optimized this select node, we may have added pushable // outer predicates to the wherePredicates list for this node // (see the optimize() method above). When we did so, we said // that all such predicates should have been removed from the // where list by the time optimization was completed. So we // check that here, just to be safe. NOTE: We do this _after_ // calling optimizer.modifyAccessPaths(), because it's only in // that call that the scoped predicates are officially pushed // and thus removed from the list. if (wherePredicates != null) { Predicate pred = null; for (int i = wherePredicates.size() - 1; i >= 0; i--) { pred = (Predicate)wherePredicates.getOptPredicate(i); if (pred.isScopedForPush()) { SanityManager.THROWASSERT("Found scoped predicate " + pred.binaryRelOpColRefsToString() + " in WHERE list when no scoped predicates were" + " expected."); } } } } selectSubquerys.modifyAccessPaths(); if (whereSubquerys != null && whereSubquerys.size() > 0) { whereSubquerys.modifyAccessPaths(); } /* Build a temp copy of the current FromList for sort elimination, etc. */ preJoinFL.removeAllElements(); preJoinFL.nondestructiveAppend(fromList); /* Now we build a JoinNode tree from the bottom up until there is only * a single entry in the fromList and that entry points to the top of * the JoinNode tree. * * While there is still more than 1 entry in the list, create a JoinNode * which points to the 1st 2 entries in the list. This JoinNode becomes * the new 1st entry in the list and the 2nd entry is deleted. The * old 1st and 2nd entries will get shallow copies of their * ResultColumnLists. The JoinNode's ResultColumnList will be the * concatenation of the originals from the old 1st and 2nd entries. * The virtualColumnIds will be updated to reflect there new positions * and each ResultColumn.expression will be replaced with a new * VirtualColumnNode. */ while (fromList.size() > 1) { /* Get left's ResultColumnList, assign shallow copy back to it * and create new VirtualColumnNodes for the original's * ResultColumn.expressions. */ leftResultSet = (ResultSetNode) fromList.elementAt(0); leftRCList = leftResultSet.getResultColumns(); leftResultSet.setResultColumns(leftRCList.copyListAndObjects()); leftRCList.genVirtualColumnNodes(leftResultSet, leftResultSet.resultColumns); /* Get right's ResultColumnList, assign shallow copy back to it, * create new VirtualColumnNodes for the original's * ResultColumn.expressions and increment the virtualColumnIds. * (Right gets appended to left, so only right's ids need updating.) */ rightResultSet = (ResultSetNode) fromList.elementAt(1); rightRCList = rightResultSet.getResultColumns(); rightResultSet.setResultColumns(rightRCList.copyListAndObjects()); rightRCList.genVirtualColumnNodes(rightResultSet, rightResultSet.resultColumns); rightRCList.adjustVirtualColumnIds(leftRCList.size()); /* Concatenate the 2 ResultColumnLists */ leftRCList.nondestructiveAppend(rightRCList); /* Now we're finally ready to generate the JoinNode and have it * replace the 1st 2 entries in the FromList. */ fromList.setElementAt( (JoinNode) getNodeFactory().getNode( C_NodeTypes.JOIN_NODE, leftResultSet, rightResultSet, null, null, leftRCList, null, getContextManager() ), 0 ); fromList.removeElementAt(1); } return genProjectRestrict(origFromListSize); } /** * Get the final CostEstimate for this SelectNode. * * @return The final CostEstimate for this SelectNode, which is * the final cost estimate for the best join order of * this SelectNode's optimizer. */ public CostEstimate getFinalCostEstimate() throws StandardException { return optimizer.getFinalCost(); } /** Determine if this select is updatable or not, for a cursor. */ boolean isUpdatableCursor(DataDictionary dd) throws StandardException { TableDescriptor targetTableDescriptor; if (isDistinct) { if (SanityManager.DEBUG) SanityManager.DEBUG("DumpUpdateCheck","cursor select has distinct"); return false; } if ((selectAggregates == null) || (selectAggregates.size() > 0)) { return false; } if (groupByList != null || generatedForHavingClause) { return false; } if (SanityManager.DEBUG) SanityManager.ASSERT(fromList!=null, "select must have from tables"); if (fromList.size() != 1) { if (SanityManager.DEBUG) SanityManager.DEBUG("DumpUpdateCheck","cursor select has more than one from table"); return false; } targetTable = (FromTable)(fromList.elementAt(0)); if (targetTable instanceof FromVTI) { return ((FromVTI) targetTable).isUpdatableCursor(); } if (! (targetTable instanceof FromBaseTable)) { if (SanityManager.DEBUG) SanityManager.DEBUG("DumpUpdateCheck","cursor select has non base table as target table"); return false; } /* Get the TableDescriptor and verify that it is not for a * view or a system table. * NOTE: We need to use the base table name for the table. * Simplest way to get it is from a FromBaseTable. We * know that targetTable is a FromBaseTable because of check * just above us. * NOTE: We also need to use the base table's schema name; otherwise * we will think it is the default schema Beetle 4417 */ targetTableDescriptor = getTableDescriptor( ((FromBaseTable)targetTable).getBaseTableName(), getSchemaDescriptor(((FromBaseTable)targetTable).getTableNameField().getSchemaName())); if (targetTableDescriptor.getTableType() == TableDescriptor.SYSTEM_TABLE_TYPE) { if (SanityManager.DEBUG) SanityManager.DEBUG("DumpUpdateCheck","cursor select is on system table"); return false; } if (targetTableDescriptor.getTableType() == TableDescriptor.VIEW_TYPE) { if (SanityManager.DEBUG) SanityManager.DEBUG("DumpUpdateCheck","cursor select is on view"); return false; } if ((getSelectSubquerys() != null) && (getSelectSubquerys().size() != 0)) { if (SanityManager.DEBUG) SanityManager.DEBUG("DumpUpdateCheck","cursor select has subquery in SELECT list"); return false; } if ((getWhereSubquerys() != null) && (getWhereSubquerys().size() != 0)) { if (SanityManager.DEBUG) SanityManager.DEBUG("DumpUpdateCheck","cursor select has subquery in WHERE clause"); return false; } return true; } /** Assumes that isCursorUpdatable has been called, and that it is only called for updatable cursors. */ FromTable getCursorTargetTable() { if (SanityManager.DEBUG) SanityManager.ASSERT(targetTable!=null, "must call isUpdatableCursor() first, and must be updatable"); return targetTable; } /** * 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 { if (fromList.referencesTarget(name, baseTable) || (selectSubquerys != null && selectSubquerys.referencesTarget(name, baseTable)) || (whereSubquerys != null && whereSubquerys.referencesTarget(name, baseTable)) ) { return true; } return false; } /** * Return whether or not this ResultSetNode contains a subquery with a * reference to the specified target table. * * @param name The table name. * @param baseTable Whether or not table is a base table. * * @return boolean Whether or not a reference to the table was found. * * @exception StandardException Thrown on error */ boolean subqueryReferencesTarget(String name, boolean baseTable) throws StandardException { if ((selectSubquerys != null && selectSubquerys.referencesTarget(name, baseTable)) || (whereSubquerys != null && whereSubquerys.referencesTarget(name, baseTable)) ) { return true; } return false; } /** * 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 { fromList.bindUntypedNullsToResultColumns(bindingRCL); } /** * Decrement (query block) level (0-based) for * all of the tables in this ResultSet tree. * This is useful when flattening a subquery. * * @param decrement The amount to decrement by. * * @return Nothing; */ void decrementLevel(int decrement) { /* Decrement the level in the tables */ fromList.decrementLevel(decrement); selectSubquerys.decrementLevel(decrement); whereSubquerys.decrementLevel(decrement); /* Decrement the level in any CRs in predicates * that are interesting to transitive closure. */ wherePredicates.decrementLevel(fromList, decrement); } /** * Determine whether or not this subquery, * the SelectNode is in a subquery, can be flattened * into the outer query block based on a uniqueness condition. * A uniqueness condition exists when we can guarantee * that at most 1 row will qualify in each table in the * subquery. This is true if every table in the from list is * (a base table and the set of columns from the table that * are in equality comparisons with expressions that do not * include a column from the same table is a superset of any unique index * on the table) or an ExistsBaseTable. * * @param additionalEQ Whether or not the column returned * by this select, if it is a ColumnReference, * is in an equality comparison. * * @return Whether or not this subquery can be flattened based * on a uniqueness condition. * * @exception StandardException Thrown on error */ boolean uniqueSubquery(boolean additionalEQ) throws StandardException { ColumnReference additionalCR = null; ResultColumn rc = (ResultColumn) getResultColumns().elementAt(0); /* Figure out if we have an additional ColumnReference * in an equality comparison. */ if (additionalEQ && rc.getExpression() instanceof ColumnReference) { additionalCR = (ColumnReference) rc.getExpression(); /* ColumnReference only interesting if it is * not correlated. */ if (additionalCR.getCorrelated()) { additionalCR = null; } } return fromList.returnsAtMostSingleRow((additionalCR == null) ? null : getResultColumns(), whereClause, wherePredicates, getDataDictionary()); } /** * Get the lock mode for the target of an update statement * (a delete or update). The update mode will always be row for * CurrentOfNodes. It will be table if there is no where clause. * * @see TransactionController * * @return The lock mode */ public int updateTargetLockMode() { /* Do row locking if there is a restriction */ re
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -