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()); } }
// 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; }
// is any literal in this expr safely coercible to its target type? NABoolean ItemExpr::isSafelyCoercible(CacheWA &cwa) const { if (cwa.getPhase() >= CmpMain::BIND) { Int32 arity = getArity(); for (Int32 x = 0; x < arity; x++) { if (!child(x)->isSafelyCoercible(cwa)) { return FALSE; } } if (arity == 2) { // we have to disallow caching of the following types of exprs: // expr + 123456789012345678901234567890 // expr || 'overlylongstringthatwouldoverflow' ItemExpr *left = child(0), *right = child(1); if (left->getOperatorType() == ITM_CONSTANT) { if (right->getOperatorType() == ITM_CONSTANT) { // "10 + 1" should be safely coercible return TRUE; } else { return ((ConstValue*)left)->canBeSafelyCoercedTo (right->getValueId().getType()); } } else if (right->getOperatorType() == ITM_CONSTANT) { return ((ConstValue*)right)->canBeSafelyCoercedTo (left->getValueId().getType()); } // else both are nonliterals; fall thru } // else nondyadic expr; fall thru return TRUE; } return FALSE; }
ValueId NormWA::getEquivalentItmSequenceFunction(ValueId newSeqId) { ValueId equivId = newSeqId; ItemExpr *newItem = newSeqId.getItemExpr(); ItmSequenceFunction *newSeq = NULL; if(newItem->isASequenceFunction()) { newSeq = (ItmSequenceFunction *)newItem; } if(newSeq) { for(ValueId seqId = allSeqFunctions_.init(); allSeqFunctions_.next(seqId); allSeqFunctions_.advance(seqId) ){ ItemExpr *seq = seqId.getItemExpr(); if(newSeq->isEquivalentForBinding(seq)){ equivId = seqId; if(newSeq->origOpType() != seq->origOpType()) { seq->setOrigOpType(seq->getOperatorType()); } break; } } } allSeqFunctions_ += equivId; // return equivId; }
// change literals of a cacheable query into input parameters ItemExpr* ItemList::normalizeListForCache (CacheWA& cwa, BindWA& bindWA, ItemList *other) { Int32 arity = getArity(); if (cwa.getPhase() >= CmpMain::BIND && other && arity == other->getArity()) { for (Int32 x = 0; x < arity; x++) { ItemExpr *leftC = child(x), *rightC = other->child(x); OperatorTypeEnum leftO = leftC->getOperatorType(); OperatorTypeEnum rightO = rightC->getOperatorType(); if (leftO == ITM_BASECOLUMN && rightO == ITM_CONSTANT) { parameterizeMe(cwa, bindWA, other->child(x), (BaseColumn*)leftC, (ConstValue*)rightC); } else if (rightO == ITM_BASECOLUMN && leftO == ITM_CONSTANT) { parameterizeMe(cwa, bindWA, child(x), (BaseColumn*)rightC, (ConstValue*)leftC); } else if (leftO == ITM_ITEM_LIST && rightO == ITM_ITEM_LIST) { child(x) = ((ItemList*)leftC)->normalizeListForCache (cwa, bindWA, (ItemList*)rightC); } } } return this; }
// ----------------------------------------------------------------------- // Given a column list providing identifiers for columns of this table, // this method returns a list of VEG expressions and/or base columns that // show the equivalence of base columns with index columns. // ----------------------------------------------------------------------- void TableDesc::getEquivVEGCols (const ValueIdList& columnList, ValueIdList &VEGColumnList) const { for (CollIndex i=0; i < columnList.entries(); i++) { ItemExpr *ie = columnList[i].getItemExpr(); BaseColumn *bc = NULL; switch (ie->getOperatorType()) { case ITM_BASECOLUMN: bc = (BaseColumn *) ie; break; case ITM_INDEXCOLUMN: bc = (BaseColumn *) ((IndexColumn *) ie)->getDefinition(). getItemExpr(); CMPASSERT(bc->getOperatorType() == ITM_BASECOLUMN); break; default: ABORT("Invalid argument to TableDesc::getEquivVEGCols()\n"); } CMPASSERT(bc->getTableDesc() == this); VEGColumnList.insert(getColumnVEGList()[bc->getColNumber()]); } }
// 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); }
ValueIdSet TableDesc::getComputedColumns(NAColumnBooleanFuncPtrT fptr) { ValueIdSet computedColumns; for (CollIndex j=0; j<getClusteringIndex()->getIndexKey().entries(); j++) { ItemExpr *ck = getClusteringIndex()->getIndexKey()[j].getItemExpr(); if (ck->getOperatorType() == ITM_INDEXCOLUMN) ck = ((IndexColumn *) ck)->getDefinition().getItemExpr(); CMPASSERT(ck->getOperatorType() == ITM_BASECOLUMN); NAColumn* x = ((BaseColumn *) ck)->getNAColumn(); if (((*x).*fptr)()) computedColumns += ck->getValueId(); } return computedColumns; }
void HbaseSearchSpec::addColumnNames(const ValueIdSet& vs) { // TEMP TEMP. Not all needed column names are being set up. // for now, return without populating result. // that will cause all columns to be retrieved. //return; for (ValueId vid = vs.init(); vs.next(vid); vs.advance(vid)) { ItemExpr* ie = vid.getItemExpr(); NAString colName; if ( ie->getOperatorType() == ITM_BASECOLUMN ) { colName = ((BaseColumn*)ie)->getColName(); } else if ( ie->getOperatorType() == ITM_INDEXCOLUMN ) { colName = ((IndexColumn*)ie)->getNAColumn()->getIndexColName(); } if (NOT colNames_.contains(colName)) colNames_.insert(colName); } }
// is any literal in this expr safely coercible to its target type? NABoolean Cast::isSafelyCoercible(CacheWA &cwa) const { if (cwa.getPhase() >= CmpMain::BIND) { ItemExpr *opd = child(0); if (!opd->isSafelyCoercible(cwa)) { return FALSE; } if (opd->getOperatorType() == ITM_CONSTANT) { return ((ConstValue*)opd)->canBeSafelyCoercedTo(*type_); } return TRUE; } return FALSE; }
// is val a constant that can be safely coerced to BaseColumn's type? NABoolean BaseColumn::canSafelyCoerce(ItemExpr& val) const { NAColumn *baseCol = getNAColumn(); OperatorTypeEnum valTyp = val.getOperatorType(); return (baseCol != NULL && ((valTyp == ITM_CONSTANT && ((ConstValue*)&val)->canBeSafelyCoercedTo(*baseCol->getType())) // we don't need to check the types of param & hostvar here because we // are called after ItemExpr::bindNode has successfully type-checked // the current search predicate that is being tested for cacheability || valTyp == ITM_HOSTVAR || valTyp == ITM_DYN_PARAM || valTyp == ITM_CACHE_PARAM )); }
// does this query's selection predicate list qualify query // to be cacheable after this phase? NABoolean ItemList::isListOfCacheableSelPred (CacheWA& cwa, ItemList *other) const { Int32 arity = getArity(); NABoolean result = FALSE; if (cwa.getPhase() >= CmpMain::BIND && other && arity == other->getArity()) { // assume this is an AND list, so, we need only one // cacheable conjunct to consider the list cacheable. for (Int32 x = 0; x < arity; x++) { ItemExpr *leftC = child(x), *rightC = other->child(x); OperatorTypeEnum leftO = leftC->getOperatorType(); OperatorTypeEnum rightO = rightC->getOperatorType(); BaseColumn *base; if (leftO == ITM_BASECOLUMN) { base = (BaseColumn*)leftC; if (base->isKeyColumnValue(*rightC)) { cwa.addToUsedKeys(base); } result = TRUE; continue; } else if (rightO == ITM_BASECOLUMN) { base = (BaseColumn*)rightC; if (base->isKeyColumnValue(*leftC)) { cwa.addToUsedKeys(base); } result = TRUE; continue; } else if (leftO == ITM_ITEM_LIST && rightO == ITM_ITEM_LIST && ((ItemList*)leftC)->isListOfCacheableSelPred (cwa, (ItemList*)rightC)) { result = TRUE; continue; } } } return result; }
// is any literal in this expr safely coercible to its target type? NABoolean Assign::isSafelyCoercible(CacheWA &cwa) const { if (cwa.getPhase() >= CmpMain::BIND) { // we have to disallow caching of the following types of updates: // update t set col = overlylongliteral ItemExpr *src = getSource().getItemExpr(); if (src->getOperatorType() == ITM_CONSTANT) { // source is a literal; make sure this update is cacheable only if // literal can be safely coerced into its target type. return ((ConstValue*)src)->canBeSafelyCoercedTo(getTarget().getType()); } else { // source is not a literal // we need to descend into this expr to verify that no // errors can occur during backpatching. For example, // update t set i = i + 123456789012345678901234567890 // should not be cacheable if i is a smallint. // reject "update t set c=(subquery)" as noncacheable // as part of a fix to CR 10-020108-8401. return src->isSafelyCoercible(cwa) && src->isCacheableExpr(cwa); } } return FALSE; }
// 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; }
// 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; }
// 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; }
// compress the histograms based on query predicates on this table void TableDesc::compressHistogramsForCurrentQuery() { // if there are some column statistics if ((colStats_.entries() != 0) && (table_) && (table_->getExtendedQualName().getSpecialType() == ExtendedQualName::NORMAL_TABLE)) { // if 1 // check if query analysis info is available if(QueryAnalysis::Instance()->isAnalysisON()) { // if 2 // get a handle to the query analysis QueryAnalysis* queryAnalysis = QueryAnalysis::Instance(); // get a handle to the table analysis const TableAnalysis * tableAnalysis = getTableAnalysis(); if(!tableAnalysis) return; // iterate over statistics for each column for(CollIndex i = 0; i < colStats_.entries(); i++) { // for 1 // Get a handle to the column's statistics descriptor ColStatDescSharedPtr columnStatDesc = colStats_[i]; // get a handle to the ColStats ColStatsSharedPtr colStats = columnStatDesc->getColStats(); // if this is a single column, as opposed to a multicolumn if(colStats->getStatColumns().entries() == 1) { // if 3 // get column's value id const ValueId columnId = columnStatDesc->getColumn(); // get column analysis ColAnalysis* colAnalysis = queryAnalysis->getColAnalysis(columnId); if(!colAnalysis) continue; ValueIdSet predicatesOnColumn = colAnalysis->getReferencingPreds(); // we can compress this column's histogram if there // is a equality predicate against a constant ItemExpr *constant = NULL; NABoolean colHasEqualityAgainstConst = colAnalysis->getConstValue(constant); // if a equality predicate with a constant was found // i.e. predicate of the form col = 5 if (colHasEqualityAgainstConst) { // if 4 if (constant) // compress the histogram columnStatDesc->compressColStatsForQueryPreds(constant,constant); } // if 4 else { // else 4 // since there is no equality predicates we might still // be able to compress the column's histogram based on // range predicates against a constant. Following are // examples of such predicates // * col > 1 <-- predicate defines a lower bound // * col < 3 <-- predicate defines a upper bound // * col >1 and col < 30 <-- window predicate, define both bounds ItemExpr * lowerBound = NULL; ItemExpr * upperBound = NULL; // Extract predicates from range spec and add it to the // original predicate set otherwise isARangePredicate() will // return FALSE, so histgram compression won't happen. ValueIdSet rangeSpecPred(predicatesOnColumn); for (ValueId predId= rangeSpecPred.init(); rangeSpecPred.next(predId); rangeSpecPred.advance(predId)) { ItemExpr * pred = predId.getItemExpr(); if ( pred->getOperatorType() == ITM_RANGE_SPEC_FUNC ) { ValueIdSet vs; ((RangeSpecRef *)pred)->getValueIdSetForReconsItemExpr(vs); // remove rangespec vid from the original set predicatesOnColumn.remove(predId); // add preds extracted from rangespec to the original set predicatesOnColumn.insert(vs); } } // in the following loop we iterate over all the predicates // on this column. If there is a range predicate e.g. a > 2 // or a < 3, then we use that to define upper and lower bounds. // Given predicate a > 2, we get a lower bound of 2. // Given predicate a < 3, we get a upper bound of 3. // The bound are then passed down to the histogram // compression methods. // iterate over predicates to see if any of them is a range // predicate e.g. a > 2 for (ValueId predId= predicatesOnColumn.init(); predicatesOnColumn.next(predId); predicatesOnColumn.advance(predId)) { // for 2 // check if this predicate is a range predicate ItemExpr * predicateOnColumn = predId.getItemExpr(); if (predicateOnColumn->isARangePredicate()) { // if 5 // if a predicate is a range predicate we need to find out more // information regarding the predicate to see if it can be used // to compress the columns histogram. We look for the following: // * The predicate is against a constant e.g. a > 3 and not against // another column e.g. a > b // Also give a predicate we need to find out what side is the column // and what side is the constant. Normally people write a range predicate // as a > 3, but the same could be written as 3 < a. // Also either on of the operands of the range predicate might be // a VEG, if so then we need to dig into the VEG to see where is // the constant and where is the column. // check the right and left children of this predicate to // see if one of them is a constant ItemExpr * leftChildItemExpr = (ItemExpr *) predicateOnColumn->getChild(0); ItemExpr * rightChildItemExpr = (ItemExpr *) predicateOnColumn->getChild(1); // by default assume the literal is at right i.e. predicate of // the form a > 2 NABoolean columnAtRight = FALSE; // check if right child of predicate is a VEG if ( rightChildItemExpr->getOperatorType() == ITM_VEG_REFERENCE) { // if 6 // if child is a VEG VEGReference * rightChildVEG = (VEGReference *) rightChildItemExpr; // check if the VEG contains the current column // if it does contain the current column then // the predicate has the column on right and potentially // a constant on the left. if(rightChildVEG->getVEG()->getAllValues().contains(columnId)) { // if 7 // column is at right i.e. predicate is of the form // 2 < a columnAtRight = TRUE; } // if 7 } // if 6 else { // else 6 // child is not a VEG if ( columnId == rightChildItemExpr->getValueId() ) { // if 8 // literals are at left i.e. predicate is of the form // (1,2) < (a, b) columnAtRight = TRUE; } // if 8 } // else 6 ItemExpr * potentialConstantExpr = NULL; // check if the range predicate is against a constant if (columnAtRight) { // if 9 // the left child is potentially a constant potentialConstantExpr = leftChildItemExpr; } // if 9 else { // else 9 // the right child is potentially a constant potentialConstantExpr = rightChildItemExpr; } // else 9 // initialize constant to NULL before // looking for next constant constant = NULL; // check if potentialConstantExpr contains a constant. // we need to see if this range predicate is a predicate // against a constant e.g col > 1 and not a predicate // against another column e.g. col > anothercol // if the expression is a VEG if ( potentialConstantExpr->getOperatorType() == ITM_VEG_REFERENCE) { // if 10 // expression is a VEG, dig into the VEG to // get see if it contains a constant VEGReference * potentialConstantExprVEG = (VEGReference *) potentialConstantExpr; potentialConstantExprVEG->getVEG()->\ getAllValues().referencesAConstValue(&constant); } // if 10 else { // else 10 // express is not a VEG, it is a constant if ( potentialConstantExpr->getOperatorType() == ITM_CONSTANT ) constant = potentialConstantExpr; } // else 10 // if predicate involves a constant, does the constant imply // a upper bound or lower bound if (constant) { // if 11 // if range predicate has column at right e.g. 3 > a if (columnAtRight) { // if 12 if ( predicateOnColumn->getOperatorType() == ITM_GREATER || predicateOnColumn->getOperatorType() == ITM_GREATER_EQ) { // if 13 if (!upperBound) upperBound = constant; } // if 13 else { // else 13 if (!lowerBound) lowerBound = constant; } // else 13 } // if 12 else { // else 12 // range predicate has column at left e.g. a < 3 if ( predicateOnColumn->getOperatorType() == ITM_LESS || predicateOnColumn->getOperatorType() == ITM_LESS_EQ) { // if 14 if (!upperBound) upperBound = constant; } // if 14 else { // else 14 if (!lowerBound) lowerBound = constant; } // else 14 } // else 12 } // if 11 } // if 5 } // for 2 // if we found a upper bound or a lower bound if (lowerBound || upperBound) { // compress the histogram based on range predicates columnStatDesc->compressColStatsForQueryPreds(lowerBound, upperBound); } } // else 4 } // if 3 } // for 1 } // if 2 } // if 1 // All histograms compressed. Set the histCompressed flag to TRUE histsCompressed(TRUE); }
// 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
// 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"); } }
// 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
// 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; }
// ----------------------------------------------------------------------- // 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()
// 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); }
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)
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; }
//---------------------------------------------------------------------------- // 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()