📄 setoperatornode.java
字号:
*/
// See if we already have a scoped version of the predicate cached,
// and if so just use that.
Predicate scopedPred = null;
if (leftScopedPreds == null)
leftScopedPreds = new HashMap();
else
scopedPred = (Predicate)leftScopedPreds.get(pred);
if (scopedPred == null)
{
scopedPred = pred.getPredScopedForResultSet(
tableNums, leftResultSet);
leftScopedPreds.put(pred, scopedPred);
}
// Add the scoped predicate to our list for the left child.
getLeftOptPredicateList().addOptPredicate(scopedPred);
scopedPred = null;
if (rightScopedPreds == null)
rightScopedPreds = new HashMap();
else
scopedPred = (Predicate)rightScopedPreds.get(pred);
if (scopedPred == null)
{
scopedPred = pred.getPredScopedForResultSet(
tableNums, rightResultSet);
rightScopedPreds.put(pred, scopedPred);
}
// Add the scoped predicate to our list for the right child.
getRightOptPredicateList().addOptPredicate(scopedPred);
// Restore the original predicate to the way it was before we got
// here--i.e. remap it again if needed.
if (opWasRemapped)
{
rcrv = new RemapCRsVisitor(true);
pred.getAndNode().accept(rcrv);
}
// Add the predicate (in its original form) to our list of predicates
// that we've pushed during this phase of optimization. We need to
// keep this list of pushed predicates around so that we can do
// a "pull" of them later, if needed. We also need this list for
// cases where predicates are not pushed all the way down; see
// modifyAccessPaths() in this class for more.
if (pushedPredicates == null)
pushedPredicates = new PredicateList();
pushedPredicates.addOptPredicate(pred);
return true;
}
/**
* @see Optimizable#pullOptPredicates
*
* @exception StandardException Thrown on error
*/
public void pullOptPredicates(
OptimizablePredicateList optimizablePredicates)
throws StandardException
{
if (pushedPredicates == null)
// we didn't push anything, so nothing to pull.
return;
// It's possible that we tried to push a predicate down to this
// SetOperatorNode's children but weren't actually able to do so
// (see modifyAccessPaths() in this class for details on when that
// can happen). In that case the predicates will still be sitting
// in the left/right predicate list; we can ignore them here by
// just discarding them. When it comes time to modifyAccessPaths,
// though, we'll handle them correctly--i.e. we'll generate a
// ProjectRestrictNode over this node to ensure the predicates are
// enforced.
if (leftOptPredicates != null)
leftOptPredicates.removeAllElements();
if (rightOptPredicates != null)
rightOptPredicates.removeAllElements();
/* Note that predicates which have been explicitly scoped should
* not be pulled. The reason is that a scoped predicate can only
* be pushed to a specific, target result set. When it comes time
* to pull the predicate up, there's no need to pull the scoped
* predicate because it, by definition, was only intended for this
* specific result set and therefore cannot be pushed anywhere else.
* So at "pull" time, we can just discard the scoped predicates. We
* do, however, need to pull the original, unscoped predicate from
* which the scoped predicate was created because we can potentially
* push that predicate elsewhere
*/
Predicate pred = null;
for (int i = 0; i < pushedPredicates.size(); i++)
{
pred = (Predicate)pushedPredicates.getOptPredicate(i);
if (pred.isScopedForPush())
continue;
optimizablePredicates.addOptPredicate(pred);
}
// We're done with the pushedPredicates list, so clear it out
// in preparation for another phase of optimization.
pushedPredicates.removeAllElements();
}
/**
* Convert this object to a String. See comments in QueryTreeNode.java
* for how this should be done for tree printing.
*
* @return This object as a String
*/
public String toString()
{
if (SanityManager.DEBUG)
{
return "all: " + all + "\n" +
"orderByList: " +
(orderByList != null ? orderByList.toString() : "null") + "\n" +
super.toString();
}
else
{
return "";
}
}
/**
* 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
{
super.bindResultColumns(fromListParam);
/* Now we build our RCL */
buildRCL();
}
/**
* 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
{
super.bindResultColumns(targetTableDescriptor,
targetVTI,
targetColumnList, statement,
fromListParam);
/* Now we build our RCL */
buildRCL();
}
/**
* Build the RCL for this node. We propagate the RCL up from the
* left child to form this node's RCL.
*
* @return Nothing
*
* @exception StandardException Thrown on error
*/
private void buildRCL() throws StandardException
{
/* Verify that both sides of the union have the same # of columns in their
* RCL.
*/
if (leftResultSet.getResultColumns().size() !=
rightResultSet.getResultColumns().size())
{
throw StandardException.newException(SQLState.LANG_UNION_UNMATCHED_COLUMNS,
getOperatorName());
}
/* We need to recreate resultColumns for this node, since there
* may have been 1 or more *'s in the left's SELECT list.
*/
resultColumns = leftResultSet.getResultColumns().copyListAndObjects();
/* Create new expressions with the dominant types after verifying
* union compatibility between left and right sides.
*/
resultColumns.setUnionResultExpression(rightResultSet.getResultColumns(), tableNumber, level, getOperatorName());
}
/**
* Bind the result columns of a table constructor to the types in the
* given ResultColumnList. Use when inserting from a table constructor,
* and there are nulls in the values clauses.
*
* @param rcl The ResultColumnList with the types to bind to
*
* @exception StandardException Thrown on error.
*/
public void bindUntypedNullsToResultColumns(ResultColumnList rcl)
throws StandardException
{
/*
** If the RCL from the parent is null, then
** the types are coming from the union itself.
** So we have to cross check the two child
** rcls.
*/
if (rcl == null)
{
ResultColumnList lrcl = rightResultSet.getResultColumns();
ResultColumnList rrcl = leftResultSet.getResultColumns();
leftResultSet.bindUntypedNullsToResultColumns(rrcl);
rightResultSet.bindUntypedNullsToResultColumns(lrcl);
}
else
{
leftResultSet.bindUntypedNullsToResultColumns(rcl);
rightResultSet.bindUntypedNullsToResultColumns(rcl);
}
}
/**
* Get the parameter types from the given RowResultSetNode into the
* given array of types. If an array position is already filled in,
* don't clobber it.
*
* @param types The array of types to fill in
* @param rrsn The RowResultSetNode from which to take the param types
*
* @return The number of new types found in the RowResultSetNode
*/
int getParamColumnTypes(DataTypeDescriptor[] types, RowResultSetNode rrsn)
{
int numTypes = 0;
/* Look for columns where we have not found a non-? yet. */
for (int i = 0; i < types.length; i++)
{
if (types[i] == null)
{
ResultColumn rc =
(ResultColumn) rrsn.getResultColumns().elementAt(i);
if ( ! (rc.getExpression().isParameterNode()))
{
types[i] = rc.getExpressionType();
numTypes++;
}
}
}
return numTypes;
}
/**
* Set the type of each ? parameter in the given RowResultSetNode
* according to its ordinal position in the given array of types.
*
* @param types An array of types containing the proper type for each
* ? parameter, by ordinal position.
* @param rrsn A RowResultSetNode that could contain ? parameters whose
* types need to be set.
*
* @exception StandardException Thrown on error
*/
void setParamColumnTypes(DataTypeDescriptor[] types, RowResultSetNode rrsn)
throws StandardException
{
/*
** Look for ? parameters in the result column list
** of each RowResultSetNode
*/
ResultColumnList rrcl = rrsn.getResultColumns();
int rrclSize = rrcl.size();
for (int index = 0; index < rrclSize; index++)
{
ResultColumn rc = (ResultColumn) rrcl.elementAt(index);
if (rc.getExpression().isParameterNode())
{
/*
** We found a ? - set its type to the type from the
** type array.
*/
((ParameterNode) rc.getExpression()).setDescriptor(
types[index]);
}
}
}
/**
* 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
{
leftResultSet.bindTargetExpressions(fromListParam);
rightResultSet.bindTargetExpressions(fromListParam);
}
/**
* Push the order by list down from the cursor node
* into its child result set so that the optimizer
* has all of the information that it needs to
* consider sort avoidance.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -