📄 rowresultsetnode.java
字号:
* * @param numTables Number of tables in the DML Statement * @param gbl The group by list, if any * @param fromList The from list, if any * * @return The generated ProjectRestrictNode atop the original FromTable. * * @exception StandardException Thrown on error */ public ResultSetNode preprocess(int numTables, GroupByList gbl, FromList fromList) throws StandardException { if (subquerys.size() > 0) { subquerys.preprocess( numTables, (FromList) getNodeFactory().getNode( C_NodeTypes.FROM_LIST, getNodeFactory().doJoinOrderOptimization(), getContextManager()), (SubqueryList) getNodeFactory().getNode( C_NodeTypes.SUBQUERY_LIST, getContextManager()), (PredicateList) getNodeFactory().getNode( C_NodeTypes.PREDICATE_LIST, getContextManager())); } /* Allocate a dummy referenced table map */ referencedTableMap = new JBitSet(numTables); referencedTableMap.set(tableNumber); return this; } /** * Ensure that the top of the RSN tree has a PredicateList. * * @param numTables The number of tables in the query. * @return ResultSetNode A RSN tree with a node which has a PredicateList on top. * * @exception StandardException Thrown on error */ public ResultSetNode ensurePredicateList(int numTables) throws StandardException { return genProjectRestrict(numTables); } /** * Add a new predicate to the list. This is useful when doing subquery * transformations, when we build a new predicate with the left side of * the subquery operator and the subquery's result column. * * @param predicate The predicate to add * * @return ResultSetNode The new top of the tree. * * @exception StandardException Thrown on error */ public ResultSetNode addNewPredicate(Predicate predicate) throws StandardException { PredicateList predList; ResultColumnList prRCList; ResultSetNode newPRN; /* We are the body of a quantified predicate subquery. We * need to generate (and return) a PRN above us so that there will be * a place to attach the new predicate. */ /* We get a shallow copy of the ResultColumnList and its * ResultColumns. (Copy maintains ResultColumn.expression for now.) */ prRCList = resultColumns; resultColumns = resultColumns.copyListAndObjects(); /* Replace ResultColumn.expression with new VirtualColumnNodes * in the ProjectRestrictNode's ResultColumnList. (VirtualColumnNodes include * pointers to source ResultSetNode, this, and source ResultColumn.) */ prRCList.genVirtualColumnNodes(this, resultColumns); /* Put the new predicate in a list */ predList = (PredicateList) getNodeFactory().getNode( C_NodeTypes.PREDICATE_LIST, getContextManager()); predList.addPredicate(predicate); /* Finally, we create the new ProjectRestrictNode */ return (ResultSetNode) getNodeFactory().getNode( C_NodeTypes.PROJECT_RESTRICT_NODE, this, prRCList, null, /* Restriction */ predList, /* Restriction as PredicateList */ null, /* Project subquery list */ null, /* Restrict subquery list */ tableProperties, getContextManager() ); } /** * Evaluate whether or not the subquery in a FromSubquery is flattenable. * Currently, a FSqry is flattenable if all of the following are true: * o Subquery is a SelectNode or a RowResultSetNode (not a UnionNode) * o It contains no top level subqueries. (RESOLVE - we can relax this) * o It does not contain a group by or having clause * o It does not contain aggregates. * o There is at least one result set in the from list that is * not a RowResultSetNode (the reason is to avoid having * an outer SelectNode with an empty FromList. * * @param fromList The outer from list * * @return boolean Whether or not the FromSubquery is flattenable. */ public boolean flattenableInFromSubquery(FromList fromList) { if ((subquerys != null) && (subquerys.size() > 0)) { return false; } if ((aggregateVector != null) && (aggregateVector.size() > 0)) { return false; } /* ** Don't flatten if select list contains something ** that isn't clonable */ if ( ! resultColumns.isCloneable()) { return false; } boolean nonRowResultSetFound = false; int flSize = fromList.size(); for (int index = 0; index < flSize; index++) { FromTable ft = (FromTable) fromList.elementAt(index); if (ft instanceof FromSubquery) { ResultSetNode subq = ((FromSubquery) ft).getSubquery(); if ( ! (subq instanceof RowResultSetNode)) { nonRowResultSetFound = true; break; } } else { nonRowResultSetFound = true; break; } } return nonRowResultSetFound; } /** * Optimize this SelectNode. This means choosing the best access path * for each table, among other things. * * @param dataDictionary The DataDictionary to use for optimization * @param predicateList The predicate list to optimize against * @param outerRows The number of outer joining rows * * @return ResultSetNode The top of the optimized tree * * @exception StandardException Thrown on error */ public ResultSetNode optimize(DataDictionary dataDictionary, PredicateList predicateList, double outerRows) throws StandardException { /* ** Get an optimizer. The only reason we need one is to get a ** CostEstimate object, so we can represent the cost of this node. ** This seems like overkill, but it's just an object allocation... */ Optimizer optimizer = getOptimizer( (FromList) getNodeFactory().getNode( C_NodeTypes.FROM_LIST, getNodeFactory().doJoinOrderOptimization(), getContextManager()), predicateList, dataDictionary, (RequiredRowOrdering) null); costEstimate = optimizer.newCostEstimate(); // RESOLVE: THE COST SHOULD TAKE SUBQUERIES INTO ACCOUNT costEstimate.setCost(0.0d, outerRows, outerRows); subquerys.optimize(dataDictionary, outerRows); return this; } /** * @see Optimizable#modifyAccessPath * * @exception StandardException Thrown on error */ public Optimizable modifyAccessPath(JBitSet outerTables) throws StandardException { /* For most types of Optimizable, do nothing */ return (Optimizable) modifyAccessPaths(); } /** * @see ResultSetNode#modifyAccessPaths * * @exception StandardException Thrown on error */ public ResultSetNode modifyAccessPaths() throws StandardException { ResultSetNode treeTop = this; subquerys.modifyAccessPaths(); /* Generate the OrderByNode if a sort is still required for * the order by. */ if (orderByList != null) { treeTop = (ResultSetNode) getNodeFactory().getNode( C_NodeTypes.ORDER_BY_NODE, treeTop, orderByList, tableProperties, getContextManager()); } return treeTop; } /** * Return whether or not this ResultSet tree is guaranteed to return * at most 1 row based on heuristics. (A RowResultSetNode and a * SELECT with a non-grouped aggregate will return at most 1 row.) * * @return Whether or not this ResultSet tree is guaranteed to return * at most 1 row based on heuristics. */ boolean returnsAtMostOneRow() { return true; } /** * The generated ResultSet will be: * * RowResultSet -- for the VALUES clause * * * @return A compiled Expression returning a ResultSet * * @exception StandardException Thrown on error */ public void generate(ActivationClassBuilder acb, MethodBuilder mb) throws StandardException { if (SanityManager.DEBUG) SanityManager.ASSERT(resultColumns != null, "Tree structure bad"); // Get our final cost estimate. costEstimate = getFinalCostEstimate(); /* ** Check and see if everything below us is a constant or not. ** If so, we'll let execution know that it can do some caching. ** Before we do the check, we are going to temporarily set */ boolean canCache = canWeCacheResults(); /* Get the next ResultSet #, so that we can number this ResultSetNode, its * ResultColumnList and ResultSet. */ assignResultSetNumber(); // we are dealing with // VALUES(value1, value2, value3) // so we generate a RowResultSet to return the values listed. // we can reduce the tree to one RowResultSet // since there is nothing but the resultColumns // RowResultSet takes the row-generating function // so we generate one and get back the expression // pointing to it. // // generate the expression to return, which is: // ResultSetFactory.getRowResultSet(this, planX.exprN) // [planX is the name of the class being generated, // exprN is the name of the function being generated.] acb.pushGetResultSetFactoryExpression(mb); acb.pushThisAsActivation(mb); resultColumns.generate(acb, mb); mb.push(canCache); mb.push(resultSetNumber); mb.push(costEstimate.rowCount()); mb.push(costEstimate.getEstimatedCost()); closeMethodArgument(acb, mb); mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, "getRowResultSet", ClassName.NoPutResultSet, 7); } /** * Replace any DEFAULTs with the associated tree for the default. * * @param ttd The TableDescriptor for the target table. * @param tcl The RCL for the target table. * * @exception StandardException Thrown on error */ void replaceDefaults(TableDescriptor ttd, ResultColumnList tcl) throws StandardException { resultColumns.replaceDefaults(ttd, tcl); } /** * Optimize any subqueries that haven't been optimized any where * else. This is useful for a RowResultSetNode as a derived table * because it doesn't get optimized otherwise. * * @return Nothing. * * @exception StandardException Thrown on error */ void optimizeSubqueries(DataDictionary dd, double rowCount) throws StandardException { subquerys.optimize(dd, rowCount); } /** * Notify the underlying result set tree that the result is * ordering dependent. (For example, no bulk fetch on an index * if under an IndexRowToBaseRow.) * * @return Nothing. */ void markOrderingDependent() { } /* ** Check and see if everything below us is a constant or not. ** If so, we'll let execution know that it can do some caching. ** Before we do the check, we are going to temporarily set ** ParameterNodes to CONSTANT. We do this because we know ** that we can cache a row with a parameter value and get ** the param column reset by the user setting a param, so ** we can skip over parameter nodes. We are doing this ** extra work to optimize inserts of the form: ** ** prepare: insert into mytab values (?,?); ** setParam ** execute() ** setParam ** execute() */ private boolean canWeCacheResults() throws StandardException { /* ** Check the tree below us */ HasVariantValueNodeVisitor visitor = new HasVariantValueNodeVisitor(Qualifier.QUERY_INVARIANT, true); super.accept(visitor); boolean canCache = !visitor.hasVariant(); return canCache; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -