blob: 89b2fcaff28405866e676f660310393343115a1b [file] [log] [blame]
/**********************************************************************
//
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
**********************************************************************/
/* -*-C++-*-
**************************************************************************
*
* File: RelRoutine.cpp
* Description: RelExprs related to support for Routines and UDFs
* Old RelRoutine class got renamed to RelRoutine
* class resturcturing effort to support UDFs.
* Created: 6/29/09
* Language: C++
*
*************************************************************************
*/
#define SQLPARSERGLOBALS_FLAGS // must precede all #include's
#define SQLPARSERGLOBALS_NADEFAULTS
#include "Debug.h"
#include "Sqlcomp.h"
#include "AllRelExpr.h"
#include "GroupAttr.h"
#include "opt.h"
#include "PhyProp.h"
#include "mdam.h"
#include "ControlDB.h"
#include "disjuncts.h"
#include "ScanOptimizer.h"
#include "CmpContext.h"
#include "StmtDDLCreateTrigger.h"
#include "ExpError.h"
#include "ComTransInfo.h"
#include "BindWA.h"
#include "Refresh.h"
#include "CmpMain.h"
#include "ControlDB.h"
#include "ElemDDLColDef.h"
#include "Analyzer.h"
#include "OptHints.h"
#include "ComTdbSendTop.h"
#include "DatetimeType.h"
#include "ItemNAType.h"
#include "SequenceGeneratorAttributes.h"
#include "SqlParserGlobals.h"
#include "RelRoutine.h"
#include "ElemDDLColDefArray.h"
#include "CmpSeabaseDDL.h"
#include "UdfDllInteraction.h"
#include "TrafDDLdesc.h"
// -----------------------------------------------------------------------
// methods for class RelRoutine
// -----------------------------------------------------------------------
//! RelRoutine::RelRoutine Copy Constructor
RelRoutine::RelRoutine(const RelRoutine & other, CollHeap *h )
: RelExpr(other.getOperatorType(), NULL, NULL, h)
{
setSelectionPredicates(other.getSelectionPred());
procAllParamsTree_ = other.procAllParamsTree_;
procAllParamsVids_ = other.procAllParamsVids_;
procInputParamsVids_ = other.procInputParamsVids_;
procOutputParamsVids_ = other.procOutputParamsVids_;
routineName_ = other.routineName_;
// Just make a deep copy of the Routine Desc
if (other.routined_ != NULL)
routined_ = new (h) RoutineDesc(*other.routined_, h);
else
routined_ = NULL;
hasSubquery_ = other.hasSubquery_;
}
//! RelRoutine::~RelRoutine Destructor
RelRoutine::~RelRoutine()
{
// do not deallocate routine_ - shallow copy
}
//! RelRoutine::getPotentialOutputValues method
// gets the output values for the Routine from the RoutineDesc
void RelRoutine::getPotentialOutputValues(
ValueIdSet & outputValues) const
{
outputValues.clear();
//
// The attached Routine descriptor has a list of all the columns
// that this node can possibly generate.
//
RoutineDesc *rDesc = getRoutineDesc();
if (rDesc != NULL)
outputValues.insertList( getRoutineDesc()->getOutputColumnList() );
} // RelRoutine::getPotentialOutputValues()
//! RelRoutine::topHash method
HashValue RelRoutine::topHash()
{
HashValue result = RelExpr::topHash();
result ^= arity_;
result ^= procAllParamsVids_;
result ^= routineName_.getQualifiedNameAsAnsiString();
return result;
}
//! RelRoutine::duplicateMatch method
NABoolean RelRoutine::duplicateMatch(const RelExpr & other) const
{
if (!RelExpr::duplicateMatch(other))
return FALSE;
RelRoutine &o = (RelRoutine &) other;
if (NOT (procAllParamsVids_ == o.procAllParamsVids_))
return FALSE;
if (NOT (routineName_ == o.routineName_))
return FALSE;
if (NOT (arity_ == o.arity_))
return FALSE;
return TRUE;
}
//! RelRoutine::copyTopNode method
RelExpr * RelRoutine::copyTopNode(RelExpr *derivedNode, CollHeap* outHeap)
{
RelRoutine *result;
if (derivedNode == NULL)
result = new (outHeap) RelRoutine(NULL,
REL_ROUTINE,
outHeap);
else
result = (RelRoutine *) derivedNode;
result->hasSubquery_ = hasSubquery_;
result->routineName_ = routineName_;
result->procAllParamsVids_ = procAllParamsVids_;
result->procInputParamsVids_ = procInputParamsVids_;
result->procOutputParamsVids_ = procOutputParamsVids_;
result->arity_ = arity_;
// Make a deep copy unless we have been transformed. Once we have
// ValueIds for all the parameters, we don't need the tree.
if (nodeIsTransformed())
{
result->procAllParamsTree_ = NULL;
}
else
{
// Since we are not transformed, we know that we will not have any
// VEGReferences in the tree and it is safe to copy it, otherwise
// we would assert since VEGReferences do not have a copyTopNode()
// method..
if (procAllParamsTree_ != NULL)
result->procAllParamsTree_ = procAllParamsTree_->
copyTree(outHeap)->castToItemExpr();
}
// Copy routine descriptor, by creating another instance
if (routined_ != NULL)
{
result->routined_ = new (outHeap) RoutineDesc(*routined_, outHeap);
}
else
{
result->routined_ = NULL;
}
// we make sure we copy the rest of the class structure by calling the
// parent class copyTopNode()
return RelExpr::copyTopNode(result, outHeap);
}
//! RelRoutine::addLocalExpr method
void RelRoutine::addLocalExpr(LIST(ExprNode *) &xlist,
LIST(NAString) &llist) const
{
if (procAllParamsTree_ != NULL OR
NOT procAllParamsVids_.isEmpty())
{
if(procAllParamsVids_.isEmpty())
xlist.insert(procAllParamsTree_);
else
xlist.insert(procAllParamsVids_.rebuildExprTree());
llist.insert("actual_parameters");
}
RelExpr::addLocalExpr(xlist,llist);
}
//! RelRoutine::getText method
const NAString RelRoutine::getText() const
{
return "relroutine";
}
// -----------------------------------------------------------------------
// methods for class TableValuedFunction
// -----------------------------------------------------------------------
//! TableValuedFunction::~TableValuedFunction Destructor
TableValuedFunction::~TableValuedFunction()
{
}
//! TableValuedFunction::getPotentialOutputValues method
void TableValuedFunction::getPotentialOutputValues(
ValueIdSet & outputValues) const
{
outputValues.clear();
//
// The attached table descriptor has a list of all the columns
// that this node can possibly generate.
//
outputValues.insertList( getTableDesc()->getColumnList() );
} // TableValuedFunction::getPotentialOutputValues()
//! TableValuedFunction::duplicateMatch method
NABoolean TableValuedFunction::duplicateMatch(const RelExpr & other) const
{
if (! RelRoutine::duplicateMatch(other))
return FALSE;
TableValuedFunction &o = (TableValuedFunction &) other;
if (tabId_ == o.tabId_)
{
return TRUE;
}
return FALSE;
}
//! TableValuedFunction::copyTopNode method
RelExpr * TableValuedFunction::copyTopNode(RelExpr *derivedNode,
CollHeap* outHeap)
{
TableValuedFunction *result;
if (derivedNode == NULL)
{
result = new (outHeap) TableValuedFunction(NULL,
getOperatorType(),
outHeap);
}
else
result = (TableValuedFunction *) derivedNode;
// Make a shallow copy of the table decriptor. This works the same was
// as what we do for a Scan node.
result->tabId_ = tabId_;
result->userTableName_ = userTableName_ ;
return RelRoutine::copyTopNode(result, outHeap);
}
//! TableValuedFunction::getText method
const NAString TableValuedFunction::getText() const
{
return "TableValuedFunction";
}
// -----------------------------------------------------------------------
// methods for class TableMappingUDFChildInfo
// -----------------------------------------------------------------------
TableMappingUDFChildInfo::TableMappingUDFChildInfo
(const TableMappingUDFChildInfo &other)
{
inputTabName_ = other.inputTabName_;
inputTabCols_ = other.inputTabCols_;
partType_ = other.partType_;
partitionBy_ = other.partitionBy_;
orderBy_ = other.orderBy_;
outputs_ = other.outputs_;
}
void TableMappingUDFChildInfo::removeColumn(CollIndex i)
{
CMPASSERT(!partitionBy_.contains(outputs_[i]));
CMPASSERT(!orderBy_.contains(outputs_[i]));
inputTabCols_.removeAt(i);
outputs_.removeAt(i);
}
// -----------------------------------------------------------------------
// methods for class TableMappingUDF
// -----------------------------------------------------------------------
//! TableMappingUDF::TableMappingUDF Copy Constructor
TableMappingUDF::TableMappingUDF(const TableMappingUDF & other)
: TableValuedFunction(other),childInfo_(STMTHEAP)
{
selectivityFactor_ = other.selectivityFactor_;
cardinalityHint_ = other.cardinalityHint_;
for(CollIndex i = 0; i < other.childInfo_.entries(); i++)
{
childInfo_.insert(other.childInfo_[i]); // shallow copy, since copt ctor
}// called during nextSubstitue
scalarInputParams_ = other.scalarInputParams_;
outputParams_ = other.outputParams_;
dllInteraction_ = other.dllInteraction_ ;
invocationInfo_ = other.invocationInfo_;
routineHandle_ = other.routineHandle_;
constParamBuffer_ = other.constParamBuffer_; // shallow copy is ok
constParamBufferLen_ = other.constParamBufferLen_;
udfOutputToChildInputMap_ = other.udfOutputToChildInputMap_;
isNormalized_ = other.isNormalized_;
}
//! TableMappingUDF::~TableMappingUDF Destructor
TableMappingUDF::~TableMappingUDF()
{
// delete [] childInfo_ ;
}
//! TableMappingUDF::copyTopNode method
RelExpr * TableMappingUDF::copyTopNode(RelExpr *derivedNode,
CollHeap* outHeap)
{
TableMappingUDF *result;
if (derivedNode == NULL)
{
result = new (outHeap) TableMappingUDF(getArity(),
NULL,
outHeap);
}
else
result = (TableMappingUDF *) derivedNode;
for(CollIndex i = 0; i < childInfo_.entries(); i++)
{
TableMappingUDFChildInfo * ci = new (outHeap)
TableMappingUDFChildInfo(*(childInfo_[i]));
result->childInfo_.insert(ci);
}
result->selectivityFactor_ = selectivityFactor_;
result->cardinalityHint_ = cardinalityHint_;
result->scalarInputParams_ = scalarInputParams_;
result->outputParams_ = outputParams_;
result->dllInteraction_ = dllInteraction_;
result->invocationInfo_ = invocationInfo_; // shallow copies for these
result->routineHandle_ = routineHandle_; // items are ok, they are
result->constParamBuffer_ = constParamBuffer_; // shared for this invocation
result->constParamBufferLen_ = constParamBufferLen_;
result->predsEvaluatedByUDF_ = predsEvaluatedByUDF_;
result->udfOutputToChildInputMap_ = udfOutputToChildInputMap_;
result->isNormalized_ = isNormalized_;
return TableValuedFunction::copyTopNode(result, outHeap);
}
TableMappingUDF *TableMappingUDF::castToTableMappingUDF()
{
return this;
}
//! TableMappingUDF::getText method
const NAString TableMappingUDF::getText() const
{
NAString op(CmpCommon::statementHeap());
op = "tmudf ";
return op + getUserTableName().getTextWithSpecialType();
}
PredefinedTableMappingFunction * TableMappingUDF::castToPredefinedTableMappingFunction()
{
return NULL;
}
void TableMappingUDF::addLocalExpr(LIST(ExprNode *) &xlist,
LIST(NAString) &llist) const
{
if (!predsEvaluatedByUDF_.isEmpty())
{
xlist.insert(predsEvaluatedByUDF_.rebuildExprTree());
llist.insert("preds_evaluated_by_udf");
}
for(CollIndex i = 0; i < childInfo_.entries(); i++)
{
if (NOT childInfo_[i]->partitionBy_.isEmpty())
{
xlist.insert(childInfo_[i]->partitionBy_.rebuildExprTree());
llist.insert("child_part_by");
}
if (NOT childInfo_[i]->orderBy_.isEmpty())
{
xlist.insert(childInfo_[i]->orderBy_.rebuildExprTree());
llist.insert("child_order_by");
}
if (NOT childInfo_[i]->outputs_.isEmpty())
{
xlist.insert(childInfo_[i]->outputs_.rebuildExprTree());
llist.insert("child_outputs");
}
}
RelRoutine::addLocalExpr(xlist,llist);
}
void TableMappingUDF::transformNode(NormWA & normWARef,
ExprGroupId & locationOfPointerToMe)
{
RelExpr::transformNode(normWARef, locationOfPointerToMe);
}
void TableMappingUDF::rewriteNode(NormWA & normWARef)
{
for(Int32 i = 0; i < getArity(); i++)
{
childInfo_[i]->partitionBy_.normalizeNode(normWARef);
childInfo_[i]->orderBy_.normalizeNode(normWARef);
childInfo_[i]->outputs_.normalizeNode(normWARef);
}
udfOutputToChildInputMap_.normalizeNode(normWARef);
// rewrite group attributes and selection pred
RelExpr::rewriteNode(normWARef);
}
void TableMappingUDF::primeGroupAnalysis()
{
RelExpr::primeGroupAnalysis();
};
void TableMappingUDF::getPotentialOutputValues(ValueIdSet & vs) const
{
vs.clear();
vs.insertList(getProcOutputParamsVids());
};
void TableMappingUDF::getPotentialOutputValuesAsVEGs(ValueIdSet& outputs) const
{
CMPASSERT(0);
};
void TableMappingUDF::pullUpPreds()
{
// A TMUDF never pulls up predicates from its children.
for (Int32 i = 0; i < getArity(); i++)
child(i)->recomputeOuterReferences();
};
void TableMappingUDF::recomputeOuterReferences()
{
// ---------------------------------------------------------------------
// Delete all those input values that are no longer referenced on
// this operator because the predicates that reference them have
// been pulled up.
// ---------------------------------------------------------------------
ValueIdSet outerRefs = getGroupAttr()->getCharacteristicInputs();
// Remove from outerRefs those valueIds that are not needed
// by my selection predicate
GroupAttributes emptyGA;
ValueIdSet leafExprSet, emptySet;
ValueIdSet exprSet(getProcInputParamsVids());
exprSet.getLeafValuesForCoverTest(leafExprSet, emptyGA, emptySet);
leafExprSet += getSelectionPred();
// Also add any values mentioned in the select list, order by or
// partition by of the child queries. Those may contain expressions
// that are not stored anywhere else and may not be evaluated in the
// child. For example, if the child query is "select a, current_date..."
// then the child may only produce a, but not current_date.
for (CollIndex c=0; c<getArity(); c++)
{
leafExprSet += childInfo_[c]->getPartitionBy();
leafExprSet.insertList(childInfo_[c]->getOrderBy());
leafExprSet.insertList(childInfo_[c]->getOutputs());
}
leafExprSet.weedOutUnreferenced(outerRefs);
// Add to outerRefs those that my children need.
Int32 arity = getArity();
for (Int32 i = 0; i < arity; i++)
{
outerRefs += child(i).getPtr()->getGroupAttr()->getCharacteristicInputs();
}
// set my Character Inputs to this new minimal set.
getGroupAttr()->setCharacteristicInputs(outerRefs);
};
void TableMappingUDF::pushdownCoveredExpr(
const ValueIdSet & outputExprOnOperator,
const ValueIdSet & newExternalInputs,
ValueIdSet& predOnOperator,
const ValueIdSet *nonPredNonOutputExprOnOperator,
Lng32 childId)
{
if (!isNormalized_)
{
ValueIdSet exprOnParent;
ValueIdSet predsToPushDown;
// At this point, we have determined the characteristic outputs
// of the TableMappingUDF and a set of selection predicates to
// be evaluated on the result of the UDF.
// Call the UDF code to determine which child outputs we should
// require as child characteristic outputs and what to do with the
// selection predicates
// The logic below only works if we push preds to all children
// at the same time.
CMPASSERT(childId == -MAX_REL_ARITY);
// interact with the UDF
NABoolean status = dllInteraction_->describeDataflow(
this,
exprOnParent,
selectionPred(),
predsEvaluatedByUDF_,
predsToPushDown);
// no good way to return failure, error will be detected
// at the end of the normalization phase
// rewrite the predicates to be pushed down in terms
// of the values produced by the table-valued inputs
ValueIdSet childPredsToPushDown;
udfOutputToChildInputMap_.rewriteValueIdSetDown(
predsToPushDown, childPredsToPushDown);
// remaining selection predicates stay with the parent
exprOnParent += selectionPred();
if(nonPredNonOutputExprOnOperator)
exprOnParent += *nonPredNonOutputExprOnOperator;
RelExpr::pushdownCoveredExpr(outputExprOnOperator,
newExternalInputs,
childPredsToPushDown,
&exprOnParent,
childId);
// apply any leftover predicates back to the parent, but need
// to rewrite them in terms of the parent first
if (!childPredsToPushDown.isEmpty())
{
predsToPushDown.clear();
// Map the leftovers back to the language of out outputs.
// Note that since we rewrote these values on the way down,
// a simple mapping will suffice when going back up, as they
// are recorded already in the map table.
udfOutputToChildInputMap_.mapValueIdSetUp(predsToPushDown,
childPredsToPushDown);
selectionPred() += predsToPushDown;
}
// indicate that we did this step and recorded needed columns
// and pushed predicate in the InvocationInfo, don't change this
// information from now on (unless recording such changes in
// UDRPlanInfo)
isNormalized_ = TRUE;
}
// else
// If this is past the normalizer UDF interface call,
// pushdownCoveredExpr() has already been called in the
// normalizer. We cannot push down predicates and/or eliminate
// columns in this phase, because the UDR has already been told
// which columns and predicates we need. Also, this situation could
// apply only to one plan alternative and the UDRInvocationInfo
// object that records the predicates and columns is shared among
// all the alternatives. If we want to do such pushdown in the
// future (and this would be very desirable, something like a
// "routine join"), then we'll have to record the pushed down
// predicates and eliminated columns in the UDRPlanInfo object and
// we'll have to add another compiler interface method for the UDR
// writer.
};
void TableMappingUDF::synthLogProp(NormWA * normWAPtr)
{
// avoid multiple calls
if (getGroupAttr()->existsLogExprForSynthesis())
return;
RelExpr::synthLogProp(normWAPtr);
// +1 on the TMUDFs
getGroupAttr()->setNumTMUDFs(getGroupAttr()->getNumTMUDFs()+1);
NABoolean status = dllInteraction_->describeConstraints(this);
// rely on diags area to communicate failure
};
void TableMappingUDF::finishSynthEstLogProp()
{
RelExpr::finishSynthEstLogProp();
};
void TableMappingUDF::synthEstLogProp(const EstLogPropSharedPtr& inputEstLogProp)
{
if (getGroupAttr()->isPropSynthesized(inputEstLogProp)) return;
CostScalar inputFromParentCard = inputEstLogProp->getResultCardinality();
// create an empty result
EstLogPropSharedPtr myEstProps(new (HISTHEAP) EstLogProp(*inputEstLogProp));
// call the compiler UDF interaction, this may produce row counts and UECs
// for the output columns of the UDF, if specified by the UDF writer
NABoolean status = dllInteraction_->describeStatistics(this, inputEstLogProp);
CostScalar udfCard = dllInteraction_->getResultCardinality(this);
NABoolean udfSpecifiedCard = (udfCard >= 0);
int arity = getArity();
// Set tmUdf output cardinality, unless specified by UDF writer
if (!udfSpecifiedCard)
{
// 1. no children: children histograms will have cardinality of 1
if(arity < 1)
{
// CQD is used for default cardinality of a leaf TMUDF
udfCard =
ActiveSchemaDB()->getDefaults().getAsDouble(TMUDF_LEAF_CARDINALITY);
}
else
{
// use information about the function type (e.g. mapper, reducer) to
// estimate the row count
CostScalar udfCardFactor =
dllInteraction_->getCardinalityScaleFactorFromFunctionType(this);
// if the function type does not help, use a CQD
if (udfCardFactor < 0)
udfCardFactor =
ActiveSchemaDB()->getDefaults().getAsDouble(TMUDF_CARDINALITY_FACTOR);
// base the result cardinality of the child with the highest cardinality
for (CollIndex c=0; c<getArity(); c++)
{
EstLogPropSharedPtr childrenInputEstLogProp = child(c).outputLogProp(inputEstLogProp);
CostScalar childCard = child(c).outputLogProp(inputEstLogProp)->getResultCardinality();
myEstProps->unresolvedPreds() += childrenInputEstLogProp->getUnresolvedPreds();
if (childCard > udfCard)
udfCard = childCard;
}
udfCard = udfCard * udfCardFactor;
}
}
myEstProps->setResultCardinality(udfCard);
// use child(ren) histograms to figure out output column uecs
ValueIdList &tmudfOutputs = getProcOutputParamsVids();
ColStatDescList udfColStatDescList(CmpCommon::statementHeap());
for(CollIndex c=0; c<tmudfOutputs.entries(); c++)
{
ValueId udfOutputCol = tmudfOutputs[c];
NABoolean inputHistFound = FALSE;
ValueId inputValId;
ColStatsSharedPtr inputColStats;
// initialize the uec with the value specified by the UDF, or -1
CostScalar colUec = dllInteraction_->getOutputColumnUEC(this, c);
if (arity > 0)
{
udfOutputToChildInputMap_.mapValueIdDown(udfOutputCol, inputValId);
if(inputValId == udfOutputCol)
// udfOutputCol is not passed through from a child
inputValId = NULL_VALUE_ID;
if(inputValId != NULL_VALUE_ID)
{
for (CollIndex c=0; c<arity && !inputHistFound; c++)
{
// try to get child histogram from this child
inputColStats =
child(c).outputLogProp(inputEstLogProp)->
getColStats().getColStatsPtrForColumn(inputValId);
if(inputColStats != NULL)
inputHistFound = TRUE;
}
}
}
if(!inputHistFound)
{
// if the UDF didn't specify a UEC and we have no histogram, use a CQD
if (colUec < 1)
colUec = udfCard.getValue() *
ActiveSchemaDB()->getDefaults().getAsDouble(USTAT_MODIFY_DEFAULT_UEC);
// create a fake histogram with the specified cardinality and UEC
udfColStatDescList.addColStatDescForVirtualCol(colUec,
udfCard,
udfOutputCol,
udfOutputCol,
udfOutputCol,
NULL,
TRUE);
}
else
{
ColStatDescSharedPtr outputColStatDescSharedPtr(
new(HISTHEAP) ColStatDesc(inputColStats,udfOutputCol, HISTHEAP),HISTHEAP);
if (colUec >= 1)
{
// We have information from two sources: The UDF specified a column UEC
// and we also have a histogram from the corresponding child column.
// Try to consolidate these two pieces of information by scaling the
// UECs in the histogram to match those specified by the UDF.
outputColStatDescSharedPtr->getColStats()->setRowsAndUec(udfCard, colUec);
}
udfColStatDescList.insert(outputColStatDescSharedPtr);
}
}
const ValueIdSet & inputValues = getGroupAttr()->getCharacteristicInputs();
ValueIdSet outerReferences;
CollIndex outerRefCount;
ValueIdSet predsEvaluatedForStats(getSelectionPred());
if (inputValues.entries() > 0)
inputValues.getOuterReferences(outerReferences);
outerRefCount = outerReferences.entries();
if (!udfSpecifiedCard)
// The UDF writer did not specify a cardinality, use our conventional
// methods to estimate the effect of predicates evaluated in the
// UDF. Note that if the UDF did specify a result cardinality, we
// assume that it is the cardinality after evaluating those predicates.
predsEvaluatedForStats += predsEvaluatedByUDF_;
// synchronize output colum rowcounts
udfColStatDescList.synchronizeStats(udfCard,udfColStatDescList.entries());
// apply predicates
udfCard = udfColStatDescList.estimateCardinality(
udfCard, /*in*/
predsEvaluatedForStats, /*in*/
outerReferences, /*in*/
NULL, /* no join */
NULL, /* for selectivity hint, which can only be given for scan */
NULL, /* for cardinality hint, which can only be given for scan */
outerRefCount, /*in/out*/
myEstProps->unresolvedPreds(), /*in/out*/
INNER_JOIN_MERGE, /*in*/
ITM_FIRST_ITEM_OP, /*no-op*/
NULL); /* no max. cardinality */
// This is the number of rows we think we will return
myEstProps->setResultCardinality(udfCard);
// From the given ColStatDescList, populate columnStats with column
// descriptors that are useful based on the characteristic outputs
// for the group.
myEstProps->pickOutputs(udfColStatDescList,
inputEstLogProp,
getGroupAttr()->getCharacteristicOutputs(),
predsEvaluatedForStats);
// attach histograms to group attributes
getGroupAttr()->addInputOutputLogProp (inputEstLogProp, myEstProps);
};
///////////////////////////////////////////////////////////
NABoolean TableMappingUDF::pilotAnalysis(QueryAnalysis* qa)
{
return RelExpr::pilotAnalysis(qa);
};
void TableMappingUDF::jbbAnalysis(QueryAnalysis* qa)
{
RelExpr::jbbAnalysis(qa);
};
void TableMappingUDF::jbbJoinDependencyAnalysis(ValueIdSet & predsWithDependencies)
{
RelExpr::jbbJoinDependencyAnalysis(predsWithDependencies);
};
void TableMappingUDF::predAnalysis(QueryAnalysis* qa)
{
RelExpr::predAnalysis(qa);
};
RelExpr* TableMappingUDF::convertToMultiJoinSubtree(QueryAnalysis* qa)
{
return RelExpr::convertToMultiJoinSubtree(qa);
};
RelExpr* TableMappingUDF::expandMultiJoinSubtree()
{
return RelExpr::expandMultiJoinSubtree();
};
void TableMappingUDF::analyzeInitialPlan()
{
RelExpr::analyzeInitialPlan();
};
///////////////////////////////////////////////////////////
// ---------------------------------------------------------------------
// comparison, hash, and copy methods
// ---------------------------------------------------------------------
SimpleHashValue TableMappingUDF::hash()
{
return RelExpr::hash();
}; // from ExprNode
HashValue TableMappingUDF::topHash()
{
HashValue result = RelRoutine::topHash();
for (Int32 i=0; i<getArity(); i++)
{
result ^= (childInfo_[i]->getPartitionBy());
result ^= (childInfo_[i]->getOrderBy());
}
return result;
};
NABoolean TableMappingUDF::patternMatch(const RelExpr & other) const
{
// will need additional code for CQS
return (RelExpr::patternMatch(other) &&
getArity() == other.getArity());
};
NABoolean TableMappingUDF::duplicateMatch(const RelExpr & other) const
{
if (!TableValuedFunction::duplicateMatch(other))
return FALSE;
TableMappingUDF &o = (TableMappingUDF &) other;
for (Int32 i=0; i<getArity(); i++)
{
if (NOT ((childInfo_[i]->getPartitionBy()) == (o.childInfo_[i]->getPartitionBy())))
return FALSE;
if (NOT ((childInfo_[i]->getOrderBy()) == (o.childInfo_[i]->getOrderBy())))
return FALSE;
}
return TRUE;
};
NABoolean TableMappingUDF::isLogical() const { return TRUE; }
NABoolean TableMappingUDF::isPhysical() const { return FALSE; }
void TableMappingUDF::checkAndCoerceScalarInputParamTypes(BindWA* bindWA)
{
if (getProcInputParamsVids().entries() != getScalarInputParamCount())
{
*CmpCommon::diags() << DgSqlCode(-4452)
<< DgString0(getUserTableName().getCorrNameAsString())
<< DgInt0((Lng32) getScalarInputParamCount())
<< DgInt1((Lng32) getProcInputParamsVids().entries());
bindWA->setErrStatus();
return ;
}
for(Int32 i =0; i < getScalarInputParamCount(); i++)
{
const NAType &paramType = *(getScalarInputParams()[i]->getType());
ValueId inputTypeId = getProcInputParamsVids()[i];
// If function argument is character type, get detailed info.
if (inputTypeId.getType().getTypeQualifier() == NA_CHARACTER_TYPE)
{
const CharType* stringLiteral = (CharType*)&(inputTypeId.getType());
if(CmpCommon::wantCharSetInference())
{
const CharType* desiredType =
CharType::findPushDownCharType(((CharType&)paramType).getCharSet(),
stringLiteral, 0);
if ( desiredType )
inputTypeId.coerceType((NAType&)*desiredType, NA_CHARACTER_TYPE);
}
}
// Get final type of function argument.
const NAType &inputType = inputTypeId.getType();
// Do type checking,
// If it is not a compatible type report an error
if (!( NA_UNKNOWN_TYPE == inputType.getTypeQualifier() ||
paramType.isCompatible(inputType) ||
inputTypeId.getItemExpr()->getOperatorType() == ITM_DYN_PARAM))
{
// Error, data types dont match
// Create error for user-defined function.
*CmpCommon::diags() << DgSqlCode(-4455)
<< DgInt0((Lng32) i+1)
<< DgString0(getUserTableName().getCorrNameAsString())
<< DgString1(inputType.getTypeSQLname(TRUE))
<< DgString2(paramType.getTypeSQLname(TRUE));
bindWA->setErrStatus();
return;
} // if NOT isCompatible
if ( ! ( paramType == inputType) )
{
// Create a Cast node to cast the argument from the function call
// to the type specified by the metadata (if the two are compatible.)
Cast *castExpr = new (bindWA->wHeap())
Cast(inputTypeId.getItemExpr(), &paramType, ITM_CAST, TRUE);
ItemExpr *boundCast = castExpr->bindNode(bindWA);
if (bindWA->errStatus()) return;
// Add to input vid list.
getProcInputParamsVids().removeAt(i);
getProcInputParamsVids().insertAt(i,boundCast->getValueId());
}
}
}
void TableMappingUDF::createOutputVids(BindWA* bindWA)
{
// RETDesc has already been allocated
RETDesc *resultTable = getRETDesc();
if (!resultTable)
{
bindWA->setErrStatus();
return;
}
for(Int32 i =0; i < getOutputParamCount(); i++)
{
NAColumn &naColumn = *(getOutputParams()[i]);
const NAType &paramType = *(naColumn.getType());
// use a NamedTypeToItem, so EXPLAIN and other
// tools show a name instead of just the type
NamedTypeToItem *paramTypeItem =
new (bindWA->wHeap()) NamedTypeToItem(
naColumn.getColName().data(),
naColumn.mutateType(),
bindWA->wHeap());
ItemExpr *outputExprToBind = NULL;
outputExprToBind = paramTypeItem->bindNode (bindWA);
if ( bindWA->errStatus()) return;
// Fill the ValueIdList for the output params
addProcOutputParamsVid(outputExprToBind->getValueId());
const NAString &formalParamName = naColumn.getColName();
const NAString *colParamName = &formalParamName;
ColRefName *columnName =
new (bindWA->wHeap())
ColRefName(*colParamName, bindWA->wHeap());
resultTable->addColumn(bindWA, *columnName, outputExprToBind->getValueId());
}
return ;
}
NARoutine * TableMappingUDF::getRoutineMetadata(
QualifiedName &routineName,
CorrName &tmfuncName,
BindWA *bindWA)
{
NARoutine *result = NULL;
CmpSeabaseDDL cmpSBD((NAHeap *)bindWA->wHeap());
TrafDesc *tmudfMetadata =
cmpSBD.getSeabaseRoutineDesc(
routineName.getCatalogName(),
routineName.getSchemaName(),
routineName.getObjectName());
// IS req 5: If function name not found, output binder error.
if (NULL == tmudfMetadata)
{
*CmpCommon::diags() << DgSqlCode(-4450)
<< DgString0(tmfuncName.getQualifiedNameAsString());
bindWA->setErrStatus();
return NULL;
}
ComRoutineType udfType ;
udfType = tmudfMetadata->routineDesc()->UDRType ;
// IS req 6: Check ROUTINE_TYPE column of ROUTINES table.
// Emit error if invalid type.
if (udfType != COM_TABLE_UDF_TYPE)
{
*CmpCommon::diags() << DgSqlCode(-4457)
<< DgString0(tmfuncName.getQualifiedNameAsString())
<< DgString1("Only table-valued functions are supported here");
bindWA->setErrStatus();
return NULL;
}
// IS req 3, 7.3. Instantiate NARoutine object.
// NARoutine data members will be assigned from udfMetadata.
Int32 errors=0;
result = new (bindWA->wHeap())
NARoutine(tmfuncName.getQualifiedNameObj(),
tmudfMetadata,
bindWA,
errors,
bindWA->wHeap());
if ( NULL == result || errors != 0)
{
bindWA->setErrStatus();
return NULL;
}
return result;
}
// -----------------------------------------------------------------------
// methods for class PredefinedTableMappingFunction
// -----------------------------------------------------------------------
PredefinedTableMappingFunction::PredefinedTableMappingFunction(
int arity,
const CorrName &name,
ItemExpr *params,
OperatorTypeEnum otype,
CollHeap *oHeap) :
TableMappingUDF(name, params, arity, otype, oHeap)
{}
PredefinedTableMappingFunction::~PredefinedTableMappingFunction()
{}
// static method to find out whether a given name is a
// built-in table-mapping function - returns operator type
// of predefined function if so, REL_ANY_TABLE_MAPPING_UDF otherwise
OperatorTypeEnum PredefinedTableMappingFunction::nameIsAPredefinedTMF(const CorrName &name)
{
// Predefined functions don't reside in a schema, they are referenced with an unqualified name
const QualifiedName &qualName = name.getQualifiedNameObj();
const NAString &funcName = qualName.getObjectName();
if (! qualName.getSchemaName().isNull())
return REL_ANY_TABLE_MAPPING_UDF;
if (funcName == "EVENT_LOG_READER")
return REL_TABLE_MAPPING_BUILTIN_LOG_READER;
else if (funcName == "TIMESERIES")
return REL_TABLE_MAPPING_BUILTIN_TIMESERIES;
else if (funcName == "SERIES")
return REL_TABLE_MAPPING_BUILTIN_SERIES;
else if (funcName == "JDBC")
return REL_TABLE_MAPPING_BUILTIN_JDBC;
else
// none of the built-in names matched, so it must be a UDF
return REL_ANY_TABLE_MAPPING_UDF;
}
const NAString PredefinedTableMappingFunction::getText() const
{
switch (getOperatorType())
{
case REL_TABLE_MAPPING_BUILTIN_LOG_READER:
return "event_log_reader";
case REL_TABLE_MAPPING_BUILTIN_TIMESERIES:
return "timeseries";
case REL_TABLE_MAPPING_BUILTIN_SERIES:
return "series";
case REL_TABLE_MAPPING_BUILTIN_JDBC:
return "jdbc_udf";
default:
CMPASSERT(0);
return "predefined_tmf_with_invalid_operator_type";
}
}
PredefinedTableMappingFunction * PredefinedTableMappingFunction::castToPredefinedTableMappingFunction()
{
return this;
}
// a virtual function used to copy most of a Node
RelExpr * PredefinedTableMappingFunction::copyTopNode(RelExpr *derivedNode,
CollHeap* outHeap)
{
RelExpr *result;
if (derivedNode == NULL)
result = new(outHeap) PredefinedTableMappingFunction(
getArity(),
getUserTableName(),
NULL, // params get copied by parent classes
getOperatorType(),
outHeap);
else
result = derivedNode;
return TableMappingUDF::copyTopNode(derivedNode, outHeap);
}
NARoutine * PredefinedTableMappingFunction::getRoutineMetadata(
QualifiedName &routineName,
CorrName &tmfuncName,
BindWA *bindWA)
{
NARoutine *result = NULL;
ComRoutineLanguage lang = COM_LANGUAGE_CPP;
ComRoutineParamStyle paramStyle = COM_STYLE_CPP_OBJ;
const char *externalName = NULL;
// By default, predefined UDRs share a DLL.
const char *libraryFileName = "libudr_predef.so";
NAString libraryPath;
// the libraries for predefined UDRs are in the regular
// library directory $TRAF_HOME/export/lib${SQ_MBTYPE}
libraryPath += getenv("TRAF_HOME");
libraryPath += "/export/lib";
switch (getOperatorType())
{
case REL_TABLE_MAPPING_BUILTIN_LOG_READER:
externalName = "TRAF_CPP_EVENT_LOG_READER";
libraryPath += getenv("SQ_MBTYPE");
break;
case REL_TABLE_MAPPING_BUILTIN_SERIES:
externalName = "SERIES";
libraryPath += getenv("SQ_MBTYPE");
break;
case REL_TABLE_MAPPING_BUILTIN_TIMESERIES:
externalName = "TRAF_CPP_TIMESERIES";
libraryPath += getenv("SQ_MBTYPE");
break;
case REL_TABLE_MAPPING_BUILTIN_JDBC:
lang = COM_LANGUAGE_JAVA;
paramStyle = COM_STYLE_JAVA_OBJ;
externalName = "org.trafodion.sql.udr.predef.JDBCUDR";
libraryPath += "/trafodion-sql-";
libraryPath += getenv("TRAFODION_VER");
libraryPath += ".jar";
break;
default:
*CmpCommon::diags() << DgSqlCode(-4457)
<< DgString0(routineName.getQualifiedNameAsString())
<< DgString1("Failed to get metadata for predefined UDF");
bindWA->setErrStatus();
return NULL;
}
// Produce a very simple NARoutine, most of the
// error checking and determination of output
// columns is done by the compiler interface of
// this predefined table mapping function.
result = new(bindWA->wHeap()) NARoutine(routineName,
bindWA->wHeap());
result->setExternalName(externalName);
result->setLanguage(lang);
result->setRoutineType(COM_TABLE_UDF_TYPE);
result->setParamStyle(paramStyle);
result->setFile(libraryFileName);
result->setExternalPath(libraryPath);
return result;
}
// -----------------------------------------------------------------------
// methods for class PhysicalTableMappingUDF
// -----------------------------------------------------------------------
double PhysicalTableMappingUDF::getEstimatedRunTimeMemoryUsage(Generator *generator, ComTdb * tdb) {return 0;}
RelExpr * PhysicalTableMappingUDF::copyTopNode(RelExpr *derivedNode,
CollHeap* outHeap)
{
PhysicalTableMappingUDF *result;
if (derivedNode == NULL)
result = new(outHeap) PhysicalTableMappingUDF(getArity(), outHeap);
else
result = (PhysicalTableMappingUDF *) derivedNode;
result->planInfo_ = planInfo_;
return TableMappingUDF::copyTopNode(result, outHeap);
}
//! PhysicalTableMappingUDF::getText method
const NAString PhysicalTableMappingUDF::getText() const
{
return TableMappingUDF::getText();
}
// -----------------------------------------------------------------------
// methods for class BuiltinTableValuedFunction
// -----------------------------------------------------------------------
//! BuiltinTableValuedFunction::~BuiltinTableValuedFunction Destructor
BuiltinTableValuedFunction::~BuiltinTableValuedFunction()
{
}
//! BuiltinTableValuedFunction::getText method
const NAString BuiltinTableValuedFunction::getText() const
{
return "BuiltinTableValuedFunction";
}
// -----------------------------------------------------------------------
// methods for class TableValuedUDF
// -----------------------------------------------------------------------
//! TableValuedUDF::~TableValuedUDF Destructor
TableValuedUDF::~TableValuedUDF()
{
}
//! TableValuedUDF::copyTopNode method
RelExpr * TableValuedUDF::copyTopNode(RelExpr *derivedNode,
CollHeap* outHeap)
{
TableValuedUDF *result;
if (derivedNode == NULL)
{
result = new (outHeap) TableValuedUDF(NULL,
getOperatorType(),
outHeap);
}
else
result = (TableValuedUDF *) derivedNode;
return TableValuedFunction::copyTopNode(result, outHeap);
}
//! TableValuedUDF::getText method
const NAString TableValuedUDF::getText() const
{
return "TableValuedUDF";
}
// -----------------------------------------------------------------------
// methods for class IsolatedNonTableUDR
// -----------------------------------------------------------------------
//! IsolatedNonTableUDR::~IsolatedNonTableUDR Destructor
IsolatedNonTableUDR::~IsolatedNonTableUDR()
{
}
//! IsolatedNonTableUDR::getText method
const NAString IsolatedNonTableUDR::getText() const
{
return "IsolatedNonTableUDR";
}
//! IsolatedNonTableUDR::copyTopNode method
RelExpr *IsolatedNonTableUDR::copyTopNode(RelExpr *derivedNode, CollHeap *outHeap)
{
IsolatedNonTableUDR *result;
if (derivedNode == NULL)
result = new (outHeap) IsolatedNonTableUDR(getRoutineName(), outHeap);
else
result = (IsolatedNonTableUDR *) derivedNode;
result->neededValueIds_ = neededValueIds_;
return RelRoutine::copyTopNode(result, outHeap);
}
// -----------------------------------------------------------------------
// methods for class IsolatedScalarUDF
// -----------------------------------------------------------------------
//! IsolatedScalarUDF::~IsolatedScalarUDF Destructor
IsolatedScalarUDF::~IsolatedScalarUDF()
{
}
//! IsolatedScalarUDF::getText method
const NAString IsolatedScalarUDF::getText() const
{
NAString name("Isolated_Scalar_UDF ");
name += getRoutineName().getQualifiedNameAsAnsiString();
if (getRoutineDesc() && getRoutineDesc()->isUUDFRoutine() == TRUE &&
getRoutineDesc()->getActionNARoutine() &&
getRoutineDesc()->getActionNARoutine()->getActionName())
{
name += ":";
name += *(getRoutineDesc()->getActionNARoutine()->getActionName());
}
return name;
}
//! IsolatedScalarUDF::copyTopMethod method
RelExpr *IsolatedScalarUDF::copyTopNode(RelExpr *derivedNode, CollHeap *outHeap)
{
IsolatedScalarUDF *result;
if (derivedNode == NULL)
{
result = new (outHeap) IsolatedScalarUDF(getRoutineName(),
outHeap);
}
else
{
result = (IsolatedScalarUDF *) derivedNode;
}
return super::copyTopNode(result, outHeap);
}
//! IsolatedScalarUDF::addLocalExpr method
void IsolatedScalarUDF::addLocalExpr(LIST(ExprNode *) &xlist,
LIST(NAString) &llist) const
{
RelRoutine::addLocalExpr(xlist,llist);
}
//! IsolatedScalarUDF::getPotentialOutputValues method
void IsolatedScalarUDF::getPotentialOutputValues(ValueIdSet &vs) const
{
vs.clear();
vs.insertList(getProcOutParams());
}
// -----------------------------------------------------------------------
// methods for class PhysicalIsolatedScalarUDF
// -----------------------------------------------------------------------
//! PhysicalIsolatedScalarUDF::PhysicalIsolatedScalarUDF Constructor
PhysicalIsolatedScalarUDF::PhysicalIsolatedScalarUDF(CollHeap *heap)
: IsolatedScalarUDF(NULL, heap)
{
}
// -----------------------------------------------------------------------
// methods for class ExplainFunc
// -----------------------------------------------------------------------
//! ExplainFunc::~ExplainFunc Destructor
ExplainFunc::~ExplainFunc()
{
}
//! ExplainFunc::copyTopNode method
RelExpr * ExplainFunc::copyTopNode(RelExpr *derivedNode, CollHeap* outHeap)
{
ExplainFunc *result;
if (derivedNode == NULL)
result = new (outHeap) ExplainFunc(NULL,outHeap);
else
result = (ExplainFunc *) derivedNode;
return BuiltinTableValuedFunction::copyTopNode(result, outHeap);
}
//! ExplainFunc::getText method
const NAString ExplainFunc::getText() const
{
return "explain";
}
// -----------------------------------------------------------------------
// methods for class HiveMDaccessFunc
// -----------------------------------------------------------------------
HiveMDaccessFunc::HiveMDaccessFunc(NAString *mdt,
NAString* schName,
NAString* objName,
CollHeap *oHeap)
: BuiltinTableValuedFunction(NULL,REL_HIVEMD_ACCESS,oHeap)
{
if (mdt)
mdType_ = *mdt;
if (schName)
schemaName_ = *schName;
if (objName)
objectName_ = *objName;
}
//! HiveMDaccessFunc::~HiveMDaccessFunc Destructor
HiveMDaccessFunc::~HiveMDaccessFunc()
{
}
//! HiveMDaccessFunc::copyTopNode method
RelExpr * HiveMDaccessFunc::copyTopNode(RelExpr *derivedNode, CollHeap* outHeap)
{
HiveMDaccessFunc *result;
if (derivedNode == NULL)
result = new (outHeap) HiveMDaccessFunc(NULL,NULL,NULL,outHeap);
else
result = (HiveMDaccessFunc *) derivedNode;
result->mdType_ = mdType_;
result->schemaName_ = schemaName_;
result->objectName_ = objectName_;
return BuiltinTableValuedFunction::copyTopNode(result, outHeap);
}
RelExpr *HiveMDaccessFunc::bindNode(BindWA *bindWA)
{
if (nodeIsBound())
{
bindWA->getCurrentScope()->setRETDesc(getRETDesc());
return this;
}
RelExpr * re = BuiltinTableValuedFunction::bindNode(bindWA);
if (bindWA->errStatus())
return this;
return re;
}
//! HiveMDaccessFunc::getText method
const NAString HiveMDaccessFunc::getText() const
{
return "hiveMD";
}
void
HiveMDaccessFunc::synthEstLogProp(const EstLogPropSharedPtr& inputEstLogProp)
{
if (getGroupAttr()->isPropSynthesized(inputEstLogProp))
return;
// Create a new Output Log Property with cardinality of 10 for now.
EstLogPropSharedPtr myEstProps(new (HISTHEAP) EstLogProp(10));
getGroupAttr()->addInputOutputLogProp(inputEstLogProp, myEstProps);
} // HiveMDaccessFunc::synthEstLogProp
void
HiveMDaccessFunc::synthLogProp(NormWA * normWAPtr)
{
// Check to see whether this GA has already been associated
// with a logExpr for synthesis. If so, no need to resynthesize
// for this equivalent log. expression.
if (getGroupAttr()->existsLogExprForSynthesis()) return;
RelExpr::synthLogProp(normWAPtr);
} // HiveMDaccessFunc::synthLogProp()
//<pb>
//==============================================================================
// Synthesize physical properties for HiveMD operator's current plan
// extracted from a spcified context.
//
// Input:
// myContext -- specified context containing this operator's current plan.
//
// planNumber -- plan's number within the plan workspace. Used optionally for
// synthesizing partitioning functions but unused in this
// derived version of synthPhysicalProperty().
//
// Output:
// none
//
// Return:
// Pointer to this operator's synthesized physical properties.
//
//==============================================================================
PhysicalProperty*
HiveMDaccessFunc::synthPhysicalProperty(const Context* myContext,
const Lng32 planNumber,
PlanWorkSpace *pws)
{
//----------------------------------------------------------
// Create a node map with a single, active, wild-card entry.
//----------------------------------------------------------
NodeMap* myNodeMap = new(CmpCommon::statementHeap())
NodeMap(CmpCommon::statementHeap(),
1,
NodeMapEntry::ACTIVE);
//------------------------------------------------------------
// Synthesize a partitioning function with a single partition.
//------------------------------------------------------------
PartitioningFunction* myPartFunc =
new(CmpCommon::statementHeap())
SinglePartitionPartitioningFunction(myNodeMap);
PhysicalProperty * sppForMe =
new(CmpCommon::statementHeap())
PhysicalProperty(myPartFunc,
EXECUTE_IN_MASTER,
SOURCE_VIRTUAL_TABLE);
// remove anything that's not covered by the group attributes
sppForMe->enforceCoverageByGroupAttributes (getGroupAttr()) ;
return sppForMe ;
} // HiveMDaccessFunc::synthPhysicalProperty()
// -----------------------------------------------------------------------
// methods for class StatisticsFunc
// -----------------------------------------------------------------------
//! StatisticsFunc::copyTopNode method
RelExpr * StatisticsFunc::copyTopNode(RelExpr *derivedNode, CollHeap* outHeap)
{
StatisticsFunc *result;
if (derivedNode == NULL)
result = new (outHeap) StatisticsFunc(NULL,outHeap);
else
result = (StatisticsFunc *) derivedNode;
return BuiltinTableValuedFunction::copyTopNode(result, outHeap);
}
//! StatisticsFunc::getText method
const NAString StatisticsFunc::getText() const
{
return "statistics";
}
// -----------------------------------------------------------------------
// methods for class ProxyFunc
// -----------------------------------------------------------------------
//! ProxyFunc::ProxyFunc Constructor
ProxyFunc::ProxyFunc(OperatorTypeEnum otype,
ElemDDLNode *columnsFromParser,
CollHeap *heap)
: BuiltinTableValuedFunction(NULL, otype, heap),
columnListFromParser_(columnsFromParser),
virtualTableName_("", heap)
{
}
//! ProxyFunc::ProxyFunc Copy Constructor
ProxyFunc::ProxyFunc(const ProxyFunc &other, CollHeap *h)
: BuiltinTableValuedFunction(other, h),
columnListFromParser_(other.columnListFromParser_),
virtualTableName_(other.virtualTableName_, h)
{
}
//! ProxyFunc::~ProxyFunc Destructor
ProxyFunc::~ProxyFunc()
{
}
//! ProxyFunc::getVirtualTableName method
const char *ProxyFunc::getVirtualTableName()
{
return virtualTableName_.data();
}
//! ProxyFunc::getNumColumns method
ComUInt32 ProxyFunc::getNumColumns() const
{
ComUInt32 result = 0;
if (columnListFromParser_)
result = columnListFromParser_->entries();
return result;
}
//! ProxyFunc::getColumn method
const ElemProxyColDef &ProxyFunc::getColumn(ComUInt32 i) const
{
CMPASSERT(i < getNumColumns());
ElemProxyColDef *result =
(*columnListFromParser_)[i]->castToElemProxyColDef();
CMPASSERT(result);
return *result;
}
//! ProxyFunc::getColumnType method
const NAType &ProxyFunc::getColumnType(ComUInt32 i) const
{
const ElemProxyColDef &c = getColumn(i);
const NAType *t = c.getColumnDataType();
CMPASSERT(t);
return *t;
}
//! ProxyFunc::getColumnNameForDescriptor method
const NAString *ProxyFunc::getColumnNameForDescriptor(ComUInt32 i) const
{
const ElemProxyColDef &c = getColumn(i);
const NAString &s = c.getColumnName();
return &s;
}
//! ProxyFunc::getTableNameForDescriptor method
const QualifiedName *ProxyFunc::getTableNameForDescriptor(ComUInt32 i) const
{
const ElemProxyColDef &c = getColumn(i);
const QualifiedName *qn = c.getTableName();
return qn;
}
//! ProxyFunc::getColumnHeading method
const NAString *ProxyFunc::getColumnHeading(ComUInt32 i) const
{
const ElemProxyColDef &c = getColumn(i);
if (c.getIsHeadingSpecified())
{
const NAString &s = c.getHeading();
return &s;
}
return NULL;
}
//! ProxyFunc::populateColumnDesc method
void ProxyFunc::populateColumnDesc(char *tableNam,
TrafDesc *&colDescs,
Lng32 &reclen) const
{
ElemDDLColDefArray colArray;
ComObjectName tableName(tableNam);
ComUInt32 numCols = getNumColumns();
for (ComUInt32 colNum = 0; colNum < numCols; colNum++)
{
ElemProxyColDef *result =
(*columnListFromParser_)[colNum]->castToElemProxyColDef();
colArray.insert(result);
}
CmpSeabaseDDL cmpSBD(CmpCommon::statementHeap());
ComTdbVirtTableColumnInfo * colInfoArray = (ComTdbVirtTableColumnInfo*)
new(STMTHEAP) char[numCols * sizeof(ComTdbVirtTableColumnInfo)];
cmpSBD.buildColInfoArray(COM_USER_DEFINED_ROUTINE_OBJECT,
FALSE,
&colArray,
colInfoArray,
FALSE, FALSE, NULL, NULL, NULL, NULL,
CmpCommon::statementHeap());
for (size_t colNum = 0; colNum < colArray.entries(); colNum++)
{
char buf[128];
str_sprintf(buf, "C%d", (Int32) colNum + 1);
const char *colName = &buf[0];
char * col_name = new(STMTHEAP) char[strlen(colName) + 1];
strcpy(col_name, (char*)colName);
colInfoArray[colNum].colName = col_name;
}
colDescs = cmpSBD.convertVirtTableColumnInfoArrayToDescStructs(&tableName,
colInfoArray,
numCols) ;
// calculate the record length
TrafDesc *tempDescs = colDescs;
for (ComUInt32 colNum = 0; colNum < numCols; colNum++)
{
NAType *naType = getColumn(colNum).getColumnDataType();
Int32 fsType = naType->getFSDatatype();
if (tempDescs->columnsDesc()->isNullable())
reclen += SQL_NULL_HDR_SIZE;
if (DFS2REC::isSQLVarChar(fsType))
reclen += SQL_VARCHAR_HDR_SIZE;
reclen += tempDescs->columnsDesc()->length;
tempDescs = tempDescs->next;
}
}
//! ProxyFunc::copyTopNode method
RelExpr *ProxyFunc::copyTopNode(RelExpr *derivedNode, CollHeap *outHeap)
{
ProxyFunc *result;
if (derivedNode == NULL)
result = new (outHeap) ProxyFunc(*this);
else
result = (ProxyFunc *) derivedNode;
// make a shallow copy of the parse tree struct. This was originally
// instantiated as a shallow copy from the parser too.
// assumption is that is is read only and that it does not get freed...
result->columnListFromParser_ = columnListFromParser_;
result->virtualTableName_ = virtualTableName_;
return TableValuedFunction::copyTopNode(result, outHeap);
}
//! ProxyFunc::topHash method
HashValue ProxyFunc::topHash()
{
HashValue result = BuiltinTableValuedFunction::topHash();
result ^= columnListFromParser_;
result ^= virtualTableName_.hash();
return result;
}
//! ProxyFunc::duplicateMatch method
NABoolean ProxyFunc::duplicateMatch(const RelExpr & other) const
{
if (!BuiltinTableValuedFunction::duplicateMatch(other))
return FALSE;
ProxyFunc &o = (ProxyFunc &) other;
if (columnListFromParser_ != o.columnListFromParser_)
return FALSE;
if (virtualTableName_ != o.virtualTableName_)
return FALSE;
return TRUE;
}
// -----------------------------------------------------------------------
// methods for class SPProxyFunc
// -----------------------------------------------------------------------
//! SPProxyFunc::SPProxyFunc Constructor
SPProxyFunc::SPProxyFunc(ElemDDLNode *columnsFromParser,
ItemExprList *optionalStrings,
CollHeap *heap)
: ProxyFunc(REL_SP_PROXY, columnsFromParser, heap),
optionalStrings_(optionalStrings)
{
}
//! SPProxyFunc::SPProxyFunc Constructor
SPProxyFunc::SPProxyFunc(CollHeap *heap)
: ProxyFunc(REL_SP_PROXY, NULL, heap),
optionalStrings_(NULL)
{
}
//! SPProxyFunc::SPProxyFunc Copy Constructor
SPProxyFunc::SPProxyFunc(const SPProxyFunc &other, CollHeap *h)
: ProxyFunc(other,h),
optionalStrings_(other.optionalStrings_)
{
}
//! SPProxyFunc::~SPProxyFunc Destructor
SPProxyFunc::~SPProxyFunc()
{
}
//! SPProxyFunc::getNumOptionalStrings method
ComUInt32 SPProxyFunc::getNumOptionalStrings() const
{
ComUInt32 result = 0;
if (optionalStrings_)
result = optionalStrings_->entries();
return result;
}
//! SPProxyFunc::getOptionalString method
const char *SPProxyFunc::getOptionalString(ComUInt32 i) const
{
const char *result = NULL;
const ItemExpr *e = NULL;
const ConstValue *cv = NULL;
const NAString *s = NULL;
NABoolean dummyNegate = FALSE;
if (i < getNumOptionalStrings())
e = (*optionalStrings_)[i];
if (e)
cv = ((ItemExpr *) e)->castToConstValue(dummyNegate);
if (cv)
s = cv->getRawText();
if (s)
result = s->data();
return result;
}
//! SPProxyFunc::copyTopNode method
RelExpr *SPProxyFunc::copyTopNode(RelExpr *derivedNode, CollHeap *outHeap)
{
SPProxyFunc *result;
if (derivedNode == NULL)
result = new (outHeap) SPProxyFunc(*this);
else
result = (SPProxyFunc *) derivedNode;
// Make a shallow copy of the pointer.
result->optionalStrings_ = optionalStrings_;
return ProxyFunc::copyTopNode(result, outHeap);
}
//! SPProxyFunc::getText method
const NAString SPProxyFunc::getText() const
{
return "sp_result_set";
}
//! SPProxyFunc::topHash method
HashValue SPProxyFunc::topHash()
{
HashValue result = ProxyFunc::topHash();
result ^= optionalStrings_;
return result;
}
//! SPProxyFunc::duplicateMatch method
NABoolean SPProxyFunc::duplicateMatch(const RelExpr & other) const
{
if (!ProxyFunc::duplicateMatch(other))
return FALSE;
SPProxyFunc &o = (SPProxyFunc &) other;
if (optionalStrings_ != o.optionalStrings_)
return FALSE;
return TRUE;
}
// -----------------------------------------------------------------------
// methods for class CallSP
// -----------------------------------------------------------------------
// Raj P - 12/2000
//! CallSP::copyTopNode method
// virtual copy constructor for the CallSP class
RelExpr *CallSP::copyTopNode(RelExpr *derivedNode, CollHeap *outHeap)
{
CallSP *result;
if (derivedNode == NULL)
result = new (outHeap) CallSP(getRoutineName(), outHeap);
else
result = (CallSP *) derivedNode;
result->duplicateVars_ = duplicateVars_;
result->outDupVars_ = outDupVars_;
result->hasUDF_ = hasUDF_;
return super::copyTopNode(result, outHeap);
}
//! CallSP::getPotentialOutputValues method
void CallSP::getPotentialOutputValues(ValueIdSet &vs) const
{
vs.clear();
vs.insertList(getProcOutputParamsVids());
}
//! CallSP::getText method
const NAString CallSP::getText() const
{
NAString result("call ", CmpCommon::statementHeap ());
result += getRoutineName().getQualifiedNameAsString();
if (nodeIsBound())
{
getProcAllParamsVids().unparse(result);
}
else
{
result += "(";
if (getProcAllParamsTree() != NULL)
{
getProcAllParamsTree()->unparse(result);
}
result += ")";
}
return result;
}
//! CallSP::pushdownCoveredExpr method
void CallSP::pushdownCoveredExpr(const ValueIdSet &outputExprOnOperator,
const ValueIdSet &newExternalInputs,
ValueIdSet &predicatesOnOperator,
const ValueIdSet *nonPredNonOutputExprOnOperator,
Lng32 childIndex
)
{
// We use an emptySet for the outputs for the call to
// Relexpr::pushdowCoveredExpr because our child is a tuple with a
// subquery in it and that subquery is an input to the Routine, so none
// of the CallSPs output pertains to the child.
ValueIdSet emptySet;
RelExpr::pushdownCoveredExpr( emptySet,
newExternalInputs,
predicatesOnOperator,
&getNeededValueIds());
}
// -----------------------------------------------------------------------
// methods for class ExtractSource
// -----------------------------------------------------------------------
//! ExtractSource::ExtractSource Constructor
ExtractSource::ExtractSource(ElemDDLNode *columnsFromParser,
NAString &espPhandle,
NAString &securityKey,
CollHeap *heap)
: ProxyFunc(REL_EXTRACT_SOURCE, columnsFromParser, heap),
espPhandle_(espPhandle, heap),
securityKey_(securityKey, heap)
{
}
//! ExtractSource::ExtractSource Constructor
ExtractSource::ExtractSource(CollHeap *heap)
: ProxyFunc(REL_EXTRACT_SOURCE, NULL, heap),
espPhandle_("", heap),
securityKey_("", heap)
{
}
//! ExtractSource::ExtractSource Copy Constructor
ExtractSource::ExtractSource(const ExtractSource &other, CollHeap *h)
: ProxyFunc(other,h),
espPhandle_(other.espPhandle_),
securityKey_(other.securityKey_)
{
}
//! ExtractSource::~ExtractSource Destructor
ExtractSource::~ExtractSource()
{
}
//! ExtractSource::copyTopNode method
RelExpr *ExtractSource::copyTopNode(RelExpr *derivedNode, CollHeap *outHeap)
{
ExtractSource *result;
if (derivedNode == NULL)
result = new (outHeap) ExtractSource(*this, outHeap);
else
result = (ExtractSource *) derivedNode;
result->espPhandle_ = espPhandle_;
result->securityKey_ = securityKey_;
return ProxyFunc::copyTopNode(result, outHeap);
}
//! ExtractSource::getText method
const NAString ExtractSource::getText() const
{
return "extract_source";
}
//! ExtractSource::topHash method
HashValue ExtractSource::topHash()
{
HashValue result = ProxyFunc::topHash();
result ^= espPhandle_.hash();
result ^= securityKey_.hash();
return result;
}
//! ExtractSource::duplicateMatch method
NABoolean ExtractSource::duplicateMatch(const RelExpr & other) const
{
if (!ProxyFunc::duplicateMatch(other))
return FALSE;
ExtractSource &o = (ExtractSource &) other;
if (espPhandle_ != o.espPhandle_)
return FALSE;
if (securityKey_ != o.securityKey_)
return FALSE;
return TRUE;
}