blob: be01d7ded96ea7a6a19287141f1329fbdab81ec4 [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: ComKeyMDAM.cpp
* Description:
*
* Created: 5/6/98
* Language: C++
*
*
*
*
****************************************************************************
*/
// -----------------------------------------------------------------------
#include "ComKeyRange.h"
#include "ComKeyMDAM.h"
#include "ComPackDefs.h"
#include "exp_clause_derived.h"
keyMdamGen::keyMdamGen(ULng32 keyLen,
ex_cri_desc * workCriDesc,
unsigned short keyValuesAtpIndex,
unsigned short excludeFlagAtpIndex,
unsigned short dataConvErrorFlagAtpIndex,
unsigned short valueAtpIndex,
MdamColumnGen * first,
MdamColumnGen * last,
NABoolean complementKeysBeforeReturning,
CollHeap * heap)
: keyRangeGen(KEYMDAM,keyLen,workCriDesc,
keyValuesAtpIndex,excludeFlagAtpIndex,
dataConvErrorFlagAtpIndex),
valueAtpIndex_(valueAtpIndex),
first_(first),
last_(last),
complementKeysBeforeReturning_(complementKeysBeforeReturning)
{
// calculate the maximum disjunct number (and the number of columns
// while we are at it)
maxDisjunctNumber_ = 0; // make sure there is at least one disjunct
// (if there aren't any the query is known
// to be false and we should not get here)
Lng32 numberOfColumns = 0;
MdamColumnGen *cg = first;
for (; cg != 0; cg = cg->getNext())
{
Lng32 temp = cg->getLastDisjunctNumber();
if (temp > maxDisjunctNumber_)
maxDisjunctNumber_ = temp;
numberOfColumns++;
}
// calculate upper bounds on storage required
// for a discussion on these upper bounds, see
// \tess.$sqldoc.gemdoc.arkmemmg.
maxMdamIntervals_ = 0;
maxMdamRefs_ = 0;
maxMdamRefsForStopLists_ = 0;
Lng32 sumByColumn = 0;
Lng32 maxByColumn = -1;
Lng32 numberOfDisjuncts = maxDisjunctNumber_ + 1;
Lng32 * sumsByDisjunct = NULL;
sumsByDisjunct = new(heap) Lng32[numberOfDisjuncts];
Lng32 d;
Lng32 maxByColumnAndDisjunct = -1;
Lng32 nullableCount = 0;
Lng32 totalSum = 0;
for (d = 0; d < numberOfDisjuncts; d++)
sumsByDisjunct[d] = 0;
for (cg = first; cg != 0; cg = cg->getNext())
{
MdamPred * p = cg->getFirstPred();
NABoolean isNullable = TRUE; // $$$ safe stub for now
sumByColumn = 1;
if (isNullable)
{
nullableCount++;
sumByColumn++;
}
for (d = 0; d < numberOfDisjuncts; d++)
{
// calculate the number of equality predicates and the
// number of other predicates for this column and disjunct
Lng32 equalityPreds = 0;
Lng32 otherPreds = 0;
while ((p)&&(p->getDisjunctNumber() <= d))
{
if (p->getPredType() == MdamPred::MDAM_EQ)
equalityPreds++;
else
otherPreds++;
p = p->getNext();
}
Lng32 columnDisjunctCount = 2*equalityPreds + otherPreds + 1;
if (isNullable)
columnDisjunctCount++;
// at this point,
// columnDisjunctCount = 2 * # of equality predicates on
// this column and disjunct
// + # of other predicates on this
// column and disjunct
// + (1 if column is nullable, 0 otherwise)
// + 1
if (maxByColumnAndDisjunct < columnDisjunctCount)
maxByColumnAndDisjunct = columnDisjunctCount;
sumByColumn += 2*equalityPreds + otherPreds;
sumsByDisjunct[d] += 2*equalityPreds + otherPreds;
}
// at this point,
// sumByColumn = 2 * # of equality predicates on this column
// + # of other predicates on this column
// + (1 if column is nullable, 0 otherwise)
// + 1
if (maxByColumn < sumByColumn)
maxByColumn = sumByColumn;
}
// at this point,
// sumsByDisjunct[d] = 2 * # of equality predicates on disjunct d
// + # of other predicates on disjunct d
Lng32 maxByDisjunct = -1;
for (d = 0; d < numberOfDisjuncts; d++)
{
totalSum += sumsByDisjunct[d];
if (maxByDisjunct < sumsByDisjunct[d])
maxByDisjunct = sumsByDisjunct[d];
}
maxByDisjunct += (nullableCount + numberOfColumns);
totalSum += (nullableCount + numberOfColumns);
// at this point,
// maxByDisjunct = max over all disjuncts of
// ( 2 * # of equality predicates on disjunct d
// + # of other predicates on disjunct d
// + # of nullable columns
// + # of columns )
// and
// totalSum = 2 * # of equality predicates in the scan
// + # of other predicates in the scan
// + # of nullable columns
// + # of columns
NADELETEBASIC(sumsByDisjunct, heap); // done with it now
// calculate upper bound on number of MdamIntervals
maxMdamIntervals_ = 1 + maxByColumnAndDisjunct + maxByDisjunct +
totalSum + maxByColumn;
// calculate upper bound on number of MdamRefListEntrys
maxMdamRefs_ = numberOfDisjuncts * totalSum
+ (numberOfDisjuncts - 1) * maxByColumn;
// set the upper bound on number of MdamRefListEntrys used fr stop lists.
maxMdamRefsForStopLists_ = numberOfDisjuncts;
};
keyMdamGen::~keyMdamGen()
{
MdamColumnGen *next;
for (MdamColumnGen *m = first_; m != NULL; m = next)
{
next = m->getNext(); // get it before we destroy it
delete m;
}
first_ = NULL;
last_ = NULL;
};
Long keyMdamGen::pack(void * space)
{
first_.pack(space);
last_.pack(space);
return keyRangeGen::pack(space);
}
Lng32 keyMdamGen::unpack(void * base, void * reallocator)
{
// On NSK and Linux, there are stack limitations that are hit when we use
// recursive calls. Make this an iterative function instead.
MdamColumnGenPtr currGenPtr;
MdamColumnGen *nextColumnGen;
MdamColumnGen *currColumnGen;
if (first_.unpack(base, reallocator)) return -1;
currColumnGen = first_;
if (currColumnGen != NULL)
{
nextColumnGen = first_->getNext();
currGenPtr = nextColumnGen;
}
else
currGenPtr = NULL;
while (currGenPtr != (MdamColumnGenPtr)NULL)
{
if (currGenPtr.unpack(base, reallocator)) return -1;
nextColumnGen = currGenPtr.getPointer();
currColumnGen->setNext(nextColumnGen);
currColumnGen = nextColumnGen;
nextColumnGen = currColumnGen->getNext();
currGenPtr = nextColumnGen;
}
if (last_.unpack(base, reallocator)) return -1;
currColumnGen = last_;
if (currColumnGen != NULL)
{
nextColumnGen = last_->getNext();
currGenPtr = nextColumnGen;
}
else
currGenPtr = NULL;
while (currGenPtr != (MdamColumnGenPtr)NULL)
{
if (currGenPtr.unpack(base, reallocator)) return -1;
nextColumnGen = currGenPtr.getPointer();
currColumnGen->setNext(nextColumnGen);
currColumnGen = nextColumnGen;
nextColumnGen = currColumnGen->getNext();
currGenPtr = nextColumnGen;
}
return keyRangeGen::unpack(base, reallocator);
}
ex_expr* keyMdamGen::getExpressionNode(Int32)
{
return NULL;
}
ex_expr::exp_return_type MdamColumnGen::fixup(Lng32 base, unsigned short mode,
Space * space, CollHeap *heap,
const ex_tcb *tcb)
{
// the return from this procedure will be either EXPR_OK or it will be
// the return from the first fixup() that fails
ex_expr::exp_return_type rc;
ex_expr::exp_return_type rc1;
rc = loExpr_->fixup(base,mode,tcb,space,heap,FALSE,NULL);
rc1 = hiExpr_->fixup(base,mode,tcb,space,heap,FALSE,NULL);
if (rc == ex_expr::EXPR_OK)
rc = rc1;
rc1 = nonNullLoExpr_->fixup(base,mode,tcb,space,heap,FALSE,NULL);
if (rc == ex_expr::EXPR_OK)
rc = rc1;
rc1 = nonNullHiExpr_->fixup(base,mode,tcb,space,heap,FALSE,NULL);
if (rc == ex_expr::EXPR_OK)
rc = rc1;
for (MdamPred *p = preds_; p != 0; p = p->getNext())
{
rc1 = p->fixup(base,mode,tcb,space,heap);
if (rc == ex_expr::EXPR_OK)
rc = rc1;
}
return rc;
};
MdamColumnGen::~MdamColumnGen()
{
MdamPred * next = preds_;
while (preds_)
{
MdamPred *current = next;
next = current->getNext(); // get it before we destroy it
delete current;
}
preds_ = NULL;
}
Long MdamColumnGen::pack(void * space)
{
loExpr_.pack(space);
hiExpr_.pack(space);
nonNullLoExpr_.pack(space);
nonNullHiExpr_.pack(space);
preds_.pack(space);
lastPred_.pack(space);
previous_.pack(space);
next_.pack(space);
return NAVersionedObject::pack(space);
}
Lng32 MdamColumnGen::unpack(void * base, void * reallocator)
{
if(loExpr_.unpack(base, reallocator)) return -1;
if(hiExpr_.unpack(base, reallocator)) return -1;
if(nonNullLoExpr_.unpack(base, reallocator)) return -1;
if(nonNullHiExpr_.unpack(base, reallocator)) return -1;
// On NSK and Linux, there are stack limitations that are hit when we use
// recursive calls. Make this an iterative function instead.
MdamPredPtr currPredPtr;
MdamPred *nextPred;
MdamPred *currPred;
if (preds_.unpack(base, reallocator)) return -1;
currPred = preds_;
if (currPred != NULL)
{
nextPred = preds_->getNext();
currPredPtr = nextPred;
}
else
currPredPtr = NULL;
while (currPredPtr != (MdamPredPtr)NULL)
{
if (currPredPtr.unpack(base, reallocator)) return -1;
nextPred = currPredPtr.getPointer();
currPred->setNext(nextPred);
currPred = nextPred;
nextPred = currPred->getNext();
currPredPtr = nextPred;
}
if(lastPred_.unpack(base, reallocator)) return -1;
if(previous_.unpack(base, reallocator)) return -1;
return NAVersionedObject::unpack(base, reallocator);
}
MdamPred::MdamPredType MdamPred::getTransformedPredType
(Lng32 dataConvErrorFlag,
Lng32 dataConvErrorFlag2,
MdamEnums::MdamInclusion& startInclusion,
MdamEnums::MdamInclusion& endInclusion)
{
MdamPredType returnPredType = (MdamPredType)predType_;
switch (predType_)
{
case MdamPred::MDAM_EQ:
if(dataConvErrorFlag != ex_conv_clause::CONV_RESULT_OK)
returnPredType = MdamPred::MDAM_RETURN_FALSE;
break;
case MdamPred::MDAM_LE:
switch (dataConvErrorFlag)
{
case ex_conv_clause::CONV_RESULT_OK:
case ex_conv_clause::CONV_RESULT_ROUNDED_DOWN:
case ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX:
// predType remains MDAM_LE.
break;
case ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN:
case ex_conv_clause::CONV_RESULT_FAILED:
returnPredType = MdamPred::MDAM_RETURN_FALSE;
break;
case ex_conv_clause::CONV_RESULT_ROUNDED_UP:
returnPredType = MdamPred::MDAM_LT;
break;
default:
// ex_assert(0,"adjustPredType: invalid dataConvErrorFlag.");
break;
}
break;
case MdamPred::MDAM_LT:
switch (dataConvErrorFlag)
{
case ex_conv_clause::CONV_RESULT_OK:
case ex_conv_clause::CONV_RESULT_ROUNDED_UP:
// predType remains MDAM_LT.
break;
case ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN:
case ex_conv_clause::CONV_RESULT_FAILED:
returnPredType = MdamPred::MDAM_RETURN_FALSE;
break;
case ex_conv_clause::CONV_RESULT_ROUNDED_DOWN:
case ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX:
returnPredType = MdamPred::MDAM_LE;
break;
default:
// ex_assert(0,"adjustPredType: invalid dataConvErrorFlag.");
break;
}
break;
case MdamPred::MDAM_GE:
switch (dataConvErrorFlag)
{
case ex_conv_clause::CONV_RESULT_OK:
case ex_conv_clause::CONV_RESULT_ROUNDED_UP:
case ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN:
// predType remains MDAM_GE.
break;
case ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX:
case ex_conv_clause::CONV_RESULT_FAILED:
returnPredType = MdamPred::MDAM_RETURN_FALSE;
break;
case ex_conv_clause::CONV_RESULT_ROUNDED_DOWN:
returnPredType = MdamPred::MDAM_GT;
break;
default:
// ex_assert(0,"adjustPredType: invalid dataConvErrorFlag.");
break;
}
break;
case MdamPred::MDAM_GT:
switch (dataConvErrorFlag)
{
case ex_conv_clause::CONV_RESULT_OK:
case ex_conv_clause::CONV_RESULT_ROUNDED_DOWN:
// predType remains MDAM_GT.
break;
case ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX:
case ex_conv_clause::CONV_RESULT_FAILED:
returnPredType = MdamPred::MDAM_RETURN_FALSE;
break;
case ex_conv_clause::CONV_RESULT_ROUNDED_UP:
case ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN:
returnPredType = MdamPred::MDAM_GE;
break;
default:
// ex_assert(0,"adjustPredType: invalid dataConvErrorFlag.");
break;
}
break;
case MdamPred::MDAM_BETWEEN:
// predType remains MDAM_BETWEEN in all cases (unless an error makes it
// MDAM_RETURN_FALSE); only the inclusivity of the endpoints is subject
// to change. We don't want to modify an MdamPred object here (runtime),
// so the inclusivity values are passed by reference to this function
// and the possibly modified values are used by the caller.
// Check start of interval.
if (startInclusion == MdamEnums::MDAM_INCLUDED)
{
switch (dataConvErrorFlag)
{
case ex_conv_clause::CONV_RESULT_OK:
case ex_conv_clause::CONV_RESULT_ROUNDED_UP:
case ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN:
// start of interval remains inclusive
break;
case ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX:
case ex_conv_clause::CONV_RESULT_FAILED:
returnPredType = MdamPred::MDAM_RETURN_FALSE;
break;
case ex_conv_clause::CONV_RESULT_ROUNDED_DOWN:
// start of interval becomes noninclusive
startInclusion = MdamEnums::MDAM_EXCLUDED; ;
break;
default:
// ex_assert(0,"adjustPredType: invalid dataConvErrorFlag.");
break;
}
}
else // start of interval is noninclusive
{
switch (dataConvErrorFlag)
{
case ex_conv_clause::CONV_RESULT_OK:
case ex_conv_clause::CONV_RESULT_ROUNDED_DOWN:
// start of interval remains noninclusive
break;
case ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX:
case ex_conv_clause::CONV_RESULT_FAILED:
returnPredType = MdamPred::MDAM_RETURN_FALSE;
break;
case ex_conv_clause::CONV_RESULT_ROUNDED_UP:
case ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN:
// start of interval becomes inclusive
startInclusion = MdamEnums::MDAM_INCLUDED;
break;
default:
// ex_assert(0,"adjustPredType: invalid dataConvErrorFlag.");
break;
}
}
// Check end of interval.
if (endInclusion == MdamEnums::MDAM_INCLUDED)
{
switch (dataConvErrorFlag2)
{
case ex_conv_clause::CONV_RESULT_OK:
case ex_conv_clause::CONV_RESULT_ROUNDED_DOWN:
case ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX:
// end of interval remains inclusive.
break;
case ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN:
case ex_conv_clause::CONV_RESULT_FAILED:
returnPredType = MdamPred::MDAM_RETURN_FALSE;
break;
case ex_conv_clause::CONV_RESULT_ROUNDED_UP:
// end of interval becomes noninclusive.
endInclusion = MdamEnums::MDAM_EXCLUDED;
break;
default:
// ex_assert(0,"adjustPredType: invalid dataConvErrorFlag2.");
break;
}
}
else // end of interval is noninclusive
{
switch (dataConvErrorFlag2)
{
case ex_conv_clause::CONV_RESULT_OK:
case ex_conv_clause::CONV_RESULT_ROUNDED_UP:
// end of interval remains noninclusive.
break;
case ex_conv_clause::CONV_RESULT_ROUNDED_UP_TO_MIN:
case ex_conv_clause::CONV_RESULT_FAILED:
returnPredType = MdamPred::MDAM_RETURN_FALSE;
break;
case ex_conv_clause::CONV_RESULT_ROUNDED_DOWN:
case ex_conv_clause::CONV_RESULT_ROUNDED_DOWN_TO_MAX:
// end of interval becomes inclusive.
endInclusion = MdamEnums::MDAM_INCLUDED;
break;
default:
// ex_assert(0,"adjustPredType: invalid dataConvErrorFlag2.");
break;
}
}
break;
case MdamPred::MDAM_ISNULL: // IS NULL predicate on ASC column
break;
case MdamPred::MDAM_ISNULL_DESC: // IS NULL predicate on DESC column
break;
case MdamPred::MDAM_ISNOTNULL:
break;
default:
// ex_assert(0,"adjustPredType: invalid predType.");
break;
}
return returnPredType;
}
ex_expr::exp_return_type MdamPred::getValue_(ExExprPtr value,
atp_struct *atp0,
atp_struct *atp1)
{
ex_expr::exp_return_type returnExpReturnType = ex_expr::EXPR_OK;
if (value)
{
returnExpReturnType = value->eval(atp0,atp1);
}
return returnExpReturnType;
}
Long MdamPred::pack(void *space)
{
value_.pack(space);
value2_.pack(space);
next_.pack(space);
return NAVersionedObject::pack(space);
}
Lng32 MdamPred::unpack(void * base, void * reallocator)
{
if(value_.unpack(base, reallocator)) return -1;
if(value2_.unpack(base, reallocator)) return -1;
return NAVersionedObject::unpack(base, reallocator);
}
ex_expr::exp_return_type MdamPred::fixup(Lng32 base, unsigned short mode,
const ex_tcb *tcb,
Space * space, CollHeap *heap)
{
ex_expr::exp_return_type rc = ex_expr::EXPR_OK;
if (value_)
rc = value_->fixup(base,mode,tcb,space,heap,FALSE,NULL);
if (rc == ex_expr::EXPR_OK && value2_)
rc = value2_->fixup(base,mode,tcb,space,heap,FALSE,NULL);
return rc;
}