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); }
// index access (both reference and value) ItemExpr * ItemExprTreeAsList::operator [] (CollIndex i) { // think of three different cases: // // a) i is out of range (< 0 or >= #entries) // // b) the node we are looking for is neither the only nor the last // node in the backbone // // c) we are looking for the last element in the backbone (which // may be the only element) // ItemExpr *aNodePtr = *treePtr_; Int32 j = (Int32) i; // j may become negative, i may be unsigned if (j < 0) return NULL; // case a if (aNodePtr->getOperatorType() != operator_ AND j == 0) return aNodePtr; // case b while (aNodePtr != NULL AND j >= 0) { if (aNodePtr->getOperatorType() == operator_ AND aNodePtr->getArity() >= 2) { if (shape_ == LEFT_LINEAR_TREE) { if (j == 0) aNodePtr = aNodePtr->child(1); // case b else aNodePtr = aNodePtr->child(0); } else if (shape_ == RIGHT_LINEAR_TREE) { if (j == 0) aNodePtr = aNodePtr->child(0); // case b else aNodePtr = aNodePtr->child(1); } else ABORT("can't do bushy trees"); } j--; } // if we are looking for the only element, the while loop // is not executed at all return aNodePtr; }
// return number of entries Lng32 ItemExprTreeAsList::entries() const { ItemExpr *aNode = *treePtr_; Lng32 result = 0; while (aNode != NULL) { result++; if (aNode->getOperatorType() == operator_ AND aNode->getArity() >= 2) { if (shape_ == LEFT_LINEAR_TREE) aNode = aNode->child(0); else if (shape_ == RIGHT_LINEAR_TREE) aNode = aNode->child(1); else ABORT("can't do other than right-linear trees"); } else aNode = NULL; } return result; }
// check whether an element is in the collection NABoolean ItemExprTreeAsList::contains(const ItemExpr *treeToCheck) { ItemExpr *aNodePtr = *treePtr_; while (aNodePtr != NULL) { if (aNodePtr == treeToCheck) return TRUE; if (aNodePtr->getOperatorType() == operator_ AND aNodePtr->getArity() >= 2) { if (shape_ == RIGHT_LINEAR_TREE) aNodePtr = aNodePtr->child(1); else ABORT("can't do other than right-linear trees"); } else aNodePtr = NULL; } return FALSE; }
short BiLogic::codeGen(Generator * generator) { Attributes ** attr; if (generator->getExpGenerator()->genItemExpr(this, &attr, (1+getArity()), 0) == 1) return 0; Space * space = generator->getSpace(); ExpGenerator * expGen = generator->getExpGenerator(); // Normally, if code for a value id has been generated, and if // that value id is seen again, then code is not generated. The // location where the result is available is returned instead. // The case of a logical operator is different. Code is generated // again if a value id from the left child is also present in // the right child. This is done // because at expression evaluation time, some of the expressions // may be skipped due to short circuit evaluation. // // Allocate a new map table before generating code for each child. // This map table contains all the temporary results produced by // the child. // Remove this map table after generating code for each child. generator->appendAtEnd(); expGen->incrementLevel(); codegen_and_set_attributes(generator, attr, 2); // generator->getExpGenerator()->setClauseLinked(FALSE); // child(0)->codeGen(generator); // attr[1] = generator->getAttr(child(0)); // generator->getExpGenerator()->setClauseLinked(FALSE); /* generate boolean short circuit code */ Attributes ** branch_attr = new(generator->wHeap()) Attributes * [2]; branch_attr[0] = attr[0]->newCopy(generator->wHeap()); branch_attr[0]->copyLocationAttrs(attr[0]); branch_attr[1] = attr[1]->newCopy(generator->wHeap()); branch_attr[1]->copyLocationAttrs(attr[1]); branch_attr[0]->resetShowplan(); ex_branch_clause * branch_clause = new(space) ex_branch_clause(getOperatorType(), branch_attr, space); generator->getExpGenerator()->linkClause(0, branch_clause); generator->removeLast(); expGen->decrementLevel(); generator->appendAtEnd(); expGen->incrementLevel(); ValueIdSet markedEntries; // This ia a MapTable entry related fix for RangeSpec transformation. if( child(1)->getOperatorType() == ITM_RANGE_SPEC_FUNC ) markGeneratedEntries(generator, child(1)->child(1), markedEntries); else markGeneratedEntries(generator, child(1), markedEntries); // if( child(1)->getOperatorType() == ITM_RANGE_SPEC_FUNC ) // child(1)->child(1)->codeGen(generator); // else child(1)->codeGen(generator); ItemExpr *rightMost; if( child(1)->getOperatorType() == ITM_RANGE_SPEC_FUNC ) rightMost = child(1)->child(1)->castToItemExpr(); else rightMost = child(1)->castToItemExpr(); while (rightMost->getOperatorType() == ITM_ITEM_LIST) rightMost = rightMost->child(1)->castToItemExpr(); attr[2] = generator-> getMapInfo(rightMost->getValueId())->getAttr(); ex_bool_clause * bool_clause = new(space) ex_bool_clause(getOperatorType(), attr, space); generator->getExpGenerator()->linkClause(this, bool_clause); branch_clause->set_branch_clause((ex_clause *)bool_clause); generator->removeLast(); expGen->decrementLevel(); if( child(1)->getOperatorType() == ITM_RANGE_SPEC_FUNC ) unGenerate(generator, child(1)->child(1)); else unGenerate(generator, child(1)); generateMarkedEntries(generator, markedEntries); return 0; }
// change literals of a cacheable query into ConstantParameters ItemExpr* UDFunction::normalizeForCache(CacheWA& cwa, BindWA& bindWA) { if (nodeIsNormalizedForCache()) { return this; } // Since the UDFunction::transformNode refers to both the // inputVars_ ValueIdSet and the children array we need to make sure // they are consistent. // The children array may contain cast() of the expressions in inputVars_ // If we have a UUDF function the inputs that were given // at parse time, really do not reflect reality anymore. // So here we will simply reinitialize them with what we find in the // inputVars_. CMPASSERT(udfDesc_); // we better have one after binding. NABoolean isUUDF(udfDesc_->isUUDFRoutine()); // Save off a copy of the original inputVars_ set. ValueIdSet origInputVars(inputVars_); // Loop through the given inputs for (Int32 x = 0; x < getArity(); x++) { NABoolean origInputIsChildOfCast(FALSE); ItemExpr * origIe = child(x); ItemExpr * newIe = NULL; ValueId vid = origIe->getValueId(); if (cwa.getPhase() == CmpMain::BIND) { if (origIe->isSafelyCoercible(cwa)) { // fix CR 10-010726-4109: make sure queries with constants that // cannot be safely backpatched such as // select case smallintcol when 4294967393 then 'max' end from t // are not parameterized newIe = origIe->normalizeForCache(cwa, bindWA); if (newIe != origIe ) { // normalizeForCache returned a new ItemExpr. We have to update // the UDFunction inputVars_ set, as this is used to determine // characteristic inputs for IsolatedScalarUDF at transform time. child(x) = newIe; // Is it a input that UDFunction::bindNode put a cast around? if ((origIe->getOperatorType() == ITM_CAST) && (origInputVars.contains(origIe->child(0)->getValueId()))) { // Since the original child was a CAST that UDFunction::bindNode // created, check to see if that CAST's child is part of the new // expression, if it is, we don't have to do anything, since the // CASTED value is part of the inputVars set, otherwise, we have // to update the inputVars set to keep the characteristic inputs // consistent. if (! newIe->referencesTheGivenValue( origIe->child(0)->getValueId()), TRUE) { // remove the original input from inputVars. It is the child // of origIe because origIe is a cast that UDFunction::bindNode // introduced. inputVars_ -= origIe->child(0)->getValueId(); if (newIe->getOperatorType() == ITM_CAST) { // If the new expression is a CAST, we assume the child is the // real input. We don't expect CAST(CAST(CAST(expr))) type // expressions only simple CAST(expr) ones. inputVars_ += newIe->child(0)->getValueId(); } else { // add the newIe itself if it was not a CAST. inputVars_ += newIe->getValueId(); } } } else { // If the newIe doesn't contain the original one, we need to update // the inputVars set. if (! newIe->referencesTheGivenValue( origIe->getValueId()), TRUE) { // the origIe was not a CAST introduced by UDFunction::bindNode() if (newIe->getOperatorType() == ITM_CAST) { if (!origInputVars.contains(newIe->child(0)->getValueId())) { inputVars_ -= origIe->getValueId(); // If the new expression is a CAST, we assume the child is the // real input. We don't expect CAST(CAST(CAST(expr))) type // expressions only simple CAST(expr) ones. inputVars_ += newIe->child(0)->getValueId(); } // we don't need to update inputVars_ if the origInputVars // contains the valueId of the newIe child already. } else { // This is an entirely new input. Remove the old one, and // add in the new. inputVars_ -= origIe->getValueId(); inputVars_ += newIe->getValueId(); } } } } } } } markAsNormalizedForCache(); return this; }
// 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
// computeHistoryBuffer // // Helper function that traverses the set of root sequence functions // supplied by the compiler and dynamically determines the size // of the history buffer. // void PhysSequence::computeHistoryRows(const ValueIdSet &sequenceFunctions,//historyIds Lng32 &computedHistoryRows, Lng32 &unableToCalculate, NABoolean &unboundedFollowing, Lng32 &minFollowingRows, const ValueIdSet &outputFromChild) { ValueIdSet children; ValueIdSet historyAttributes; Lng32 value = 0; for(ValueId valId = sequenceFunctions.init(); sequenceFunctions.next(valId); sequenceFunctions.advance(valId)) { if(valId.getItemExpr()->isASequenceFunction()) { ItemExpr *itmExpr = valId.getItemExpr(); switch(itmExpr->getOperatorType()) { // THIS and NOT THIS are not dynamically computed // case ITM_THIS: case ITM_NOT_THIS: break; // The RUNNING functions and LastNotNull all need to go back just one row. // case ITM_RUNNING_SUM: case ITM_RUNNING_COUNT: case ITM_RUNNING_MIN: case ITM_RUNNING_MAX: case ITM_RUNNING_CHANGE: case ITM_LAST_NOT_NULL: computedHistoryRows = MAXOF(computedHistoryRows, 2); break; ///set to unable to compute for now-- will change later to compte values from frameStart_ and frameEnd_ case ITM_OLAP_SUM: case ITM_OLAP_COUNT: case ITM_OLAP_MIN: case ITM_OLAP_MAX: case ITM_OLAP_RANK: case ITM_OLAP_DRANK: { if ( !outputFromChild.contains(itmExpr->getValueId())) { ItmSeqOlapFunction * olap = (ItmSeqOlapFunction*)itmExpr; if (olap->isFrameStartUnboundedPreceding()) //(olap->getframeStart() == - INT_MAX) { computedHistoryRows = MAXOF(computedHistoryRows, 2); } else { computedHistoryRows = MAXOF(computedHistoryRows, ABS(olap->getframeStart()) + 2); } if (!olap->isFrameEndUnboundedFollowing()) //(olap->getframeEnd() != INT_MAX) { computedHistoryRows = MAXOF(computedHistoryRows, ABS(olap->getframeEnd()) + 1); } if (olap->isFrameEndUnboundedFollowing()) //(olap->getframeEnd() == INT_MAX) { unboundedFollowing = TRUE; if (olap->getframeStart() > 0) { minFollowingRows = ((minFollowingRows > olap->getframeStart()) ? minFollowingRows : olap->getframeStart()); } } else if (olap->getframeEnd() > 0) { minFollowingRows = ((minFollowingRows > olap->getframeEnd()) ? minFollowingRows : olap->getframeEnd()); } } } break; // If 'rows since', we cannot determine how much history is needed. case ITM_ROWS_SINCE: unableToCalculate = 1; break; // The MOVING and OFFSET functions need to go back as far as the value // of their second child. // // The second argument can be: // Constant: for these, we can use the constant value to set the upper bound // for the history buffer. // ItmScalarMinMax(child0, child1) (with operType = ITM_SCALAR_MIN) // - if child0 or child1 is a constant, then we can use either one // to set the upper bound. case ITM_MOVING_MIN: case ITM_MOVING_MAX: case ITM_OFFSET: for(Lng32 i = 1; i < itmExpr->getArity(); i++) { if (itmExpr->child(i)->getOperatorType() != ITM_NOTCOVERED) { ItemExpr * exprPtr = itmExpr->child(i); NABoolean negate; ConstValue *cv = exprPtr->castToConstValue(negate); if (cv AND cv->canGetExactNumericValue()) { Lng32 scale; Int64 value64 = cv->getExactNumericValue(scale); if(scale == 0 && value64 >= 0 && value64 < INT_MAX) { value64 = (negate ? -value64 : value64); value = MAXOF((Lng32)value64, value); } } else { if (exprPtr->getOperatorType() == ITM_SCALAR_MIN) { for(Lng32 j = 0; j < exprPtr->getArity(); j++) { if (exprPtr->child(j)->getOperatorType() != ITM_NOTCOVERED) { ItemExpr * exprPtr1 = exprPtr->child(j); NABoolean negate1; ConstValue *cv1 = exprPtr1->castToConstValue(negate1); if (cv1 AND cv1->canGetExactNumericValue()) { Lng32 scale1; Int64 value64_1 = cv1->getExactNumericValue(scale1); if(scale1 == 0 && value64_1 >= 0 && value64_1 < INT_MAX) { value64_1 = (negate1 ? -value64_1 : value64_1); value = MAXOF((Lng32)value64_1, value); } } } } } } // end of inner else }// end of if }// end of for // Check if the value is greater than zero. // If it is, then save the value, but first // increment the returned ConstValue by one. // Otherwise, the offset or moving value was unable // to be calculated. if (value > 0) { value++; computedHistoryRows = MAXOF(computedHistoryRows, value); value = 0; } else unableToCalculate = 1; 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 (//valId.getItemExpr()->child(i)->getOperatorType() != ITM_NOTCOVERED //old stuff !outputFromChild.contains(valId.getItemExpr()->child(i)->getValueId())) { children += valId.getItemExpr()->child(i)->getValueId(); } } } if (NOT children.isEmpty()) { computeHistoryRows(children, computedHistoryRows, unableToCalculate, unboundedFollowing, minFollowingRows, outputFromChild); } } // PhysSequence::computeHistoryRows
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)
// remove an element that is given by its value ItemExpr * ItemExprTreeAsList::remove(ItemExpr *treeToRemove) { ItemExpr *andNodePtr = treePtr_->getPtr(); ItemExpr *predecessor = NULL; NABoolean found = FALSE; // assume the predicate is represented in right-linear // form: // // op // / \ // A op // / \ // B ... // // and search for the <op> node that is directly above the // predicate that we want to remove. if (shape_ != RIGHT_LINEAR_TREE) ABORT("delete is supported for right linear trees only"); // is the node to delete the only node? if (treeToRemove == andNodePtr) { found = TRUE; delete andNodePtr; *treePtr_ = NULL; } else // traverse the backbone looking for "treeToRemove" while (andNodePtr != NULL AND andNodePtr->getOperatorType() == operator_ AND andNodePtr->getArity() == 2 AND NOT found) { // did we find the right node? if (andNodePtr->child(0).getPtr() == treeToRemove) { found = TRUE; // take "andNode" out of the original tree if (predecessor != NULL) { predecessor->child(1) = andNodePtr->child(1); } else *treePtr_ = andNodePtr->child(1); // set all children of "andNode" to NULL, then delete it andNodePtr->child(0) = NULL; andNodePtr->child(1) = NULL; delete andNodePtr; andNodePtr = NULL; } else { predecessor = andNodePtr; andNodePtr = andNodePtr->child(1); } } if (found) return treeToRemove; else return NULL; }
// insert a new entry. // The new entry is created at the end of the current tree. void ItemExprTreeAsList::insert(ItemExpr *treeToInsert) { if (treePtr_->getPtr() == NULL) { *treePtr_ = treeToInsert; } else { if (shape_ == RIGHT_LINEAR_TREE) { switch (operator_) { case ITM_AND: *treePtr_ = new(CmpCommon::statementHeap()) BiLogic(operator_, treeToInsert, treePtr_->getPtr()); break; case ITM_ITEM_LIST: { ItemExpr *aNode = treePtr_->getPtr(); ItemExpr *pNode = treePtr_->getPtr(); if (aNode->getOperatorType() != operator_ AND aNode->getArity() < 2) { // case of current number of entries equal to 1. *treePtr_ = new(CmpCommon::statementHeap()) ItemList(treePtr_->getPtr(), treeToInsert); } else { // current number of entries > 1 while (aNode != NULL) { if (aNode->getOperatorType() == operator_ AND aNode->getArity() >= 2) { if (shape_ == RIGHT_LINEAR_TREE) { pNode = aNode; aNode = aNode->child(1); } else ABORT("can't do other than right-linear trees"); } else aNode = NULL; } pNode->child(1) = new(CmpCommon::statementHeap()) ItemList(pNode->child(1), treeToInsert); } } break; default: ABORT("Can't do backbones with this node type"); } } else ABORT("can only insert into right-linear trees"); } }
//---------------------------------------------------------------------------- // Transform each aggregate in the MAV select list, to use the @OP column in // order to calculate deleted rows correctly: // COUNT(*) => SUM(@OP) // COUNT(a) => SUM(IF (a IS NULL) THEN 0 ELSE @OP) // SUM(a) => SUM(a * @OP) // MIN(a) & MAX(a) => Special treatment (see handleDeltaMinMaxColumns()). // AVG, STDDEV and VARIANCE are derived from other COUNT and SUM columns. // They are removed from this select list to avoid divide by zero problems // in case COUNT=0. void MavRelRootBuilder::fixDeltaColumns(RelExpr *mvSelectTree, NABoolean canSkipMinMax, NABoolean wasFullDE) { // Get the MAV select list from the mvSelectTree. CMPASSERT(mvSelectTree->getOperatorType() == REL_ROOT); RelRoot *mavSelectRoot = (RelRoot *)mvSelectTree; ItemExprList mavSelectList(mavSelectRoot->removeCompExprTree(), heap_); ItemExprList newSelectList(heap_); const NAString& opName = MavBuilder::getVirtualOpColumnName(); for (CollIndex i=0; i<mavSelectList.entries(); i++) { ItemExpr *selectListExpr = mavSelectList[i]; CMPASSERT(selectListExpr->getOperatorType() == ITM_RENAME_COL); const NAString& colName = ((RenameCol*)selectListExpr)->getNewColRefName()->getColName(); ItemExpr *aggregateExpr = selectListExpr; while ((aggregateExpr->getOperatorType() == ITM_RENAME_COL) || (aggregateExpr->getOperatorType() == ITM_CAST)) aggregateExpr = aggregateExpr->child(0); // Assuming all aggregates are top-most functions as explained in the // MV external spec. ItemExpr *aggregateOperand = aggregateExpr->child(0); ItemExpr *newExpr = NULL; if (!aggregateExpr->containsAnAggregate()) { // Non-aggregate columns (group-by cols) are added unchanged. } else switch (aggregateExpr->getOperatorType()) { case ITM_COUNT_NONULL: // COUNT(a) => SUM(IF (a IS NULL) THEN 0 ELSE @OP) newExpr = new(heap_) Aggregate(ITM_SUM, new(heap_) Case(NULL, new(heap_) IfThenElse (new(heap_) UnLogic(ITM_IS_NULL, aggregateOperand), new(heap_) SystemLiteral(0), new(heap_) ColReference(new(heap_) ColRefName(opName))))); selectListExpr->child(0) = newExpr; break; case ITM_COUNT: // COUNT(*) => SUM(@OP) newExpr = new(heap_) Aggregate(ITM_SUM, new(heap_) ColReference(new(heap_) ColRefName(opName))); selectListExpr->child(0) = newExpr; break; case ITM_SUM: // SUM(a) => SUM(a * @OP) newExpr = new(heap_) BiArith(ITM_TIMES, aggregateOperand, new(heap_) ColReference(new(heap_) ColRefName(opName))); aggregateExpr->child(0) = newExpr; break; case ITM_MIN: case ITM_MAX: // Handle Min/Max if not all deltas are INSERT ONLY. if (!canSkipMinMax) handleDeltaMinMaxColumns(aggregateExpr, colName, newSelectList, wasFullDE); // Add the SYS_DELTA Min/Max aggregate as is. break; case ITM_AVG: case ITM_DIVIDE: case ITM_VARIANCE: case ITM_STDDEV: // Remove these expressions from the select list. selectListExpr = NULL; break; default: // A new type of aggregate? CMPASSERT(FALSE); break; } if (selectListExpr!=NULL) newSelectList.insert(selectListExpr); } ItemExpr *selList = newSelectList.convertToItemExpr(); mavSelectRoot->addCompExprTree(selList); mavSelectList.clear(); // Don't delete all the entries from the Dtor. } // MavRelRootBuilder::fixDeltaColumns()