public ResultSetNode optimize(DataDictionary dataDictionary,
PredicateList predicateList,
double outerRows)
throws StandardException
{
Optimizer optimizer;
/* Optimize any subquerys before optimizing the underlying result set */
/* selectSubquerys is always allocated at bind() time */
if (SanityManager.DEBUG)
SanityManager.ASSERT(selectSubquerys != null,
"selectSubquerys is expected to be non-null");
/* If this select node is the child of an outer node that is
* being optimized, we can get here multiple times (once for
* every permutation that is done for the outer node). With
* DERBY-805, we can add optimizable predicates to the WHERE
* list as part of this method; thus, before proceeding we
* need go through and remove any opt predicates that we added
* to our WHERE list the last time we were here; if we don't
* do that, we'll end up with the same predicates in our
* WHERE list multiple times, which can lead to incorrect
* optimization.
*/
if (wherePredicates != null)
{
// Iterate backwards because we might be deleting entries.
for (int i = wherePredicates.size() - 1; i >= 0; i--)
{
if (((Predicate)wherePredicates.elementAt(i)).isScopedForPush())
wherePredicates.removeOptPredicate(i);
}
}
/* Get a new optimizer */
/* With DERBY-805 we take any optimizable predicates that
* were pushed into this node and we add them to the list of
* predicates that we pass to the optimizer, thus allowing
* the optimizer to use them when choosing an access path
* for this SELECT node. We do that by adding the predicates
* to our WHERE list, since the WHERE predicate list is what
* we pass to the optimizer for this select node (see below).
* We have to pass the WHERE list directly (as opposed to
* passing a copy) because the optimizer is only created one
* time; it then uses the list we pass it for the rest of the
* optimization phase and finally for "modifyAccessPaths()".
* Since the optimizer can update/modify the list based on the
* WHERE predicates (such as by adding internal predicates or
* by modifying the actual predicates themselves), we need
* those changes to be applied to the WHERE list directly for
* subsequent processing (esp. for modification of the access
* path). Note that by adding outer opt predicates directly
* to the WHERE list, we're changing the semantics of this
* SELECT node. This is only temporary, though--once the
* optimizer is done with all of its work, any predicates
* that were pushed here will have been pushed even further
* down and thus will have been removed from the WHERE list
* (if it's not possible to push them further down, then they
* shouldn't have made it this far to begin with).
*/
if (predicateList != null)
{
if (wherePredicates == null) {
wherePredicates = (PredicateList) getNodeFactory().getNode(
C_NodeTypes.PREDICATE_LIST,
getContextManager());
}
Predicate pred = null;
int sz = predicateList.size();
for (int i = sz - 1; i >= 0; i--)
{
// We can tell if a predicate was pushed into this select
// node because it will have been "scoped" for this node
// or for some result set below this one.
pred = (Predicate)predicateList.getOptPredicate(i);
if (pred.isScopedToSourceResultSet())
{
// If we're pushing the predicate down here, we have to
// remove it from the predicate list of the node above
// this select, in order to keep in line with established
// push 'protocol'.
wherePredicates.addOptPredicate(pred);
predicateList.removeOptPredicate(pred);
}
}
}
optimizer = getOptimizer(fromList,
wherePredicates,
dataDictionary,
orderByList);
optimizer.setOuterRows(outerRows);
/* Optimize this SelectNode */
while (optimizer.getNextPermutation())
{
while (optimizer.getNextDecoratedPermutation())
{
optimizer.costPermutation();
}
}
/* When we're done optimizing, any scoped predicates that
* we pushed down the tree should now be sitting again
* in our wherePredicates list. Put those back in the
* the list from which we received them, to allow them
* to be "pulled" back up to where they came from.
*/
if (wherePredicates != null)
{
Predicate pred = null;
for (int i = wherePredicates.size() - 1; i >= 0; i--)
{
pred = (Predicate)wherePredicates.getOptPredicate(i);
if (pred.isScopedForPush())
{
predicateList.addOptPredicate(pred);
wherePredicates.removeOptPredicate(pred);
}
}
}
/* Get the cost */
costEstimate = optimizer.getOptimizedCost();
/* Update row counts if this is a scalar aggregate */
if ((selectAggregates != null) && (selectAggregates.size() > 0))
{
costEstimate.setEstimatedRowCount((long) outerRows);