void PhysSequence::transformOlapFunctions(CollHeap *wHeap) { for(ValueId valId = sequenceFunctions().init(); sequenceFunctions().next(valId); sequenceFunctions().advance(valId)) { ItemExpr * itmExpr = valId.getItemExpr(); //NAType *itmType = itmExpr->getValueId().getType().newCopy(wHeap); if (itmExpr->isOlapFunction()) { NAType *itmType = itmExpr->getValueId().getType().newCopy(wHeap); itmExpr = ((ItmSeqOlapFunction*)itmExpr)->transformOlapFunction(wHeap); CMPASSERT(itmExpr); if(itmExpr->getValueId() != valId) { itmExpr = new (wHeap) Cast(itmExpr, itmType); itmExpr->synthTypeAndValueId(TRUE); valId.replaceItemExpr(itmExpr); itmExpr->getValueId().changeType(itmType);//???? } } itmExpr->transformOlapFunctions(wHeap); } }
ItemExpr * addConvNode(ItemExpr *childExpr, ValueIdMap *mapping, CollHeap *wHeap) { if(childExpr->getOperatorType() != ITM_CONVERT && !childExpr->isASequenceFunction()) { ValueId topValue; mapping->mapValueIdUp(topValue, childExpr->getValueId()); if(topValue == childExpr->getValueId()) { // add the convert node ItemExpr *newChild = new(wHeap) Convert (childExpr); newChild->synthTypeAndValueId(TRUE); mapping->addMapEntry(newChild->getValueId(), childExpr->getValueId()); return newChild; } else { return topValue.getItemExpr(); } } return childExpr; }
// A transformation method for protecting sequence functions from not // being evaluated due to short-circuit evaluation. // void BiLogic::protectiveSequenceFunctionTransformation(Generator *generator) { // Recurse on the children // ItemExpr::protectiveSequenceFunctionTransformation(generator); // Remove the original value id from the node being transformed and // assign it a new value id. // ValueId id = getValueId(); setValueId(NULL_VALUE_ID); synthTypeAndValueId(TRUE); // Construct the new subtree. // // AND/OR -- force right child evaluation // // LOGIC(LEFT_CHILD, RIGHT_CHILD) ==> // BLOCK(RIGHT_CHILD, LOGIC(LEFT_CHILD, RIGHT_CHILD)) // ItemExpr *block = new(generator->wHeap()) ItmBlockFunction(child(1), this); // Replace the old expression with the new expression for the // orginal value id // id.replaceItemExpr(block); // Run the new expression through type and value id synthesis // block->synthTypeAndValueId(TRUE); }
// ItmSeqNotTHISFunction::preCodeGen // // Transforms the NOT THIS sequence function into an offset of its child // that uses the saved ROWS SINCE offset in the ExpGenerator. This allows // the entire part of the expression which changes with each history row to be // calculated inside a single offset expression. All other parts of the // expression are below THIS, i.e., in the current row. // // Note: NOT THIS expressions occur only within a ROWS SINCE. // // EXAMPLE: // select runningsum(this(a)), // rows since (this (b) > a * (c+5)) // from iTab2 sort by a; // // rows since -----> becomes: rows since // | | // > > // / \ / \ // this not this this OFFSET // / \ / / \ // b * b * <not THIS Loop counter> // / \ / \ // a + a + // / \ / \ // c 5 c 5 // // ItemExpr *ItmSeqNotTHISFunction::preCodeGen(Generator *generator) { if (nodeIsPreCodeGenned()) return this; markAsPreCodeGenned(); // Get some local handles... // CollHeap *wHeap = generator->wHeap(); ItemExpr *itmChild = child(0)->castToItemExpr(); ItemExpr *savedRowsSinceCounter = generator->getExpGenerator()->getRowsSinceCounter(); GenAssert(savedRowsSinceCounter, "ItmSeqNotTHIS::preCodeGen -- ROWS SINCE counter is NULL."); // Generate the new OFFSET expression // ItemExpr *offExpr = new(wHeap) ItmSeqOffset(itmChild, savedRowsSinceCounter); ((ItmSeqOffset *)offExpr)->setIsOLAP(isOLAP()); // Get value Ids and types for all of the items. Must do this typing before // replacing this value Id's item expression -- otherwise, the typing // will give a result different than the type already computed for this // sequence function. // offExpr->synthTypeAndValueId(TRUE); // Replace the original value ID with the new expression. // getValueId().replaceItemExpr(offExpr); // Return the preCodeGen of the new OFFSET expression. // return offExpr->preCodeGen(generator); }
// A transformation method for protecting sequence functions from not // being evaluated due to short-circuit evaluation. // void ItmScalarMinMax::protectiveSequenceFunctionTransformation (Generator *generator) { // Recurse on the children // ItemExpr::protectiveSequenceFunctionTransformation(generator); // Remove the original value id from the node being transformed. // ValueId id = getValueId(); setValueId(NULL_VALUE_ID); synthTypeAndValueId(TRUE); // Construct the new subtree. // // SCALAR_MIN/MAX -- force evaluation of both children // // SCALAR(LEFT_CHILD, RIGHT_CHILD) ==> // BLOCK(BLOCK(LEFT_CHILD, RIGHT_CHILD), // SCALAR(LEFT_CHILD, RIGHT_CHILD)) // ItemExpr *block = new(generator->wHeap()) ItmBlockFunction (new(generator->wHeap()) ItmBlockFunction(child(0), child(1)), this); // Replace the old expression with the new expression for the // orginal value id // id.replaceItemExpr(block); // Run the new expression through type and value id synthesis // block->synthTypeAndValueId(TRUE); }
void RelSequence::addCancelExpr(CollHeap *wHeap) { ItemExpr *cPred = NULL; if (this->partition().entries() > 0) { return; } if(cancelExpr().entries() > 0) { return; } for(ValueId valId = selectionPred().init(); selectionPred().next(valId); selectionPred().advance(valId)) { ItemExpr *pred = valId.getItemExpr(); // Look for preds that select a prefix of the sequence. // Rank() < const; Rank <= const; const > Rank; const >= Rank ItemExpr *op1 = NULL; ItemExpr *op2 = NULL; if(pred->getOperatorType() == ITM_LESS || pred->getOperatorType() == ITM_LESS_EQ) { op1 = pred->child(0); op2 = pred->child(1); } else if (pred->getOperatorType() == ITM_GREATER || pred->getOperatorType() == ITM_GREATER_EQ) { op1 = pred->child(1); op2 = pred->child(0); } NABoolean negate; if (op1 && op2 && (op2->getOperatorType() == ITM_CONSTANT || op2->getOperatorType() == ITM_DYN_PARAM) && (op1->getOperatorType() == ITM_OLAP_RANK || op1->getOperatorType() == ITM_OLAP_DRANK || (op1->getOperatorType() == ITM_OLAP_COUNT && op1->child(0)->getOperatorType() == ITM_CONSTANT && !op1->child(0)->castToConstValue(negate)->isNull()))) { cPred = new(wHeap) UnLogic(ITM_NOT, pred); //break at first occurence break; } } if(cPred) { cPred->synthTypeAndValueId(TRUE); cancelExpr().insert(cPred->getValueId()); } }
// A transformation method for protecting sequence functions from not // being evaluated due to short-circuit evaluation. // void Case::protectiveSequenceFunctionTransformation(Generator *generator) { // Recurse on the children // ItemExpr::protectiveSequenceFunctionTransformation(generator); // Remove the original value id from the node being transformed and // assign it a new value id. // ValueId id = getValueId(); setValueId(NULL_VALUE_ID); synthTypeAndValueId(TRUE); // Construct the new subtree. // // Case -- force evaluation of all the WHEN, THEN and ELSE parts // // CASE(IFE1(W1,T1,IFE2(W2,T2,IFE3(...)))) ==> // BLOCK(BLOCK(BLOCK(W1,T1),BLOCK(W2,T2)), CASE(...)) // // Decend the ITM_IF_THEN_ELSE tree pulling out each WHEN and THEN pair. // Mate each pair with a block and attach them to the protected block, // which contains all of the WHEN/THEN pairs for the entire tree. // Also, pull out any CASE operands and attach them to the protected // block as well. // ItemExpr *block = NULL; ItemExpr *ife = child(0); for(; (ife != NULL) && (ife->getOperatorType() == ITM_IF_THEN_ELSE); ife = ife->child(2)) { ItemExpr *sub = new(generator->wHeap()) ItmBlockFunction(ife->child(0), ife->child(1)); if(block) block = new(generator->wHeap()) ItmBlockFunction(sub, block); else block = sub; } // Add the ELSE condition, if any to the protected block // if(ife) block = new(generator->wHeap()) ItmBlockFunction(ife, block); // Construct the top-level block function. The left child is the protected // block, which contains all of the expresssions that need to be // pre-evaluated. This right child is the original case statement. // block = new(generator->wHeap()) ItmBlockFunction(block, this); // Replace the old expression with the new expression for the // original id // id.replaceItemExpr(block); // Run the new expression through type and value id synthesis // block->synthTypeAndValueId(TRUE); }
// ItmSeqOffset::preCodeGen // // Casts the second child to SqlInt. // ItemExpr *ItmSeqOffset::preCodeGen(Generator *generator) { if (nodeIsPreCodeGenned()) return this; CollHeap *wHeap = generator->wHeap(); // The following code is being disabled (0 && ...) since it will // sometimes incorrectly think that the output of a tuple list of // contants is a single constant. For example: // SELECT a, b, c, MOVINGSUM(c,b) as MSUM, MOVINGAVG(c,b) as MAVG // FROM (values // (1,1, 1), // (2,0, 2), // (3,2, NULL), // (4,0, 6), // (5,3, 7)) as T(a,b,c) // SEQUENCE BY a; // // For this query it will think that the offset index (b) is a // constant and it will use the value 3 for the // offsetConstantValue_. // if (0 && getArity() > 1) { NABoolean negate; ConstValue *cv = child(1)->castToConstValue(negate); if (cv AND cv->canGetExactNumericValue()) { Lng32 scale; Int64 value = cv->getExactNumericValue(scale); if(scale == 0 && value >= 0 && value < INT_MAX) { value = (negate ? -value : value); offsetConstantValue_ = (Int32)value; child(1) = NULL; } } } if (getArity() > 1) { const NAType &cType = child(1)->getValueId().getType(); // (must be) signed; nulls allowed (if allowed by child1) ItemExpr *castExpr = new (wHeap) Cast (child(1), new (wHeap) SQLInt(wHeap, TRUE, cType.supportsSQLnullLogical())); castExpr->synthTypeAndValueId(TRUE); child (1) = castExpr; } return ItemExpr::preCodeGen(generator); }
// PhysSequence::computeHistoryAttributes // // Helper function to compute the attribute for the history buffer based // on the items projected from the child and the computed history items. // Also, adds the attribute information the the map table. // void PhysSequence::computeHistoryAttributes(Generator *generator, MapTable *localMapTable, Attributes **attrs, const ValueIdSet &historyIds) const { // Get a local handle on some of the generator objects. // CollHeap *wHeap = generator->wHeap(); // Populate the attribute vector with the flattened list of sequence // functions and/or sequence function arguments that must be in the // history row. Add convert nodes for the items that are not sequence // functions to force them to be moved into the history row. // if(NOT historyIds.isEmpty()) { Int32 i = 0; ValueId valId; for (valId = historyIds.init(); historyIds.next(valId); historyIds.advance(valId)) { // If this is not a sequence function, then insert a convert // node. // if(!valId.getItemExpr()->isASequenceFunction()) { // Get a handle on the original expression and erase // the value ID. // ItemExpr *origExpr = valId.getItemExpr(); origExpr->setValueId(NULL_VALUE_ID); origExpr->markAsUnBound(); // Construct the cast expression with the original expression // as the child -- must have undone the child value ID to // avoid recursion later. // ItemExpr *castExpr = new(wHeap) Cast(origExpr, &(valId.getType())); // Replace the expression for the original value ID and the // synthesize the types and value ID for the new expression. // valId.replaceItemExpr(castExpr); castExpr->synthTypeAndValueId(TRUE); } attrs[i++] = (generator->addMapInfoToThis(localMapTable, valId, 0))->getAttr(); } } } // PhysSequence::computeHistoryAttributes
ItemExpr *ItmLagOlapFunction::preCodeGen(Generator *generator) { if (nodeIsPreCodeGenned()) return this; CollHeap *wHeap = generator->wHeap(); if (getArity() > 1) { const NAType &cType = child(1)->getValueId().getType(); ItemExpr *castExpr = new (wHeap) Cast (child(1), new (wHeap) SQLInt(wHeap, TRUE, cType.supportsSQLnullLogical())); castExpr->synthTypeAndValueId(TRUE); child (1) = castExpr; } return ItemExpr::preCodeGen(generator); }
void PhysSequence::computeReadNReturnItems( ValueId topSeqVid, ValueId vid, const ValueIdSet &outputFromChild, CollHeap *wHeap) { ItemExpr * itmExpr = vid.getItemExpr(); if (outputFromChild.contains(vid)) { return; } //test if itm_minus and then if negative offset .... if ( itmExpr->getOperatorType() == ITM_OFFSET && ((ItmSeqOffset *)itmExpr)->getOffsetConstantValue() < 0) { readSeqFunctions() -= topSeqVid; returnSeqFunctions() += topSeqVid; readSeqFunctions() += itmExpr->child(0)->castToItemExpr()->getValueId(); return; } if (itmExpr->getOperatorType() == ITM_MINUS) { ItemExpr * chld0 = itmExpr->child(0)->castToItemExpr(); if ( chld0->getOperatorType() == ITM_OFFSET && ((ItmSeqOffset *)chld0)->getOffsetConstantValue() <0) { readSeqFunctions() -= topSeqVid; returnSeqFunctions() += topSeqVid; readSeqFunctions() += chld0->child(0)->castToItemExpr()->getValueId(); ItemExpr * chld1 = itmExpr->child(1)->castToItemExpr(); if (chld1->getOperatorType() == ITM_OFFSET && ((ItmSeqOffset *)chld1)->getOffsetConstantValue() < 0) { readSeqFunctions() += chld1->child(0)->castToItemExpr()->getValueId(); } else { readSeqFunctions() += chld1->getValueId(); } return; } } if (itmExpr->getOperatorType() == ITM_OLAP_MIN || itmExpr->getOperatorType() == ITM_OLAP_MAX) { ItmSeqOlapFunction * olap = (ItmSeqOlapFunction *)itmExpr; if (olap->getframeEnd()>0) { readSeqFunctions() -= topSeqVid; returnSeqFunctions() += topSeqVid; ItemExpr *newChild = new(wHeap) Convert (itmExpr->child(0)->castToItemExpr()); newChild->synthTypeAndValueId(TRUE); itmExpr->child(0) = newChild; readSeqFunctions() += newChild->getValueId(); return; } } if (itmExpr->getOperatorType() == ITM_SCALAR_MIN || itmExpr->getOperatorType() == ITM_SCALAR_MAX) { ItemExpr * chld0 = itmExpr->child(0)->castToItemExpr(); ItemExpr * chld1 = itmExpr->child(1)->castToItemExpr(); if ((chld0->getOperatorType() == ITM_OLAP_MIN && chld1->getOperatorType() == ITM_OLAP_MIN )|| (chld0->getOperatorType() == ITM_OLAP_MAX && chld1->getOperatorType() == ITM_OLAP_MAX )) { ItmSeqOlapFunction * olap0 = (ItmSeqOlapFunction *)chld0; ItmSeqOlapFunction * olap1 = (ItmSeqOlapFunction *)chld1; if ( olap1->getframeEnd()>0) { CMPASSERT(olap0->getframeEnd()==0); readSeqFunctions() -= topSeqVid; returnSeqFunctions() += topSeqVid; readSeqFunctions() += olap0->getValueId(); ItemExpr *newChild = new(wHeap) Convert (olap1->child(0)->castToItemExpr()); newChild->synthTypeAndValueId(TRUE); olap1->child(0) = newChild; readSeqFunctions() += newChild->getValueId(); } else { CMPASSERT(olap1->getframeEnd()==0); readSeqFunctions() -= topSeqVid; returnSeqFunctions() += topSeqVid; readSeqFunctions() += olap1->getValueId(); ItemExpr *newChild = new(wHeap) Convert (olap0->child(0)->castToItemExpr()); newChild->synthTypeAndValueId(TRUE); olap0->child(0) = newChild; readSeqFunctions() += newChild->getValueId(); } return; } } for (Int32 i= 0 ; i < itmExpr->getArity(); i++) { ItemExpr * chld= itmExpr->child(i); computeReadNReturnItems(topSeqVid, chld->getValueId(), outputFromChild, wHeap); } }//void PhysSequence::computeReadNReturnItems(ItemExpr * other)
// ItmSeqMovingFunction::preCodeGen // // All of the moving sequence functions have been transformed away at this // point except min and max. Transform these operations to a while-loop which // iterates over the past rows testing the min/max condition for each row. // Use the ItmScalarMin/Max functions for computing the min/max. // ItemExpr *ItmSeqMovingFunction::preCodeGen(Generator *generator) { if (nodeIsPreCodeGenned()) return this; markAsPreCodeGenned(); // Get some local handles... // CollHeap *wHeap = generator->wHeap(); ItemExpr *itmChild = child(0)->castToItemExpr(); ItemExpr *itmWindow = child(1)->castToItemExpr(); // What scalar operation needs to be done. // OperatorTypeEnum operation; if(getOperatorType() == ITM_MOVING_MIN) operation = ITM_SCALAR_MIN; else operation = ITM_SCALAR_MAX; // Allocate a HostVar for local storage of the index. // ItemExpr *itmLocalCounter = new(wHeap) HostVar("_sys_LocalCounter", new(wHeap) SQLInt(wHeap, TRUE,FALSE), TRUE); // Expression to initailize the iterator. // ItemExpr *itmLocalCounterInitialize = new(wHeap) Assign(itmLocalCounter, new(wHeap) ConstValue(0), FALSE); // Expression to increment the iterator. // ItemExpr *itmLocalCounterIncrement = new(wHeap) Assign(itmLocalCounter, new(wHeap) BiArith(ITM_PLUS, itmLocalCounter, new (wHeap) ConstValue(1)), FALSE); // Allocate a HostVar for referencing the result before it is computed. // ItemExpr *itmResult = new(wHeap) HostVar("_sys_Result", getValueId().getType().newCopy(wHeap), TRUE); // Expression to initialize the result. // ItemExpr *itmResultInitialize = new(wHeap) Assign(itmResult, new(wHeap) ConstValue()); // Expression to compute the min/max. // ItemExpr *itmOffsetExpr = new(wHeap) ItmSeqOffset( itmChild, itmLocalCounter); ((ItmSeqOffset *)itmOffsetExpr)->setIsOLAP(isOLAP()); ItemExpr *itmResultUpdate = new(wHeap) Assign(itmResult, new(wHeap) ItmScalarMinMax(operation, itmResult, itmOffsetExpr)); // Construct code blocks for the initialization and body for the while-loop // ItemExpr *itmInit = new(wHeap) ItmBlockFunction(itmLocalCounterInitialize, itmResultInitialize); ItemExpr *itmBody = new(wHeap) ItmBlockFunction(itmResultUpdate, itmLocalCounterIncrement); // Construct the While loop (i < window) // ItemExpr *itmLoopCondition = new(wHeap) BiRelat (ITM_LESS, itmLocalCounter, itmWindow); ItemExpr *itmWhile = new(wHeap) ItmWhileFunction(itmBody, itmLoopCondition); // Construct the blocks to contain the initialization and looping. // The result is the final value of the min/max. // ItemExpr *itmBlock = new(wHeap) ItmBlockFunction (new(wHeap) ItmBlockFunction(itmInit, itmWhile), itmResult); // Replace the item for this value id with the new item expression. // getValueId().replaceItemExpr(itmBlock); // Run the new expression through type and value Id synthesis. // itmBlock->synthTypeAndValueId(TRUE); // Map the reference to the result to the actual result in the map table. // Attributes *attr = generator->getMapInfo(itmBlock->getValueId())->getAttr(); MapInfo *mapInfo = generator->addMapInfo(itmResult->getValueId(), attr); itmResult->markAsPreCodeGenned(); mapInfo->codeGenerated(); // Return the preCodeGen of the new expression. // return itmBlock->preCodeGen(generator); }
ItemExpr *ItmSeqOlapFunction::preCodeGen(Generator *generator) { if (getOperatorType() != ITM_OLAP_MIN && getOperatorType() != ITM_OLAP_MAX) { GenAssert(0, "ItmSeqOlapFunction::preCodeGen -- Should never get here!"); return 0; } if (nodeIsPreCodeGenned()) return this; markAsPreCodeGenned(); // Get some local handles... // CollHeap *wHeap = generator->wHeap(); ItemExpr *itmChild = child(0)->castToItemExpr(); //ItemExpr *itmWindow = child(1)->castToItemExpr(); // What scalar operation needs to be done. // OperatorTypeEnum operation; if(getOperatorType() == ITM_OLAP_MIN) operation = ITM_SCALAR_MIN; else operation = ITM_SCALAR_MAX; // Allocate a HostVar for local storage of the index. // ItemExpr *itmLocalCounter = new(wHeap) HostVar("_sys_LocalCounter", new(wHeap) SQLInt(wHeap, TRUE,FALSE), TRUE); // Expression to initailize the iterator. // ItemExpr *itmLocalCounterInitialize = new(wHeap) Assign(itmLocalCounter, new(wHeap) ConstValue(frameStart_), FALSE); // Expression to increment the iterator. // ItemExpr *itmLocalCounterIncrement = new(wHeap) Assign(itmLocalCounter, new(wHeap) BiArith(ITM_PLUS, itmLocalCounter, new (wHeap) ConstValue(1)), FALSE); // Allocate a HostVar for referencing the result before it is computed. // ItemExpr *itmResult = new(wHeap) HostVar("_sys_Result", getValueId().getType().newCopy(wHeap), TRUE); // Expression to initialize the result. // ItemExpr *itmResultInitialize = new(wHeap) Assign(itmResult, new(wHeap) ConstValue()); // Expression to compute the min/max. // ItemExpr * invCouter= new(wHeap) BiArith(ITM_MINUS, new (wHeap) ConstValue(0), itmLocalCounter); ItemExpr * itmOffsetExpr = new(wHeap) ItmSeqOffset( itmChild, invCouter); //ItemExpr * itmOffsetIsNotNull = new (wHeap) UnLogic(ITM_IS_NOT_NULL, itmOffsetExpr); ((ItmSeqOffset *)itmOffsetExpr)->setIsOLAP(isOLAP()); ItemExpr *itmResultUpdate = new(wHeap) Assign(itmResult, new(wHeap) ItmScalarMinMax(operation, itmResult, itmOffsetExpr)); // Construct code blocks for the initialization and body for the while-loop // ItemExpr *itmInit = new(wHeap) ItmBlockFunction(itmLocalCounterInitialize, itmResultInitialize); ItemExpr *itmBody = new(wHeap) ItmBlockFunction(itmResultUpdate, itmLocalCounterIncrement); // Construct the While loop (i < window) // ItemExpr *itmLoopCondition = new(wHeap) BiRelat (ITM_LESS_EQ, itmLocalCounter, new(wHeap) ConstValue(frameEnd_)); if (isFrameEndUnboundedFollowing()) //(frameEnd_ == INT_MAX)// not needed in other cases -- can cause issues fo the preceding part { ItemExpr * itmOffset1 = new(wHeap) ItmSeqOffset( itmChild, invCouter,NULL,TRUE); ItemExpr * itmOffset1IsNotNull = new (wHeap) UnLogic(ITM_IS_NOT_NULL, itmOffset1); ((ItmSeqOffset *)itmOffset1)->setIsOLAP(isOLAP()); itmLoopCondition = itmOffset1IsNotNull; //new (wHeap) BiLogic( ITM_AND, // itmLoopCondition, // itmOffset1IsNotNull); } ItemExpr *itmWhile = new(wHeap) ItmWhileFunction(itmBody, itmLoopCondition); // Construct the blocks to contain the initialization and looping. // The result is the final value of the min/max. // ItemExpr *itmBlock = new(wHeap) ItmBlockFunction (new(wHeap) ItmBlockFunction(itmInit, itmWhile), itmResult); // Replace the item for this value id with the new item expression. // getValueId().replaceItemExpr(itmBlock); // Run the new expression through type and value Id synthesis. // itmBlock->synthTypeAndValueId(TRUE); // Map the reference to the result to the actual result in the map table. // Attributes *attr = generator->getMapInfo(itmBlock->getValueId())->getAttr(); MapInfo *mapInfo = generator->addMapInfo(itmResult->getValueId(), attr); itmResult->markAsPreCodeGenned(); mapInfo->codeGenerated(); // Return the preCodeGen of the new expression. // return itmBlock->preCodeGen(generator); }
// ItmSeqRunningFunction::preCodeGen // // Transforms the running sequence functions into scalar expressions // that use offset to reference the previous value of the function. // ItemExpr *ItmSeqRunningFunction::preCodeGen(Generator *generator) { if (nodeIsPreCodeGenned()) return this; markAsPreCodeGenned(); // Get some local handles... // CollHeap *wHeap = generator->wHeap(); ItemExpr *itmChild = child(0)->castToItemExpr(); // Allocate a HostVar for referencing the result before it is computed. // ItemExpr *itmResult = new(wHeap) HostVar("_sys_Result", getValueId().getType().newCopy(wHeap), TRUE); // Create an item expression to reference the previous // value of this running sequence function. // ItemExpr *offExpr = new(wHeap) ItmSeqOffset(itmResult, 1); ((ItmSeqOffset *)offExpr)->setIsOLAP(isOLAP()); // Add the sequence function specific computation. // ItemExpr *itmNewSeqFunc = 0; switch(getOperatorType()) { case ITM_RUNNING_COUNT: { // By this point ITM_RUNNING_COUNT is count(column). The count // is one more than the previous count if the current column is // not null, otherwise, it is the previous count. // // Create the increment value. For non-nullable values, this // is always 1, essentially runningcount(*). // ItemExpr *incr; if(itmChild->getValueId().getType().supportsSQLnullLogical()) { incr = generator->getExpGenerator()->createExprTree ("CASE WHEN @A1 IS NULL THEN @A3 ELSE @A2 END", 0, 3, itmChild, new(wHeap) ConstValue(1), new(wHeap) ConstValue(0)); } else { incr = new(wHeap) ConstValue(1); } ((ItmSeqOffset *)offExpr)->setNullRowIsZero(TRUE); ItemExpr *src = offExpr; // Do the increment. // itmNewSeqFunc = new(wHeap) BiArith(ITM_PLUS, src, incr); } break; case ITM_RUNNING_SUM: { // SUM(sum from previous row, child) // itmNewSeqFunc = new(wHeap) BiArithSum(ITM_PLUS, offExpr, itmChild); } break; case ITM_RUNNING_MIN: { // MIN(min from previous rows, child) // itmNewSeqFunc = new(wHeap) ItmScalarMinMax(ITM_SCALAR_MIN, offExpr, itmChild); } break; case ITM_RUNNING_MAX: { // MAX(max from previous row, child) // itmNewSeqFunc = new(wHeap) ItmScalarMinMax(ITM_SCALAR_MAX, offExpr, itmChild); } break; case ITM_LAST_NOT_NULL: { // If the current value is null then use the previous value // of last not null. // itmNewSeqFunc = generator->getExpGenerator()->createExprTree ("CASE WHEN @A2 IS NOT NULL THEN @A2 ELSE @A1 END", 0, 2, offExpr, itmChild); } break; case ITM_RUNNING_CHANGE: { // The running change (or 'rows since changed') can have a // composite child (a list of values) // Convert the list of values to a list of offset of values. // ItemExpr *offChild = itmChild; if (itmChild->getOperatorType() == ITM_ITEM_LIST) { // child is a multi-valued expression, transform into multiple // ExprValueId treePtr = itmChild; ItemExprTreeAsList changeValues(&treePtr, ITM_ITEM_LIST, RIGHT_LINEAR_TREE); offChild = new(wHeap) ItmSeqOffset( changeValues[0], 1); ((ItmSeqOffset *)offChild)->setIsOLAP(isOLAP()); // add Offset expressions for all the items of the list // CollIndex nc = changeValues.entries(); for (CollIndex i = 1; i < nc; i++) { ItemExpr *off = new(generator->wHeap()) ItmSeqOffset( changeValues[i], 1); ((ItmSeqOffset *)off)->setIsOLAP(isOLAP()); offChild = new(generator->wHeap()) ItemList(offChild, off); } } else { offChild = new(wHeap) ItmSeqOffset( offChild, 1); ((ItmSeqOffset *)offChild)->setIsOLAP(isOLAP()); } ((ItmSeqOffset *)offExpr)->setNullRowIsZero(TRUE); ItemExpr *prevValue = offExpr; // Compare the value(s) to the previous value(s). Use special // NULLs flags to treat NULLs as values. Two NULL values are // considered equal here. // ItemExpr *pred = new (wHeap) BiRelat(ITM_EQUAL, itmChild, offChild, TRUE); // Special NULLs // running change = // (value(s) == prev(value(s))) ? prev(running change)+1 : 1 // // Compute base value. // itmNewSeqFunc = new (wHeap) IfThenElse(pred, prevValue, new (wHeap) SystemLiteral(0)); itmNewSeqFunc = new (wHeap) Case(NULL, itmNewSeqFunc); // Force the evaluation of the offset expression so that the // result can be reused by subsequent references. // itmNewSeqFunc = new(wHeap) ItmBlockFunction(offChild, itmNewSeqFunc); // Increment the base value. // itmNewSeqFunc = new (wHeap) BiArith(ITM_PLUS, itmNewSeqFunc, new(wHeap) SystemLiteral(1)); } break; } // Get value Ids and types for all of the items. Must do this typing before // replacing this value Id's item expression -- otherwise, the typing // will give a result different than the type already computed for this // sequence function. // GenAssert(itmNewSeqFunc, "ItmSeqRunningFunction::preCodeGen -- Unexpected Operator Type!"); itmNewSeqFunc->synthTypeAndValueId(TRUE); // Replace the original value ID with the new expression. // getValueId().replaceItemExpr(itmNewSeqFunc); // Map the reference to the result to the actual result in the map table. // Attributes *attr = generator->getMapInfo (itmNewSeqFunc->getValueId())->getAttr(); MapInfo *mapInfo = generator->addMapInfo(itmResult->getValueId(), attr); itmResult->markAsPreCodeGenned(); mapInfo->codeGenerated(); // Return the preCodeGen of the new expression. // return itmNewSeqFunc->preCodeGen(generator); }
// getHistoryAttributes // // Helper function that traverses the set of root sequence functions // supplied by the compiler and constructs the set of all of the // attributes that must be materialized in the history row. // void PhysSequence::getHistoryAttributes(const ValueIdSet &sequenceFunctions, const ValueIdSet &outputFromChild, ValueIdSet &historyAttributes, NABoolean addConvNodes, CollHeap *wHeap, ValueIdMap *origAttributes) const { if(addConvNodes && !origAttributes) { origAttributes = new (wHeap) ValueIdMap(); } ValueIdSet children; for(ValueId valId = sequenceFunctions.init(); sequenceFunctions.next(valId); sequenceFunctions.advance(valId)) { if(valId.getItemExpr()->isASequenceFunction()) { ItemExpr *itmExpr = valId.getItemExpr(); switch(itmExpr->getOperatorType()) { // The child needs to be in the history row. // case ITM_OFFSET: case ITM_ROWS_SINCE: case ITM_THIS: case ITM_NOT_THIS: // If the child needs to be in the history buffer, then // add a Convert node to force the value to be moved to the // history buffer. if (addConvNodes) { itmExpr->child(0) = addConvNode(itmExpr->child(0), origAttributes, wHeap); } historyAttributes += itmExpr->child(0)->getValueId(); break; // The sequence function needs to be in the history row. // case ITM_RUNNING_SUM: case ITM_RUNNING_COUNT: case ITM_RUNNING_MIN: case ITM_RUNNING_MAX: case ITM_LAST_NOT_NULL: historyAttributes += itmExpr->getValueId(); break; /* // after PhysSequence precode gen OLAP sum and count are already transform,ed into running // this is used during optimization phase-- case ITM_OLAP_SUM: case ITM_OLAP_COUNT: case ITM_OLAP_RANK: case ITM_OLAP_DRANK: if (addConvNodes) { itmExpr->child(0) = addConvNode(itmExpr->child(0), origAttributes, wHeap); } historyAttributes += itmExpr->child(0)->getValueId(); //historyAttributes += itmExpr->getValueId(); break; */ // The child and sequence function need to be in the history row. // case ITM_OLAP_MIN: case ITM_OLAP_MAX: case ITM_MOVING_MIN: case ITM_MOVING_MAX: // If the child needs to be in the history buffer, then // add a Convert node to force the value to be moved to the // history buffer. if (addConvNodes) { itmExpr->child(0) = addConvNode(itmExpr->child(0), origAttributes, wHeap); } historyAttributes += itmExpr->child(0)->getValueId(); historyAttributes += itmExpr->getValueId(); break; case ITM_RUNNING_CHANGE: if (itmExpr->child(0)->getOperatorType() == ITM_ITEM_LIST) { // child is a multi-valued expression // ExprValueId treePtr = itmExpr->child(0); ItemExprTreeAsList changeValues(&treePtr, ITM_ITEM_LIST, RIGHT_LINEAR_TREE); CollIndex nc = changeValues.entries(); ItemExpr *newChild = NULL; if(addConvNodes) { newChild = addConvNode(changeValues[nc-1], origAttributes, wHeap); historyAttributes += newChild->getValueId(); } else { historyAttributes += changeValues[nc-1]->getValueId(); } // add each item in the list // for (CollIndex i = nc; i > 0; i--) { if(addConvNodes) { ItemExpr *conv = addConvNode(changeValues[i-1], origAttributes, wHeap); newChild = new(wHeap) ItemList(conv, newChild); newChild->synthTypeAndValueId(TRUE); historyAttributes += conv->getValueId(); } else { historyAttributes += changeValues[i-1]->getValueId(); } } if(addConvNodes) { itmExpr->child(0) = newChild; } } else { // If the child needs to be in the history buffer, then // add a Convert node to force the value to be moved to the // history buffer. if (addConvNodes) { itmExpr->child(0) = addConvNode(itmExpr->child(0), origAttributes, wHeap); } historyAttributes += itmExpr->child(0)->getValueId(); } historyAttributes += itmExpr->getValueId(); break; default: CMPASSERT(0); } } // Gather all the children, and if not empty, recurse down to the // next level of the tree. // for(Lng32 i = 0; i < valId.getItemExpr()->getArity(); i++) { if (!outputFromChild.contains(valId.getItemExpr()->child(i)->getValueId())) //!valId.getItemExpr()->child(i)->nodeIsPreCodeGenned()) { children += valId.getItemExpr()->child(i)->getValueId(); } } } if (NOT children.isEmpty()) { getHistoryAttributes( children, outputFromChild, historyAttributes, addConvNodes, wHeap, origAttributes); } } // PhysSequence::getHistoryAttributes
// ItmSeqRowsSince::preCodeGen // // Transform ItmSeqRowsSince to a do-while which iterates over the // past rows testing the since condition for each row. The expression // returns the relative index of the first row in which the since condition is // TRUE or the number of rows in the history buffer + 1. // ItemExpr *ItmSeqRowsSince::preCodeGen(Generator *generator) { if (nodeIsPreCodeGenned()) return this; markAsPreCodeGenned(); // Get some local handles... // CollHeap *wHeap = generator->wHeap(); ItemExpr *itmChild = child(0)->castToItemExpr(); ItemExpr *itmWindow = NULL; if(getArity() > 1) itmWindow = child(1)->castToItemExpr(); // Allocate a counter for iterating through the past rows. The counter // also doubles as the result of the rows since. This requires the // counter to be nullable in case the condition is never true. // ItemExpr *itmLocalCounter = new(wHeap) ItmExpressionVar(getValueId().getType().newCopy(wHeap)); // If the ROWS SINCE is inclusive start the iterator at -1 to // include the current row, otherwise, start the iterator at 0 to // skip the current row. (The iterator is incremented before testing // the condition since a DoWhile loop is used -- thus, the iterator // is not starting at 0 and 1.) // ItemExpr *startExpr; if(this->includeCurrentRow()) startExpr = new(wHeap) ConstValue(-1); else startExpr = new(wHeap) ConstValue(0); // Expression to initialize the iterator. -- and put the variable in // the map table before it is used in an assignment. // ItemExpr *itmInitializeCounter = new(wHeap) ItmBlockFunction (itmLocalCounter, new(wHeap) Assign(itmLocalCounter, startExpr, FALSE)); // Expression to increment the iterator. // ItemExpr *itmIncrementCounter = new(wHeap) Assign (itmLocalCounter, new(wHeap) BiArith(ITM_PLUS, itmLocalCounter, new (wHeap) ConstValue(1)), FALSE); // Expression to make the counter NULL. // ItemExpr *itmNullCounter = new(wHeap) Assign(itmLocalCounter, new(wHeap) ConstValue(), FALSE); // Expression for DoWhile looping condition. // // AND(0) returns TRUE if the looping should continue, FALSE otherwise. // The looping should continue as long as the counter is within the // row history. the counter is less than the maximum search offset, and // the condition has not returned TRUE. // // The left side of AND(0) returns TRUE if the OFFSET of the current // counter value is within the row history and the counter is less // than the maximum search offset. If the left side of the AND(0) // returns FALSE, the counter is set to NULL because the condition // was not found to be true withing the search window -- and the // counter doubles as the result. In this case the right side of the // AND(0) is not evaluated because of short circuit evaluation. // // The right side of AND(0) returns TRUE if the condition is not TRUE // relative to the row indicated by counter. // // // AND(0) // ____/ \___ // / \ // / \ // _ OR _ IS_NOT_TRUE // / \ | // / BLOCK OFFSET // AND(2) / \ / \ // / \ Counter=NULL FALSE ROWS SINCE Counter // IS_NOT_NULL \ (cond) // / LESS THAN // / / \ // OFFSET Counter MaxWindow // / \ //ROWS SINCE Counter // (cond) // // Expression to test if counter is within history range. // ItemExpr *itmRangeIndicator = new (wHeap) ItmSeqOffset( new (wHeap) UnLogic (ITM_IS_TRUE,itmChild), itmLocalCounter); ((ItmSeqOffset *)itmRangeIndicator)->setIsOLAP(isOLAP()); // Expression to compute AND(2). If the window is not specified, then // return the left child of AND(2). // ItemExpr *itmAnd2; if(itmWindow) { itmAnd2 = new(wHeap) BiLogic (ITM_AND, new(wHeap) UnLogic (ITM_IS_NOT_NULL, itmRangeIndicator), new(wHeap) BiRelat (ITM_LESS_EQ, itmLocalCounter, itmWindow)); } else { itmAnd2 = new(wHeap) UnLogic (ITM_IS_NOT_NULL, itmRangeIndicator); } // Expression to compute OR // ItemExpr *itmOr = new(wHeap) BiLogic (ITM_OR, itmAnd2, new(wHeap) ItmBlockFunction(itmNullCounter, new(wHeap) ConstValue(0))); // Expression to compute AND(0) // ItemExpr *itmLoopCondition = new(wHeap) BiLogic (ITM_AND, itmOr, new(wHeap) UnLogic(ITM_NOT, new (wHeap) UnLogic(ITM_IS_TRUE,itmChild))); // Construct the Do-While loop // ItemExpr *itmDoWhile = new(wHeap) ItmDoWhileFunction(itmIncrementCounter, itmLoopCondition); // Construct the counter initialization along with the looping. // ItemExpr *itmBlockPart = new(wHeap) ItmBlockFunction(itmInitializeCounter, itmDoWhile); // Finally, construct a block to execute the operation and return // the FINAL value of the counter as the result. This is tricky, because // the do-while returns the value of the counter for the last time // the body (the increment expression) is executed which may be // different than the last value of the counter. // ItemExpr *itmBlock = new(wHeap) ItmBlockFunction(itmBlockPart, itmLocalCounter); // Replace the item for this value id with the new result item expression. // getValueId().replaceItemExpr(itmBlock); // Run the new expression through type and value Id synthesis. // itmBlock->synthTypeAndValueId(TRUE); // Save the previous rows since counter and set to the current one. // ItemExpr *savedRowsSinceCounter = generator->getExpGenerator()->getRowsSinceCounter(); generator->getExpGenerator()->setRowsSinceCounter (itmLocalCounter); // Save the preCodeGen of the new expression. // ItemExpr *tmpBlock = itmBlock->preCodeGen(generator); // Restore the saved ROWS SINCE counter expression. // generator->getExpGenerator()->setRowsSinceCounter (savedRowsSinceCounter); // return the saved expression // return tmpBlock; }
ItemExpr * buildEncodeTree(desc_struct * column, desc_struct * key, NAString * dataBuffer, //IN:contains original value Generator * generator, ComDiagsArea * diagsArea) { ExpGenerator * expGen = generator->getExpGenerator(); // values are encoded by evaluating the expression: // encode (cast (<dataBuffer> as <datatype>)) // where <dataBuffer> points to the string representation of the // data value to be encoded, and <datatype> contains the // PIC repsentation of the columns's datatype. // create the CAST part of the expression using the parser. // if this is a nullable column and the key value passed in // is a NULL value, then treat it as a special case. A NULL value // is passed in as an unquoted string of characters NULL in the // dataBuffer. This case has to be treated different since the // parser doesn't recognize the syntax "CAST (NULL as <datatype>)". NAString ns; ItemExpr * itemExpr; NABoolean nullValue = FALSE; NABoolean caseinsensitiveEncode = FALSE; if (column->body.columns_desc.caseinsensitive) caseinsensitiveEncode = TRUE; if (column->body.columns_desc.null_flag && dataBuffer->length() >= 4 && str_cmp(*dataBuffer, "NULL", 4) == 0) { nullValue = TRUE; ns = "CAST ( @A1 AS "; ns += column->body.columns_desc.pictureText; ns += ");"; // create a NULL constant ConstValue * nullConst = new(expGen->wHeap()) ConstValue(); nullConst->synthTypeAndValueId(); itemExpr = expGen->createExprTree(ns, CharInfo::UTF8, ns.length(), 1, nullConst); } else { ns = "CAST ( "; ns += *dataBuffer; ns += " AS "; ns += column->body.columns_desc.pictureText; ns += ");"; itemExpr = expGen->createExprTree(ns, CharInfo::UTF8, ns.length()); } CMPASSERT(itemExpr != NULL); ItemExpr *boundItemExpr = itemExpr->bindNode(generator->getBindWA()); if (boundItemExpr == NULL) return NULL; // make sure that the source and target values have compatible type. // Do this only if source is not a null value. NAString srcval; srcval = ""; srcval += *dataBuffer; srcval += ";"; ItemExpr * srcNode = expGen->createExprTree(srcval, CharInfo::UTF8, srcval.length()); CMPASSERT(srcNode != NULL); srcNode->synthTypeAndValueId(); if ((NOT nullValue) && (NOT srcNode->getValueId().getType().isCompatible(itemExpr->getValueId().getType()))) { if (diagsArea) { emitDyadicTypeSQLnameMsg(-4039, itemExpr->getValueId().getType(), srcNode->getValueId().getType(), column->body.columns_desc.colname, NULL, diagsArea); } return NULL; } if (column->body.columns_desc.null_flag) ((NAType *)&(itemExpr->getValueId().getType()))->setNullable(TRUE); else ((NAType *)&(itemExpr->getValueId().getType()))->setNullable(FALSE); // Explode varchars by moving them to a fixed field // whose length is equal to the max length of varchar. ////collation?? DataType datatype = column->body.columns_desc.datatype; if (DFS2REC::isSQLVarChar(datatype)) { char lenBuf[10]; NAString vc((NASize_T)100); // preallocate a big-enough buf size_t len = column->body.columns_desc.length; if (datatype == REC_BYTE_V_DOUBLE) len /= SQL_DBCHAR_SIZE; vc = "CAST (@A1 as CHAR("; vc += str_itoa(len, lenBuf); if ( column->body.columns_desc.character_set == CharInfo::UTF8 || ( column->body.columns_desc.character_set == CharInfo::SJIS && column->body.columns_desc.encoding_charset == CharInfo::SJIS ) ) { vc += " BYTE"; if (len > 1) vc += "S"; } vc += ") CHARACTER SET "; vc += CharInfo::getCharSetName(column->body.columns_desc.character_set); vc += ");"; itemExpr = expGen->createExprTree(vc, CharInfo::UTF8, vc.length(), 1, itemExpr); itemExpr->synthTypeAndValueId(); ((NAType *)&(itemExpr->getValueId().getType()))-> setNullable(column->body.columns_desc.null_flag); } // add the encode node on top of it. short desc_flag = TRUE; if (key->body.keys_desc.ordering == 0) // ascending desc_flag = FALSE; itemExpr = new(expGen->wHeap()) CompEncode(itemExpr, desc_flag); itemExpr->synthTypeAndValueId(); ((CompEncode*)itemExpr)->setCaseinsensitiveEncode(caseinsensitiveEncode); return itemExpr; }
// ----------------------------------------------------------------------- // make an IndexDesc from an existing TableDesc and an NAFileSet // ----------------------------------------------------------------------- IndexDesc::IndexDesc(TableDesc *tdesc, NAFileSet *fileSet, CmpContext* cmpContext) : tableDesc_(tdesc), clusteringIndexFlag_(FALSE), identityColumnUniqueIndexFlag_(FALSE), partFunc_(NULL), fileSet_(fileSet), cmpContext_(cmpContext), scanBasicCosts_(NULL) { DCMPASSERT( tdesc != NULL AND fileSet != NULL ); Lng32 ixColNumber; ValueId keyValueId; ValueId baseValueId; const NATable *naTable = tdesc->getNATable(); indexLevels_ = fileSet_->getIndexLevels(); // --------------------------------------------------------------------- // Make the column list for the index or vertical partition. // Any reference to index also holds for vertical partitions. // --------------------------------------------------------------------- const NAColumnArray & allColumns = fileSet_->getAllColumns(); // any index gets a new set of IndexColumn // item expressions and new value ids CollIndex i = 0; for (i = 0; i < allColumns.entries(); i++) { ItemExpr *baseItemExpr = NULL; // make a new IndexColumn item expression, indicate how it is // defined (in terms of base table columns) and give a value // id to the new IndexColumn expression if (allColumns[i]->getPosition() >= 0) { baseValueId = tdesc->getColumnList()[allColumns[i]->getPosition()]; baseItemExpr = baseValueId.getItemExpr(); } else { // this column doesn't exist in the base table. // This is the KEYTAG column of sql/mp indices. ItemExpr * keytag = new(wHeap()) NATypeToItem((NAType *)(allColumns[i]->getType())); keytag->synthTypeAndValueId(); baseValueId = keytag->getValueId(); baseItemExpr = NULL; } #pragma nowarn(1506) // warning elimination IndexColumn *ixcol = new(wHeap()) IndexColumn(fileSet_,i,baseValueId); #pragma warn(1506) // warning elimination ixcol->synthTypeAndValueId(); // add the newly obtained value id to the index column list indexColumns_.insert(ixcol->getValueId()); // if the index column is defined as a 1:1 copy of a base // column, add it as an equivalent index column (EIC) to the // base column item expression if ((baseItemExpr) && (baseItemExpr->getOperatorType() == ITM_BASECOLUMN)) ((BaseColumn *) baseItemExpr)->addEIC(ixcol->getValueId()); } // --------------------------------------------------------------------- // make the list of access key columns in the index and make a list // of the order that the index provides // --------------------------------------------------------------------- const NAColumnArray & indexKeyColumns = fileSet_->getIndexKeyColumns(); for (i = 0; i < indexKeyColumns.entries(); i++) { // which column of the index is this (usually this will be == i) #pragma nowarn(1506) // warning elimination if ( !naTable->isHbaseTable() ) ixColNumber = allColumns.index(indexKeyColumns[i]); else { // For Hbase tables, a new NAColumn is created for every column // in an index. The above pointer-based lookup for the key column // in base table will only find the index column itself. The // fix is to lookup by the column name and type as is // implemented by the getColumnPosition() method. ixColNumber = allColumns.getColumnPosition(*indexKeyColumns[i]); CMPASSERT(ixColNumber >= 0); } #pragma warn(1506) // warning elimination // insert the value id of the index column into the key column // value id list keyValueId = indexColumns_[ixColNumber]; indexKey_.insert(keyValueId); // insert the same value id into the order list, if the column // is in ascending order, otherwise insert the inverse of the // column if (indexKeyColumns.isAscending(i)) { orderOfKeyValues_.insert(keyValueId); } else { InverseOrder *invExpr = new(wHeap()) InverseOrder(keyValueId.getItemExpr()); invExpr->synthTypeAndValueId(); orderOfKeyValues_.insert(invExpr->getValueId()); } } markIdentityColumnUniqueIndex(tdesc); // --------------------------------------------------------------------- // Find the clustering key columns in the index and store their value // ids in clusteringKey_ // --------------------------------------------------------------------- NABoolean found = TRUE; const NAColumnArray & clustKeyColumns = naTable->getClusteringIndex()->getIndexKeyColumns(); for (i = 0; i < clustKeyColumns.entries() AND found; i++) { // which column of the index is this? #pragma nowarn(1506) // warning elimination ixColNumber = allColumns.index(clustKeyColumns[i]); #pragma warn(1506) // warning elimination found = (ixColNumber != NULL_COLL_INDEX); if (found) { // insert the value id of the index column into the clustering key // value id list keyValueId = indexColumns_[ixColNumber]; clusteringKey_.insert(keyValueId); } else { // clustering key isn't contained in this index, clear the // list that is supposed to indicate the clustering key clusteringKey_.clear(); } } // --------------------------------------------------------------------- // make the list of partitioning key columns in the index and make a list // of the order that the partitioning provides // --------------------------------------------------------------------- const NAColumnArray & partitioningKeyColumns = fileSet_->getPartitioningKeyColumns(); for (i = 0; i < partitioningKeyColumns.entries(); i++) { // which column of the index is this #pragma nowarn(1506) // warning elimination ixColNumber = allColumns.index(partitioningKeyColumns[i]); #pragma warn(1506) // warning elimination // insert the value id of the index column into the partitioningkey column // value id list keyValueId = indexColumns_[ixColNumber]; partitioningKey_.insert(keyValueId); // insert the same value id into the order list, if the column // is in ascending order, otherwise insert the inverse of the // column if (partitioningKeyColumns.isAscending(i)) { orderOfPartitioningKeyValues_.insert(keyValueId); } else { InverseOrder *invExpr = new(wHeap()) InverseOrder(keyValueId.getItemExpr()); invExpr->synthTypeAndValueId(); orderOfPartitioningKeyValues_.insert(invExpr->getValueId()); } } // --------------------------------------------------------------------- // If this index is partitioned, find the partitioning key columns // and build a partitioning function. // --------------------------------------------------------------------- if ((fileSet_->getCountOfFiles() > 1) || (fileSet_->getPartitioningFunction() && fileSet_->getPartitioningFunction()-> isARoundRobinPartitioningFunction())) partFunc_ = fileSet_->getPartitioningFunction()-> createPartitioningFunctionForIndexDesc(this); } // IndexDesc::IndexDesc()