blob: 2d392fc98a22d997df27142b20f52bfdae41bc12 [file] [log] [blame]
/**********************************************************************
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
**********************************************************************/
/* -*-C++-*-
*****************************************************************************
*
* File: ReqGen.cpp
* Description: Class to generate required physical properties for a
* child of a RelExpr node
*
* Created: 2/5/98
* Language: C++
*
*
*
*
*****************************************************************************
*/
#include "Platform.h"
#include "ReqGen.h"
#include "GroupAttr.h"
#include "Globals.h"
RequirementGenerator::RequirementGenerator(
const ExprGroupId &groupForRequirement,
const ReqdPhysicalProperty *startRequirements)
: startRequirements_ (startRequirements),
ga_ (groupForRequirement.getGroupAttr()),
stillFeasible_ (TRUE),
startRequirementsHaveBeenProcessed_ (startRequirements == NULL),
generatedRequirement_ (NULL),
generatedPartitioningRequirement_ (NULL),
generatedPartitioningReqIsValid_ (FALSE),
addedSortKey_ (NULL),
sortKeyIsUnique_ (FALSE),
removeStartSortKey_ (FALSE),
addedArrangement_ (NULL),
removeStartArrangement_ (FALSE),
partKeyHasBeenAdded_ (FALSE),
addedNumberOfPartitions_ (ANY_NUMBER_OF_PARTITIONS),
addedNumOfPartsAllowedDeviation_ (
CURRSTMT_OPTDEFAULTS->numberOfPartitionsDeviation()),
addedPartitioningRequirement_ (NULL),
removeStartPartitioningRequirements_ (FALSE),
locationHasBeenAdded_ (FALSE),
removeStartLocation_ (FALSE),
addedSortOrderTypeReq_ (NO_SOT),
addedDp2SortOrderPartReq_ (NULL),
addedSkewProperty_ (ANY_SKEW_PROPERTY),
skewPropertyAdded_ (FALSE),
requireNoESPExchange_ (FALSE),
requireHash2Only_ (FALSE)
{
// For the more simple requirements, just initialize them with
// the start requirements or the default values. That means these
// values don't get processed in processStartRequirements().
if (startRequirements)
{
availableCPUs_ = startRequirements->getCountOfAvailableCPUs();
pipelinesPerCPU_ = startRequirements->getCountOfPipelines() /
availableCPUs_;
costWeight_ = startRequirements->getCostWeight();
perfGoal_ = startRequirements->getPerformanceGoal();
logicalPartReq_ = startRequirements->getLogicalPartRequirement();
logicalOrderOrArrangement_ =
startRequirements->getLogicalOrderOrArrangementFlag();
pushDownRequirement_ = startRequirements->getPushDownRequirement();
requireNoESPExchange_ = startRequirements->getNoEspExchangeRequirement();
requireOcbEnabledCosting_ = startRequirements->getOcbEnabledCostingRequirement();
}
else
{
availableCPUs_ = DEFAULT_SINGLETON;
pipelinesPerCPU_ = DEFAULT_SINGLETON;
costWeight_ = CURRSTMT_OPTDEFAULTS->getDefaultCostWeight();
perfGoal_ = CURRSTMT_OPTDEFAULTS->getDefaultPerformanceGoal();
logicalPartReq_ = NULL;
logicalOrderOrArrangement_ = FALSE;
pushDownRequirement_ = 0;
requireOcbEnabledCosting_ = 0;
}
}
void RequirementGenerator::addSortKey(const ValueIdList &additionalSortKey,
SortOrderTypeEnum sortOrderTypeReq,
PartitioningRequirement* dp2SortOrderPartReq)
{
// This applies to adding both orders and arrangements:
//
// a) A new order requirement conflicts with an existing order
// requirement if one of the two requirements (simplified) values
// are not a prefix of the other (including the case where the
// two reqs are identical).
// b) A new arrangement requirement conflicts with an existing
// order requirement if its simplified values are not a leading
// prefix of the order requirement, and if the order required
// columns are not covered by the required arrangement columns.
// c) A new order requirement conflicts with an existing
// non-empty arrangement requirement if its (simplified) values are
// not a subset of the existing (simplified) arrangement requirement,
// and if the order required columns are not covered by
// the required arrangement columns.
// d) A new arrangement requirement conflicts with an existing
// non-empty arrangement requirement if its (simplified) values are
// different from the existing arrangement requirement, but see e)
// e) A new arrangement requirement that is a proper superset or subset
// of an existing arrangement requirement may be added if the smaller
// of the new and existing requirements is converted into a new order
// requirement. Converting the smaller arrangement requirement into
// an order requirement is a way to pass conditions b) and d).
//
// Two things can be done to simplify a required order or arrangement:
// BUT, we can't do them now until we make changes in the "satisfied"
// method and in merge join. So (f) and (g) are not done now.
//
// f) If the group attributes have a cardinality constraint of at
// most one result row, then we can ignore any required order or
// arrangement, no matter how weird, because a single row is
// ordered by basically anything.
// g) If a prefix of the required sort key or a subset of an arrangement
// is unique, then it is ok to ignore all other values of the order
// requirement and the entire arrangement requirement
// because the result will automatically be ordered by any
// combination of such columns (there will always be only
// one row for each unique key column combination, and that
// one row is sorted by anything, just like in the first
// item). In fact, the GroupAttributes::isUnique() method
// is written such that it can handle both f) and g) with only a
// single check.
//
// Checks a) and c) are done here, checks b), d) and e) are done in
// RequirementGenerator::addArrangement(), checks f) and g) are done
// in both places (BUT NOT RIGHT NOW).
//
// The above rules and the simplification of order expressions done
// in ItemExpr::simplifyOrderExpr() allow some nice optimizations.
// Example: "ORDER BY a, b-3, a desc, 4-b, c, d, e" is equivalent to
// "ORDER BY a, b, c" if c is a unique column, and the code below
// will find this. The generated requirement, however, may also be
// "ORDER BY a, b-3, c".
// Do not bother if additionalSortKey is an empty list
if (additionalSortKey.entries() == 0)
return;
// Add the sort order type requirement and associated Dp2 sort order
// partitioning requirement
addSortOrderTypeReq(sortOrderTypeReq, dp2SortOrderPartReq);
CollIndex existingEntries = 0;
CollIndex i;
// Before doing any processing, must eliminate any duplicates from
// the additional sort key being added.
ValueIdList noDupsAdditionalSortKey;
ValueIdList simpAdditionalSortKey;
for (i = 0; i < additionalSortKey.entries(); i++)
{
ValueId simpVid = additionalSortKey[i].getItemExpr()->
simplifyOrderExpr()->getValueId();
// Insert the current new value only if it is not
// dependent on a previous new value (this is checked
// by looking up the simplified new value in the existing set of
// simplified new values).
if (NOT simpAdditionalSortKey.contains(simpVid))
{
noDupsAdditionalSortKey.insert(additionalSortKey[i]);
simpAdditionalSortKey.insert(simpVid);
}
}
if (addedSortKey_ == NULL)
{
// allocate a new ValueIdList for the required order
// (it may turn out that the allocated ValueIdList stays empty)
addedSortKey_ = new(CmpCommon::statementHeap()) ValueIdList;
}
else
{
// check a) (see comment above)
// make sure the already added sort key columns match the new
// ones
existingEntries = addedSortKey_->entries();
for (i = 0; i < existingEntries AND stillFeasible_; i++)
if (i < noDupsAdditionalSortKey.entries())
{
if ((*addedSortKey_)[i] != noDupsAdditionalSortKey[i])
{
ItemExpr *ie1 = (*addedSortKey_)[i].getItemExpr();
ItemExpr *ie2 = noDupsAdditionalSortKey[i].getItemExpr();
// sameOrder method compares the SIMPLIFIED values
OrderComparison co = ie1->sameOrder(ie2);
if (co != SAME_ORDER)
{
// the required order conflicts with an already
// existing order requirement
stillFeasible_ = FALSE;
}
}
}
} // end check (a)
// Insert new sort key columns that go beyond the already added columns,
// if there are any and if the order does not already extend over a
// unique column combination.
for (i = existingEntries;
i < noDupsAdditionalSortKey.entries() AND NOT sortKeyIsUnique_;
i++)
{
ValueId noDupsVid = noDupsAdditionalSortKey[i];
ValueId simpVid = simpAdditionalSortKey[i];
// perform checks f) and g), note that simpleSortCols_ may be empty!
// COMMENTED OUT UNTIL "satisfied" METHOD CHANGES ARE MADE,
// and changes to merge join.
//if (ga_->isUnique(ValueIdSet(simpleSortCols_)))
//{
// The order key cols so far are already unique, no need to
// add another column. In fact, we can now accept even
// seemingly incompatible ordering requirements for additional
// columns!
//sortKeyIsUnique_ = TRUE;
//}
//else
//{
addedSortKey_->insert(noDupsVid);
// remember the simplified order value for checks b) and c)
simpleSortCols_.insert(simpVid);
//}
}
// check c) (see comment above)
// check for a conflict with an existing arrangement requirement
if (addedArrangement_ != NULL AND addedArrangement_->entries() > 0)
{
Int32 count = simpleSortCols_.prefixCoveredInSet(simpleArrangedCols_);
// The entire simplified required arrangement must be a leading
// prefix of the simplified required sort order, or all the
// required sort order columns must be covered by the
// arrangement columns. i.e. if the required sort order is ABC,
// the arrangement must be something like AB or ABCD.
if (NOT (((CollIndex)count == simpleArrangedCols_.entries()) OR
((CollIndex)count == simpleSortCols_.entries())))
stillFeasible_ = FALSE;
}
} // addSortKey
void RequirementGenerator::makeSortKeyFeasible(
ValueIdList &proposedSortKey)
{
CollIndex i = 0;
NABoolean match = TRUE;
ValueId svid;
processStartRequirements();
// Check for compatibility with an existing sort requirement
// The n columns of the existing sort key requirement and the first
// n columns of the proposed sort key must match exactly.
if (addedSortKey_ != NULL)
{
while ((i < addedSortKey_->entries()) AND
(i < proposedSortKey.entries()) AND match)
{
if ((*addedSortKey_)[i] != proposedSortKey[i])
{
ItemExpr *ie1 = (*addedSortKey_)[i].getItemExpr();
ItemExpr *ie2 = proposedSortKey[i].getItemExpr();
// sameOrder method compares the SIMPLIFIED values
OrderComparison co = ie1->sameOrder(ie2);
if (co != SAME_ORDER)
match = FALSE;
}
if (match)
i++;
} // end while
// If we found a proposed sort key column that did not match its
// counterpart in the existing sort key, we must remove it and
// all subsequent proposed sort key columns.
if (NOT match)
{
Int32 lastEntry = (Int32)proposedSortKey.entries() - 1;
while (lastEntry >= (Int32)i)
{
proposedSortKey.removeAt(lastEntry--);
}
}
} // end if there was a required sort order
else if (addedArrangement_ != NULL)
{
// The first n columns of the simplified proposed sort key must be
// part of the n columns of the simplified existing arrangement
// requirement.
while ((i < simpleArrangedCols_.entries()) AND
(i < proposedSortKey.entries()) AND match)
{
svid = proposedSortKey[i].getItemExpr()->
simplifyOrderExpr()->getValueId();
if (NOT simpleArrangedCols_.contains(svid))
match = FALSE;
if (match)
i++;
}
// If we found a proposed sort key column that is not in the
// required arrangement, we must remove it and all subsequent
// proposed sort key columns.
if (NOT match)
{
Int32 lastEntry = (Int32)proposedSortKey.entries() - 1;
while (lastEntry >= (Int32)i)
{
proposedSortKey.removeAt(lastEntry--);
}
}
} // end if there is already a required arrangement
} // end makeSortKeyFeasible()
void RequirementGenerator::makeArrangementFeasible(
ValueIdSet &proposedArrangement)
{
ValueId svid;
processStartRequirements();
// The arrangement is certainly feasible if there are no existing
// sort key or arrangement requirements.
if ((addedSortKey_ == NULL) AND (addedArrangement_ == NULL))
return;
// a simplified version of proposedArrangement
ValueIdSet simpleProposedArrangement;
for (ValueId vid = proposedArrangement.init();
proposedArrangement.next(vid);
proposedArrangement.advance(vid))
{
simpleProposedArrangement +=
vid.getItemExpr()->simplifyOrderExpr()->getValueId();
}
// If we have already added the proposed arrangement, then it
// must be feasible, so just return.
if (simpleArrangedCols_ == simpleProposedArrangement)
return;
// is there a required sort order?
if (addedSortKey_ != NULL)
{
Int32 count = simpleSortCols_.prefixCoveredInSet(simpleProposedArrangement);
// The entire simplified proposed arrangement must be a leading
// prefix of the simplified required sort order, or all the
// simplified required sort order columns must be covered by the
// simplified proposed arrangement columns. i.e. if the required
// sort order is ABC, the proposed arrangement must be something like
// AB or ABCD.
if (NOT (((CollIndex)count == simpleProposedArrangement.entries()) OR
((CollIndex)count == simpleSortCols_.entries())))
{
// Some or all of the proposed arrangement columns are not compatible
// with the required sort order columns. i.e. if the required sort
// order is ABC, and the proposed arrangement is B (no compatible
// columns) or AC (C is not compatible).
if (count == 0)
// All of them are not compatible. Get rid of all of them.
// This will result in the empty set. This is ok. It means
// that when we ask for that arrangement it will not cover
// a prefix of the required sort order and so we will give up.
proposedArrangement.clear();
else
{
// Some are not compatible. Figure out which ones and get rid of them.
ValueIdList coveredSimpleSortCols(simpleSortCols_);
coveredSimpleSortCols.removeUncoveredSuffix(simpleProposedArrangement);
for (ValueId v = proposedArrangement.init();
proposedArrangement.next(v);
proposedArrangement.advance(v))
{
svid = v.getItemExpr()->simplifyOrderExpr()->getValueId();
if (NOT coveredSimpleSortCols.contains(svid))
proposedArrangement -= v;
}
} // end else count != 0
} // end if the proposed arrangement was not ok
} // end if there was a required sort order
else if (addedArrangement_ != NULL)
{
// Already have a required arrangement. If one of the arrangements
// is not a subset of the other, then we must remove the columns
// from the proposed arrangement that are not in the already added
// arrangement.
if (NOT simpleArrangedCols_.contains(simpleProposedArrangement) AND
NOT simpleProposedArrangement.contains(simpleArrangedCols_))
{
// Remove columns from the proposed arrangement. This may
// result in the empty set. This is ok - it means when we ask
// for that arrangement that it will not be compatible with
// the existing arrangement and we will give up.
simpleProposedArrangement.intersectSet(simpleArrangedCols_);
if (simpleProposedArrangement.isEmpty())
// Existing required arrangement and proposed arrangement
// are disjoint. Remove all columns from the proposed
// arrangement.
proposedArrangement.clear();
else // Some columns in common.
for (ValueId v = proposedArrangement.init();
proposedArrangement.next(v);
proposedArrangement.advance(v))
{
svid = v.getItemExpr()->simplifyOrderExpr()->getValueId();
if (NOT simpleProposedArrangement.contains(svid))
proposedArrangement -= v;
}
} // end if arrangements are not subsets
} // end if there is already a required arrangement
} // end makeArrangementFeasible()
void RequirementGenerator::addArrangement(
const ValueIdSet &additionalArrangementParam,
SortOrderTypeEnum sortOrderTypeReq,
PartitioningRequirement* dp2SortOrderPartReq)
{
// Do not bother if additionalArrangementParam is an empty set
if (additionalArrangementParam.entries() == 0)
return;
// Add the sort order type requirement and associated Dp2 sort order
// partitioning requirement
addSortOrderTypeReq(sortOrderTypeReq, dp2SortOrderPartReq);
// local copy of the new arrangement
ValueIdSet additionalArrangement;
// a simplified version of additionalArrangement
ValueIdSet simpleAddtnlArrangement;
ValueId svid;
for (ValueId vid = additionalArrangementParam.init();
additionalArrangementParam.next(vid);
additionalArrangementParam.advance(vid))
{
svid = vid.getItemExpr()->simplifyOrderExpr()->getValueId();
// Only keep the current value id of the new arrangement
// if its simplified form is not already in the simplified
// form of the arrangement.
if (NOT simpleAddtnlArrangement.contains(svid))
{
additionalArrangement += vid;
simpleAddtnlArrangement += svid;
}
}
// Perform checks f) and g), eliminate redundant requests for
// arrangements.
// COMMENTED OUT UNTIL "satisfied" METHOD CHANGES ARE MADE,
// and changes to merge join.
//if (ga_->isUnique(simpleAddtnlArrangement))
//{
// additionalArrangement.clear();
// simpleAddtnlArrangement.clear();
//}
// perform check b) (see comment in addSortKey())
if ((addedSortKey_ != NULL) AND
// Don't need to perform check if there already is an arrangement
// that is the same as the one we want to add, since it must have
// already passed the checks.
((addedArrangement_ == NULL) OR
(simpleArrangedCols_ != simpleAddtnlArrangement)))
{
Int32 count = simpleSortCols_.prefixCoveredInSet(simpleAddtnlArrangement);
// The entire arrangement must be a leading prefix of the
// required sort order, or all the required sort order columns must
// be covered by the arrangement columns. i.e. if the required
// sort order is ABC, the arrangement must be something like
// AB or ABCD.
if (NOT (((CollIndex)count == simpleAddtnlArrangement.entries()) OR
((CollIndex)count == simpleSortCols_.entries())))
stillFeasible_ = FALSE;
}
// perform check d) (see comment in addSortKey())
if (stillFeasible_ AND
(addedArrangement_ != NULL) AND
(simpleArrangedCols_ != simpleAddtnlArrangement))
{
// failed check d), now try the conversion described in check e)
// and see whether that got around the problem
ValueIdSet arrToConvert;
ValueIdSet simpleArrToConvert;
if (simpleArrangedCols_.contains(simpleAddtnlArrangement))
{
// convert additionalArrangement into a required order and don't
// add any new arrangement
arrToConvert = additionalArrangement;
additionalArrangement.clear();
simpleArrToConvert = simpleAddtnlArrangement;
simpleAddtnlArrangement.clear();
}
else if (simpleAddtnlArrangement.contains(simpleArrangedCols_))
{
// remove addedArrangement and convert it into a required
// order, then add additionalArrangement as a new arrangement
arrToConvert = *addedArrangement_;
addedArrangement_->clear();
simpleArrToConvert = simpleArrangedCols_;
simpleArrangedCols_.clear();
}
else
stillFeasible_ = FALSE; // conversion from check e) was not possible
if (stillFeasible_)
{
// Now try the conversion of step e). There are many ways to
// convert an arrangement into a sort order, pick a way that
// does not conflict with an existing order requirement
// since arrToConvert contains all the columns of the
// required order (if any), just start with the required
// order and add all values of arrToConvert that are not in
// the already required order
ValueIdList orderFromArr;
ValueIdSet sortColsAsSet(simpleSortCols_);
// we should already have done check b)
CMPASSERT(simpleArrToConvert.contains(sortColsAsSet) OR
sortColsAsSet.contains(simpleArrToConvert));
if (addedSortKey_ != NULL)
{
orderFromArr = *addedSortKey_;
// Remove all the columns that addedSortKey_ is based upon
// from arrToConvert, so we can add the rest below.
// NOTE: This is no longer necessary. Method addSortKey() now eliminates
// all duplicates from the sort key being added before proceeeding.
// First: Remove them from simpleArrToConvert.
simpleArrToConvert -= sortColsAsSet;
// Second: Now, remove all items from arrToConvert whose
// simplified form is no longer in simpleArrToConvert.
for (ValueId v = arrToConvert.init();
arrToConvert.next(v);
arrToConvert.advance(v))
{
svid = v.getItemExpr()->simplifyOrderExpr()->getValueId();
if (NOT simpleArrToConvert.contains(svid))
arrToConvert -= v;
}
}
// Now take care of those arrangement columns that are not
// yet a part of the required order but that need to be
// converted into an order. Simply take them in the sequence
// of their value ids and make them all ascending.
for (ValueId cvid = arrToConvert.init();
arrToConvert.next(cvid);
arrToConvert.advance(cvid))
{
orderFromArr.insert(cvid);
}
// now the actual conversion
addSortKey(orderFromArr,
sortOrderTypeReq,
dp2SortOrderPartReq);
// there isn't any reason why this should not have worked,
// we did all the necessary checks before
CMPASSERT(stillFeasible_);
} // try conversion of check e)
} // check d)
// Need to add the new arrangement if it is still feasible, has
// not been converted to an order, and is not equal to the
// existing arrangement. Note that for all this to be true there
// must not have been an existing arrangement, or the new
// arrangement must be a superset of the existing arrangement.
if (stillFeasible_ AND
NOT additionalArrangement.isEmpty() AND
((addedArrangement_ == NULL) OR
(simpleArrangedCols_ != simpleAddtnlArrangement)))
{
if (addedArrangement_ == NULL)
{
addedArrangement_ =
new (CmpCommon::statementHeap())
ValueIdSet(additionalArrangement);
simpleArrangedCols_ = simpleAddtnlArrangement;
}
else
{
// We can only come here if the new arrangement is a
// superset of an already added one. This means that we have
// converted the old "addedArrangement_" to an order
// and then cleared the old arrangement.
// So, we just need to add the new arrangement.
CMPASSERT(addedArrangement_->isEmpty());
*addedArrangement_ = additionalArrangement;
simpleArrangedCols_ = simpleAddtnlArrangement;
}
}
} // addArrangement
// combine partKey1 with partKey2 heuristically
ValueIdSet RequirementGenerator::combinePartKeysHeuristically(
const ValueIdSet& partKey1,
const ValueIdSet& partKey2)
// if partKey1 == partKey2 then return either one, else
// when PARTITIONING_SCHEME_SHARING is
// 0 (the default) means complete sharing (current behavior)
// 1 means require one set to contain the other
// otherwise disable sharing
{
ValueIdSet result(partKey1);
// initialize the result with the intersection of the keys
result.intersectSet(partKey2);
Lng32 pssc = CURRSTMT_OPTDEFAULTS->partitioningSchemeSharing();
if (pssc == 0)
return result;
// check whether either key is a subset of the other
NABoolean key1IsASubsetOfKey2 = (partKey1.entries() == result.entries());
NABoolean key2IsASubsetOfKey1 = (partKey2.entries() == result.entries());
// if both partitioning keys are the same (are subsets of
// each other), then there is no need to apply heuristics
if (key1IsASubsetOfKey2 AND key2IsASubsetOfKey1)
return result;
// With PSSC set to 1 we require that one key being a superset of the other
if ((pssc == 1) AND
(key1IsASubsetOfKey2 OR key2IsASubsetOfKey1))
return result;
// add cases where we shouldn't use the result
// make the result empty means only a serial plan will be acceptable
result.clear();
// don't set stillFeasible_ = FALSE; because that would cause errors with
// operators that need to execute in the master and that have 2 other
// operators on top of them
return result;
}
void RequirementGenerator::addPartitioningKey(
const ValueIdSet &partKey)
{
ValueIdSet simplifiedPartKey(partKey);
if (CmpCommon::getDefault(COMP_BOOL_111) != DF_ON)
{
// consider query
//
// SELECT [last 1]
// (POS.WM_FISCAL_YR - 1900)||'01',
// POS.STORE_NBR,
// SUM( POS.YRLY_SALES )
// FROM
// WM_USER.SKU_YRLY_POS POS,
// WM_HOLD.WM_ITEM073 ITEMP < < +cardinality 2.8e6>>,
// WM_HOLD.WM_CLUB STEMP < < +cardinality 0.3e1>>
// WHERE
// STEMP.UID = '6D9E40D2WMH6001' AND
// ITEMP.UID = 'E7377E75WMH6001' AND
// POS.STORE_NBR = STEMP.CLUB AND
// POS.ITEM_NBR = ITEMP.MDS_FAM_ID AND
// POS.WM_FISCAL_YR = 2006
// GROUP BY 1,2
// ORDER BY POS.STORE_NBR ;
//
// expression (POS.WM_FISCAL_YR - 1900)||'01' is a constant for
// our purpose, because POS.WM_FISCAL_YR has an equality predicate
// against a constant i.e. predicate POS.WM_FISCAL_YR = 2006
NABoolean considerConstExpressions = TRUE;
// remove constant values from the partitioning key
simplifiedPartKey.removeConstExprReferences(considerConstExpressions);
}
// check whether a partitioning key has been added before
if (partKeyHasBeenAdded_)
{
// if there is already a partitioning key, build the intersection
// NOTE: this may result in the empty set being required as a
// partitioning key (that's ok and is equivalent to a requirement
// for exactly one partition)
//
// We use heuristics to decide whether the intersection really
// forms a useful partitioning requirement. For example, combining
// (L_ORDERKEY, N_NATIONKEY) and (N_NATIONKEY, C_CUSTKEY) results
// in a partitioning requirement for N_NATIONKEY - probably not a
// good idea, given that there are only 25 nations in TPC-H.
addedPartKey_ = combinePartKeysHeuristically(addedPartKey_,
simplifiedPartKey);
}
else
{
// just copy the part key if this is the first time we add one
// (note that no requirement is not the same as the requirement
// for an empty part key!!!!!)
partKeyHasBeenAdded_ = TRUE;
addedPartKey_ = simplifiedPartKey;
}
generatedPartitioningReqIsValid_ = FALSE;
// resolve possible conflicts with fully-specified partitioning functions
// later
}
void RequirementGenerator::addNumOfPartitions(
Lng32 newNumberOfPartitions,
float newNumOfPartsAllowedDeviation)
{
if (newNumberOfPartitions == ANY_NUMBER_OF_PARTITIONS)
return;
CMPASSERT(newNumberOfPartitions > 0);
if (addedNumberOfPartitions_ == ANY_NUMBER_OF_PARTITIONS)
{
addedNumberOfPartitions_ = newNumberOfPartitions;
addedNumOfPartsAllowedDeviation_ = newNumOfPartsAllowedDeviation;
generatedPartitioningReqIsValid_ = FALSE;
}
else
{
if (addedNumberOfPartitions_ != newNumberOfPartitions)
{
// conflicting requirements for number of partitions
// $$$$ could check whether the numbers are approximately the same
// and remember a range
stillFeasible_ = FALSE;
}
// go with the smaller of the allowed deviations
if (newNumOfPartsAllowedDeviation < addedNumOfPartsAllowedDeviation_)
{
addedNumOfPartsAllowedDeviation_ = newNumOfPartsAllowedDeviation;
generatedPartitioningReqIsValid_ = FALSE;
}
}
// resolve possible conflicts with fully-specified partitioning functions
// and requirements for a partitioning key later
}
void RequirementGenerator::addPartRequirement(
PartitioningRequirement *pr)
{
if (pr->isRequirementFuzzy())
{
if (NOT pr->getPartitioningKey().isEmpty())
addPartitioningKey(pr->getPartitioningKey());
if (pr->getCountOfPartitions() != ANY_NUMBER_OF_PARTITIONS)
{
if (pr->isRequirementApproximatelyN())
{
addNumOfPartitions(pr->getCountOfPartitions(),
pr->castToRequireApproximatelyNPartitions()->
getAllowedDeviation());
requireHash2Only_ = pr->castToRequireApproximatelyNPartitions()->
isRequireHash2Only();
}
else
addNumOfPartitions(pr->getCountOfPartitions());
}
}
else if (addedPartitioningRequirement_ != NULL)
{
if (addedPartitioningRequirement_->comparePartReqToReq(pr) != SAME)
stillFeasible_ = FALSE;
}
else
{
addedPartitioningRequirement_ = pr;
generatedPartitioningReqIsValid_ = FALSE;
// don't worry about possible conflicts with added partitioning
// keys and numbers of partitions quite yet
}
} // addPartRequirement
void
RequirementGenerator::makeSkewReqFeasible(PartitioningRequirement* partR)
{
if ( skewPropertyAdded_ == FALSE || partR == NULL )
return;
// check part requirement partR. If it is fuzzy, nothing we can check
// other than set the skew property
// to it.
if (partR -> isRequirementFuzzy() ) {
const skewProperty& skInFuzzyR =
((FuzzyPartitioningRequirement*)partR)->getSkewProperty();
if ( skInFuzzyR.isAnySkew() ) {
((FuzzyPartitioningRequirement*)partR) ->
setSkewProperty(addedSkewProperty_);
} else {
if ( NOT (skInFuzzyR == addedSkewProperty_) )
stillFeasible_ = FALSE;
}
return;
} else {
// check the part func contained in the (fully specified) partR
const FullySpecifiedPartitioningRequirement* fs_req =
partR->castToFullySpecifiedPartitioningRequirement();
if ( fs_req ) {
PartitioningFunction* partFunc = fs_req->getPartitioningFunction();
if ( partFunc != NULL ) {
const SkewedDataPartitioningFunction* skpf =
partFunc->castToSkewedDataPartitioningFunction();
// The contained partfunc should be a SkewedData partfunc.
// If not, declare it not feasible right here
if ( skpf == NULL )
stillFeasible_ = FALSE;
else {
// Make sure its skew property is the same as the
// one set to the ReqGen.
if (NOT (skpf->getSkewProperty() == addedSkewProperty_ ))
stillFeasible_ = FALSE;
}
}
}
}
}
void
RequirementGenerator::addSkewRequirement(skewProperty::skewDataHandlingEnum x,
SkewedValueList* skList,
NABoolean broadcastOneRow)
{
if ( skewPropertyAdded_ == TRUE ) {
skewProperty tempSk;
tempSk.setIndicator(x);
tempSk.setBroadcastOneRow(broadcastOneRow);
tempSk.setSkewValues(skList);
if (NOT (tempSk == addedSkewProperty_)) {
stillFeasible_ = FALSE;
return;
}
}
addedSkewProperty_.setIndicator(x);
addedSkewProperty_.setBroadcastOneRow(broadcastOneRow);
addedSkewProperty_.setSkewValues(skList);
skewPropertyAdded_ = TRUE;
if ( generatedPartitioningReqIsValid_ == TRUE AND
generatedPartitioningRequirement_
)
makeSkewReqFeasible(generatedPartitioningRequirement_);
}
void RequirementGenerator::addLocationRequirement(
PlanExecutionEnum loc)
{
if (NOT locationHasBeenAdded_)
{
addedLocation_ = loc;
locationHasBeenAdded_ = TRUE;
}
else
{
if (loc != addedLocation_)
{
if ( (addedLocation_ == EXECUTE_IN_MASTER_OR_ESP) AND
( (loc == EXECUTE_IN_MASTER) OR (loc == EXECUTE_IN_ESP) )
)
{
// change location to more specific one
addedLocation_ = loc;
}
else
{ // The only two cases we want to keep stillFeasible_ value
// as TRUE are: loc is EXECUTE_IN_MASTER_OR_ESP and
// (addedLocation_ is EXECUTE_IN_MASTER or EXECUTE_IN_ESP)
// otherwisw we change it to FALSE
if ( (loc != EXECUTE_IN_MASTER_OR_ESP) OR
(addedLocation_ == EXECUTE_IN_DP2) )
{
// incompatible location requirements
stillFeasible_ = FALSE;
}
}
} // if(loc != addedLocation_)
} // else(addedLocation was TRUE)
}
void RequirementGenerator::addLogicalPartRequirement(
LogicalPartitioningRequirement *pr)
{
// it should never happen that we add two different logical partitioning
// requirements, only one DP2 exchange should do that once
CMPASSERT(logicalPartReq_ == NULL);
logicalPartReq_ = pr;
}
void RequirementGenerator::removeSortKey()
{
addedSortKey_ = NULL;
sortKeyIsUnique_ = FALSE;
removeStartSortKey_ = TRUE;
simpleSortCols_.clear();
// If there is no added arrangement requirement, we can also remove any
// sort order type requirements.
if (addedArrangement_ == NULL)
{
addedSortOrderTypeReq_ = NO_SOT;
addedDp2SortOrderPartReq_ = NULL;
}
}
// -----------------------------------------------------------------------
// RequirementGenerator::removeExtraSortKeys method
// This method removes key columns that are not covered in the
// characteristic inputs when atleast the first key column is covered.
// This method will be called only while creating a context for right
// child of a NestedJoin. E.g say LC is ordered on
// 'a.b.c.d' and RC is ordered on 'a.b'. Say we are doing a equi join on
// a and b columnns, then we should consider fully ordered NJ plan. But we
// don't since columns c and d are not covered, we return FALSE in the method
// checkCompatibilityWithGroupAttributes().
// -----------------------------------------------------------------------
void RequirementGenerator::removeExtraSortKeys()
{
ValueIdSet newExternalInputs=ga_->getCharacteristicInputs();
if (stillFeasible_ AND addedSortKey_)
{
if (addedSortKey_->entries() > 0)
{
ValueId firstVid =(*addedSortKey_)[0];
if (newExternalInputs.contains(firstVid))
{
addedSortKey_->removeUnCoveredExprs(ga_->getCharacteristicInputs());
}
}
}
}
void RequirementGenerator::removeArrangement()
{
addedArrangement_ = NULL;
removeStartArrangement_ = TRUE;
// If there is no added sort key requirement, we can also remove any
// sort order type requirements.
if (addedSortKey_ == NULL)
{
addedSortOrderTypeReq_ = NO_SOT;
addedDp2SortOrderPartReq_ = NULL;
}
}
void RequirementGenerator::removeSortOrderTypeReq()
{
addedSortOrderTypeReq_ = NO_SOT;
addedDp2SortOrderPartReq_ = NULL;
}
void RequirementGenerator::removeAllPartitioningRequirements()
{
addedPartKey_.clear();
partKeyHasBeenAdded_ = FALSE;
addedNumberOfPartitions_ = ANY_NUMBER_OF_PARTITIONS;
addedPartitioningRequirement_ = NULL;
removeStartPartitioningRequirements_ = TRUE;
generatedPartitioningReqIsValid_ = FALSE;
requireHash2Only_ = FALSE;
}
void RequirementGenerator::replaceLocationRequirement(PlanExecutionEnum loc)
{
// note that it is not allowed to remove the location requirement
// completely (we just decided this because it happens that in the
// current design there always is a location requirement)
locationHasBeenAdded_ = TRUE;
addedLocation_ = loc;
removeStartLocation_ = TRUE;
}
void RequirementGenerator::makeNumOfPartsFeasible(Lng32 &proposedNumOfParts,
float *proposedNumOfPartsAllowedDeviation)
{
// rather than just producing a non-feasible requirement by adding some
// incompatible requirement for the number of partitions, alter the
// requirement such that it does not conflict with already existing
// requirements
// see what partitioning requirement we would generate so far
producePartitioningRequirements();
// if the produced part req specifies a fixed number of partitions
// then return those, otherwise leave proposedNumOfParts unchanged
if (stillFeasible_ AND
(generatedPartitioningRequirement_ != NULL) AND
(generatedPartitioningRequirement_->getCountOfPartitions() !=
ANY_NUMBER_OF_PARTITIONS))
{
proposedNumOfParts = generatedPartitioningRequirement_->
getCountOfPartitions();
if (generatedPartitioningRequirement_->isRequirementApproximatelyN() AND
(proposedNumOfPartsAllowedDeviation != NULL))
*proposedNumOfPartsAllowedDeviation =
generatedPartitioningRequirement_->
castToRequireApproximatelyNPartitions()->
getAllowedDeviation();
}
}
NABoolean RequirementGenerator::checkFeasibility()
{
if (NOT stillFeasible_)
return FALSE;
// make sure we have seen all requirements
processStartRequirements();
if (NOT stillFeasible_)
return FALSE;
// orders and arrangements are always checked immediately, except
// for the condition that they must be covered by the group attributes
// check partitioning requirements by building them
producePartitioningRequirements();
if (NOT stillFeasible_)
return FALSE;
// adjust location because part.req. cannot be satisfied in MASTER
if ( (addedLocation_ == EXECUTE_IN_MASTER_OR_ESP) AND
((addedNumberOfPartitions_*(1.0-addedNumOfPartsAllowedDeviation_)) > 1.0)
)
{
addedLocation_ = EXECUTE_IN_ESP;
}
// finally
checkCompatibilityWithGroupAttributes();
return stillFeasible_;
}
ReqdPhysicalProperty *RequirementGenerator::produceRequirement()
{
// ---------------------------------------------------------------------
// NOTE: a NULL return value does NOT mean no requirements, it means
// that there is not any feasible requirement!
// ---------------------------------------------------------------------
if (NOT checkFeasibility())
{
// NOTE: don't move the checkFeasibility() call into the assert,
// it must be executed even when asserts get disabled!!!
CMPASSERT(0);
return NULL; // should never get here
}
// some sanity checks
// - we currently always require some execution location
// - we need at least one CPU to execute
// - we always specify some (default) cost weight and performance goal
// - logical partitioning is allowed in DP2 only
CMPASSERT(locationHasBeenAdded_ AND
availableCPUs_ > 0 AND
pipelinesPerCPU_ > 0 AND
costWeight_ != NULL AND
perfGoal_ != NULL AND
(addedLocation_ == EXECUTE_IN_DP2 OR logicalPartReq_ == NULL) );
// If we're in Dp2, there must be no sort order type requirement
CMPASSERT((addedLocation_ != EXECUTE_IN_DP2) OR
(addedSortOrderTypeReq_ == NO_SOT));
generatedRequirement_ = new(CmpCommon::statementHeap())
ReqdPhysicalProperty(
addedArrangement_,
addedSortKey_,
addedSortOrderTypeReq_,
addedDp2SortOrderPartReq_,
logicalOrderOrArrangement_,
generatedPartitioningRequirement_,
logicalPartReq_,
addedLocation_,
availableCPUs_,
pipelinesPerCPU_,
costWeight_,
perfGoal_,
NULL);
generatedRequirement_->setPushDownRequirement(pushDownRequirement_);
generatedRequirement_->setNoEspExchangeRequirement(requireNoESPExchange_);
generatedRequirement_->setOcbEnabledCostingRequirement(requireOcbEnabledCosting_);
return generatedRequirement_;
}
void RequirementGenerator::processStartRequirements()
{
if (startRequirements_ == NULL OR
startRequirementsHaveBeenProcessed_ OR
NOT stillFeasible_)
return;
// set this flag first, to prevent anyone else from recursively
// calling this method and to allow early returns
startRequirementsHaveBeenProcessed_ = TRUE;
// add the sort key and arrangement from the start requirements
if (NOT removeStartSortKey_ AND
startRequirements_->getSortKey() AND
(startRequirements_->getSortKey()->entries() > 0))
{
addSortKey(*(startRequirements_->getSortKey()),
startRequirements_->getSortOrderTypeReq(),
startRequirements_->getDp2SortOrderPartReq());
}
if (NOT stillFeasible_)
return;
if (NOT removeStartArrangement_ AND
startRequirements_->getArrangedCols() AND
(startRequirements_->getArrangedCols()->entries() > 0))
{
addArrangement(*(startRequirements_->getArrangedCols()),
startRequirements_->getSortOrderTypeReq(),
startRequirements_->getDp2SortOrderPartReq());
}
if (NOT stillFeasible_)
return;
if (NOT removeStartPartitioningRequirements_ AND
startRequirements_->requiresPartitioning())
{
addPartRequirement(startRequirements_->getPartitioningRequirement());
if (NOT stillFeasible_)
return;
}
addLocationRequirement(startRequirements_->getPlanExecutionLocation());
if (NOT stillFeasible_)
return;
// note that many other fields from the start requirements have already
// been set in the constructor
} // processStartRequirements()
void RequirementGenerator::producePartitioningRequirements()
{
// make sure we have all the pieces we need
processStartRequirements();
// protect against unnecessary calls
if (generatedPartitioningReqIsValid_)
return;
// Do a consistency check for conflicting requirements, if a fully
// specified partitioning function is required. Note that we never
// store a "fuzzy" requirement in data member addedPartitioningRequirement_!
if (addedPartitioningRequirement_)
{
// if both a fully specified requirement (addedPartitioningRequirement_)
// and a partitioning key and/or number of partitions is required,
// make sure that both requirements match
if (partKeyHasBeenAdded_ AND
NOT addedPartKey_.contains(
addedPartitioningRequirement_->getPartitioningKey()))
{
// The additional required partitioning key is not simply a
// superset of the fully specified partitioning key. This
// means that if we would require the fully specified function
// then its partitioning key would consist of values that
// are not part of addedPartKey_, therefore not satisfying the
// requirement that addedPartKey_ be a partitioning key.
stillFeasible_ = FALSE;
}
if ((addedNumberOfPartitions_ != ANY_NUMBER_OF_PARTITIONS) AND
((addedPartitioningRequirement_->getCountOfPartitions() >
addedNumberOfPartitions_) OR
(addedPartitioningRequirement_->getCountOfPartitions() <
(addedNumberOfPartitions_ -
(addedNumberOfPartitions_ * addedNumOfPartsAllowedDeviation_)))
)
)
{
// the additional requirement for addedNumberOfPartitions_
// conflicts with the requirement for the hard-coded
// partitioning function
stillFeasible_ = FALSE;
}
// Check if requireHash2Only_ is set AND partitioning requirement in
// addedPartitioningRequirement_ is not hash2.
if (requireHash2Only_ AND !addedPartitioningRequirement_->
castToFullySpecifiedPartitioningRequirement()->
getPartitioningFunction()->
isAHash2PartitioningFunction())
{
stillFeasible_ = FALSE;
}
// if the requirement is still feasible then the partitioning
// requirement in addedPartitioningRequirement_ is what we want
// to pass on as partitioning requirement
if (stillFeasible_)
generatedPartitioningRequirement_ = addedPartitioningRequirement_;
}
else if (partKeyHasBeenAdded_ OR addedNumberOfPartitions_ !=
ANY_NUMBER_OF_PARTITIONS)
{
// if we come here, only a partitioning key and/or a number
// of partitions is required
if ((partKeyHasBeenAdded_ AND addedPartKey_.isEmpty()) OR
(addedNumberOfPartitions_ == EXACTLY_ONE_PARTITION))
{
// if the partitioning key is empty or if there must be one
// partition, the only way to satisfy this is with a single
// partition, so produce a requirement for a single partition
// if there was a required number of partitions, then 1 partition
// must satisfy this requirement
if ((addedNumberOfPartitions_ != ANY_NUMBER_OF_PARTITIONS) AND
((addedNumberOfPartitions_ -
(addedNumberOfPartitions_ * addedNumOfPartsAllowedDeviation_)) >
EXACTLY_ONE_PARTITION))
stillFeasible_ = FALSE;
else
generatedPartitioningRequirement_ =
new(CmpCommon::statementHeap())
RequireExactlyOnePartition();
}
else
{
// produce a fuzzy partitioning requirement from the
// given partitioning key and number of partitions
if (NOT addedPartKey_.isEmpty())
generatedPartitioningRequirement_ =
new(CmpCommon::statementHeap())
RequireApproximatelyNPartitions(addedPartKey_,
addedNumOfPartsAllowedDeviation_,
addedNumberOfPartitions_,
requireHash2Only_);
else
generatedPartitioningRequirement_ =
new(CmpCommon::statementHeap())
RequireApproximatelyNPartitions(
addedNumOfPartsAllowedDeviation_,
addedNumberOfPartitions_,
requireHash2Only_);
}
}
else
{
// otherwise a NULL partitioning requirement is generated
generatedPartitioningRequirement_ = NULL;
}
if ( skewPropertyAdded_ == TRUE ) {
if ( generatedPartitioningRequirement_ )
makeSkewReqFeasible(generatedPartitioningRequirement_);
else
stillFeasible_ = FALSE;
}
generatedPartitioningReqIsValid_ = TRUE;
} // producePartitioningRequirements
void RequirementGenerator::checkCompatibilityWithGroupAttributes()
{
// some dummy variables for cover test
ValueIdSet newInputs;
ValueIdSet referencedInputs;
ValueIdSet coveredSubExpr;
ValueIdSet uncoveredExpr;
// sort key must be covered by the group attributes
if (stillFeasible_ AND addedSortKey_)
{
// remove all required sort columns that are covered by the
// characteristic inputs, they are constant for this group
addedSortKey_->removeCoveredExprs(ga_->getCharacteristicInputs());
if (addedSortKey_->entries() == 0)
{
addedSortKey_ = NULL;
// If there is no added arrangement requirement, we can also remove any
// sort order type requirements.
if (addedArrangement_ == NULL)
{
addedSortOrderTypeReq_ = NO_SOT;
addedDp2SortOrderPartReq_ = NULL;
}
}
else
{
ValueIdSet sortKey(*addedSortKey_);
stillFeasible_ = sortKey.isCovered(
newInputs,
*ga_,
referencedInputs,
coveredSubExpr,
uncoveredExpr);
coveredSubExpr.clear();
}
}
// arrangement must be covered by the group attributes
if (stillFeasible_ AND addedArrangement_ AND
NOT addedArrangement_->isEmpty())
{
// remove all required arrangement columns that are covered by the
// characteristic inputs, they are constant for this group
addedArrangement_->removeCoveredExprs(ga_->getCharacteristicInputs());
if (addedArrangement_->entries() == 0)
{
addedArrangement_ = NULL;
// If there is no added sort order requirement, we can also remove any
// sort order type requirements.
if (addedSortKey_ == NULL)
{
addedSortOrderTypeReq_ = NO_SOT;
addedDp2SortOrderPartReq_ = NULL;
}
}
else
{
stillFeasible_ = addedArrangement_->isCovered(
newInputs,
*ga_,
referencedInputs,
coveredSubExpr,
uncoveredExpr);
coveredSubExpr.clear();
}
}
// partitioning key must be covered by the group attributes
if (stillFeasible_ AND generatedPartitioningRequirement_)
{
stillFeasible_ = generatedPartitioningRequirement_->
getPartialPartitioningKey().isCovered(
newInputs,
*ga_,
referencedInputs,
coveredSubExpr,
uncoveredExpr);
coveredSubExpr.clear();
// if the partitioning requirement is fuzzy then we can
// just remove the uncovered expressions from the partitioning
// key requirement instead of giving up
// ||opt do that
}
// If we are to pass a dp2 sort order partitioning requirement,
// then it's partitioning key must be covered by the g.a.
if (stillFeasible_ AND (addedDp2SortOrderPartReq_ != NULL))
{
NABoolean isCovered =
addedDp2SortOrderPartReq_->getPartitioningKey().isCovered(
newInputs,
*ga_,
referencedInputs,
coveredSubExpr,
uncoveredExpr);
coveredSubExpr.clear();
// If it is not covered, we can try to convert to an ESP_NO_SORT
// requirement and then get rid of the offending part. requirement
if (NOT isCovered)
{
// see if we can convert to an ESP_NO_SORT requirement
if (addedSortOrderTypeReq_ == DP2_OR_ESP_NO_SORT_SOT)
{
addedSortOrderTypeReq_ = ESP_NO_SORT_SOT;
addedDp2SortOrderPartReq_ = NULL;
}
else
{
stillFeasible_ = FALSE;
}
} // end if the dp2 sort order part req key is not covered
} // end if still feasible and a dp2 sort order part req to check
} // checkCompatibilityWithGroupAttributes()
THREAD_P LookupTable<SortOrderTypeEnum>*
RequirementGenerator::sortOrderTypeReqCompTab_ = NULL;
// This method initializes a lookup table for comparing
// a parent's required sort order type against the child's
// required sort order type. Used to determine a required sort
// order type that is compatible with both the parent and
// child requirements. See the spec
// "Generating Join Plans with Required Orders", section 7.0,
// for more information.
void RequirementGenerator::initSortOrderTypeReqCompTab()
{
if (sortOrderTypeReqCompTab_ != NULL)
return;
sortOrderTypeReqCompTab_ =
new (GetCliGlobals()->exCollHeap())
LookupTable<SortOrderTypeEnum>(6,6,GetCliGlobals()->exCollHeap());
sortOrderTypeReqCompTab_->setValue(0,0,NO_SOT);
sortOrderTypeReqCompTab_->setValue(0,1,ESP_NO_SORT_SOT);
sortOrderTypeReqCompTab_->setValue(0,2,ESP_VIA_SORT_SOT);
sortOrderTypeReqCompTab_->setValue(0,3,DP2_SOT);
sortOrderTypeReqCompTab_->setValue(0,4,ESP_SOT);
sortOrderTypeReqCompTab_->setValue(0,5,DP2_OR_ESP_NO_SORT_SOT);
sortOrderTypeReqCompTab_->setValue(1,0,ESP_NO_SORT_SOT);
sortOrderTypeReqCompTab_->setValue(1,1,ESP_NO_SORT_SOT);
sortOrderTypeReqCompTab_->setValue(1,2,INCOMPATIBLE_SOT);
sortOrderTypeReqCompTab_->setValue(1,3,INCOMPATIBLE_SOT);
sortOrderTypeReqCompTab_->setValue(1,4,ESP_NO_SORT_SOT);
sortOrderTypeReqCompTab_->setValue(1,5,ESP_NO_SORT_SOT);
sortOrderTypeReqCompTab_->setValue(2,0,ESP_VIA_SORT_SOT);
sortOrderTypeReqCompTab_->setValue(2,1,INCOMPATIBLE_SOT);
sortOrderTypeReqCompTab_->setValue(2,2,ESP_VIA_SORT_SOT);
sortOrderTypeReqCompTab_->setValue(2,3,INCOMPATIBLE_SOT);
sortOrderTypeReqCompTab_->setValue(2,4,ESP_VIA_SORT_SOT);
sortOrderTypeReqCompTab_->setValue(2,5,INCOMPATIBLE_SOT);
sortOrderTypeReqCompTab_->setValue(3,0,DP2_SOT);
sortOrderTypeReqCompTab_->setValue(3,1,INCOMPATIBLE_SOT);
sortOrderTypeReqCompTab_->setValue(3,2,INCOMPATIBLE_SOT);
sortOrderTypeReqCompTab_->setValue(3,3,DP2_SOT);
sortOrderTypeReqCompTab_->setValue(3,4,INCOMPATIBLE_SOT);
sortOrderTypeReqCompTab_->setValue(3,5,DP2_SOT);
sortOrderTypeReqCompTab_->setValue(4,0,ESP_SOT);
sortOrderTypeReqCompTab_->setValue(4,1,ESP_NO_SORT_SOT);
sortOrderTypeReqCompTab_->setValue(4,2,ESP_VIA_SORT_SOT);
sortOrderTypeReqCompTab_->setValue(4,3,INCOMPATIBLE_SOT);
sortOrderTypeReqCompTab_->setValue(4,4,ESP_SOT);
sortOrderTypeReqCompTab_->setValue(4,5,ESP_NO_SORT_SOT);
sortOrderTypeReqCompTab_->setValue(5,0,DP2_OR_ESP_NO_SORT_SOT);
sortOrderTypeReqCompTab_->setValue(5,1,ESP_NO_SORT_SOT);
sortOrderTypeReqCompTab_->setValue(5,2,INCOMPATIBLE_SOT);
sortOrderTypeReqCompTab_->setValue(5,3,DP2_SOT);
sortOrderTypeReqCompTab_->setValue(5,4,ESP_NO_SORT_SOT);
sortOrderTypeReqCompTab_->setValue(5,5,DP2_OR_ESP_NO_SORT_SOT);
} // initSortOrderTypeReqCompTab()
SortOrderTypeEnum
RequirementGenerator::determineCompatibleSortOrderTypeReq(
SortOrderTypeEnum otherSortOrderTypeReq) const
{
if (sortOrderTypeReqCompTab_ == NULL)
initSortOrderTypeReqCompTab();
return sortOrderTypeReqCompTab_->getValue((Int32)otherSortOrderTypeReq,
(Int32)addedSortOrderTypeReq_);
}
void RequirementGenerator::addSortOrderTypeReq(
SortOrderTypeEnum sortOrderTypeReq,
PartitioningRequirement* dp2SortOrderPartReq)
{
// If the user did not explicitly specify a sort order type value,
// then they want the default. Specify a value of NO_SOT if in Dp2
// and ESP otherwise. The default value for sortOrderTypReq is
// set to be INCOMPATIBLE_SOT simply to signal that the user did
// not specify a value and we must specify a real value.
if (sortOrderTypeReq == INCOMPATIBLE_SOT)
{
if (startRequirements_->executeInDP2())
sortOrderTypeReq = NO_SOT;
else
sortOrderTypeReq = ESP_SOT;
}
if ((sortOrderTypeReq == DP2_OR_ESP_NO_SORT_SOT) OR
(sortOrderTypeReq == DP2_SOT))
CMPASSERT(dp2SortOrderPartReq != NULL);
// See if what we want to add is compatible with any already added
// requirement. Returns a type that is compatible for both .
SortOrderTypeEnum result =
determineCompatibleSortOrderTypeReq(sortOrderTypeReq);
if (result == INCOMPATIBLE_SOT)
{
stillFeasible_ = FALSE;
return;
}
// if both parent and child specified a Dp2 partitioning
// requirement, they must be the SAME
if ((dp2SortOrderPartReq != NULL) AND
(addedDp2SortOrderPartReq_ != NULL))
{
if (addedDp2SortOrderPartReq_->
comparePartReqToReq(dp2SortOrderPartReq) != SAME)
{
// See if we can convert to an ESP_NO_SORT requirement
if (result == DP2_OR_ESP_NO_SORT_SOT)
{
result = ESP_NO_SORT_SOT;
addedDp2SortOrderPartReq_ = NULL;
}
else
{
stillFeasible_ = FALSE;
return;
}
}
}
else if (dp2SortOrderPartReq != NULL)
{
// only the child specified a Dp2 partitioning requirement
addedDp2SortOrderPartReq_ = dp2SortOrderPartReq;
}
// Now, store the resultant sortOrderType
addedSortOrderTypeReq_ = result;
// if the resultant sortOrderType now no longer requires a
// dp2SortOrderPartReq, then set it to NULL.
if ((addedSortOrderTypeReq_ == ESP_NO_SORT_SOT) OR
(addedSortOrderTypeReq_ == ESP_VIA_SORT_SOT) OR
(addedSortOrderTypeReq_ == ESP_SOT))
addedDp2SortOrderPartReq_ = NULL;
} // addSortOrderTypeReq()
void RequirementGenerator::addNoEspExchangeRequirement()
{
requireNoESPExchange_ = TRUE;
} // addNoEspExchangeRequirement()
void RequirementGenerator::addOcbCostingRequirement()
{
requireOcbEnabledCosting_ = TRUE;
} // addOcbCostingRequirement()