blob: 4ceb7e8fbc8af1c6f4a987a79b69bd6351fb508b [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 @@@
**********************************************************************/
#include "GroupAttr.h"
#include "AllItemExpr.h"
#include "ItemSample.h"
#include "Sqlcomp.h"
// -----------------------------------------------------------------------
// member functions for Balance
// -----------------------------------------------------------------------
//
ItmBalance::~ItmBalance() {};
HashValue ItmBalance::topHash()
{
HashValue result = ItemExpr::topHash();
result ^= (const ValueId &)child(0);
result ^= (const ValueId &)child(1);
return result;
}
ItemExpr * ItmBalance::getNextBalance() const
{
if (sampleType() == RelSample::PERIODIC ||
sampleType() == RelSample::CLUSTER)
return child(3);
else
return child(2);
}
ItemExpr * ItmBalance::getSkipSize() const
{
if (sampleType() == RelSample::PERIODIC)
return child(2);
else
return NULL;
}
ItemExpr * ItmBalance::getClusterSize() const
{
if (sampleType() == RelSample::CLUSTER)
return child(2);
else
return NULL;
}
void ItmBalance::propagateSampleType(RelSample::SampleTypeEnum sampType)
{
// Must be called BEFORE rearrangeChildren() is called
setSampleType(sampType);
ItmBalance * nextBal = (ItmBalance *)(ItemExpr *)child(2);
while (nextBal != NULL)
{
nextBal->setSampleType(sampType);
nextBal = (ItmBalance *)(ItemExpr *)(nextBal->child(2));
}
}
void ItmBalance::rearrangeChildren()
{
// This is called from the parser before any processing on the
// balance node. It basically reorders the skipSize/clusterSize and
// nextBalance children for the entire tree in addition to setting
// the skipSize for all the balance nodes in the tree if the
// sampling type is periodic. NOTE: Access the specific children
// (e.g., skipSize, etc) only through the accessor functions after
// this is called.
if (sampleType() != RelSample::PERIODIC &&
sampleType() != RelSample::CLUSTER)
// Nothing to rearrange
return;
ItemExpr * skip = (ItemExpr *)child(3);
ItmBalance * nextBal = (ItmBalance *)(ItemExpr *)child(2);
// Rearrange for this node
setChild(2, skip);
setChild(3, nextBal);
// Propagate down the tree
while (nextBal != NULL)
{
ItmBalance * temp = (ItmBalance *)(ItemExpr *)(nextBal->child(2));
nextBal->setChild(2, skip);
nextBal->setChild(3, temp);
nextBal = temp;
}
}
Int32 ItmBalance::getArity() const
{
Int32 arity = 2;
if (sampleType() == RelSample::PERIODIC ||
sampleType() == RelSample::CLUSTER)
arity++;
if (getNextBalance() != NULL)
arity++;
return arity;
}
NABoolean ItmBalance::duplicateMatch(const ItemExpr &other) const
{
if (NOT ItemExpr::duplicateMatch(other))
return FALSE;
ItmBalance &o = (ItmBalance &)other;
if (child(0) != o.child(0))
return FALSE;
if (child(1) != o.child(1))
return FALSE;
if (sampleType() != o.sampleType())
return FALSE;
return TRUE;
}
ItemExpr * ItmBalance::copyTopNode(ItemExpr *derivedNode, CollHeap* outHeap)
{
ItmBalance *result;
if (derivedNode == NULL)
result = new (outHeap) ItmBalance(child(0),
child(1),
child(2),
child(3),
isAbsolute(),
isExact());
else
{
result = (ItmBalance *)derivedNode;
result->absolute_ = isAbsolute();
result->exact_ = isExact();
}
result->sampleType_ = sampleType();
result->skipAbsolute_ = isSkipAbsolute();
return ItemExpr::copyTopNode(result, outHeap);
}
NABoolean ItmBalance::isCovered(const ValueIdSet& newExternalInputs,
const GroupAttributes& newRelExprAnchorGA,
ValueIdSet& referencedInputs,
ValueIdSet& coveredSubExpr,
ValueIdSet& unCoveredExpr) const
{
ValueIdSet localSubExpr;
for(Lng32 i = 0; i < (Lng32)getArity(); i++)
{
if(newRelExprAnchorGA.covers(child(i)->getValueId(),
newExternalInputs,
referencedInputs,
&localSubExpr))
{
coveredSubExpr += child(i)->getValueId();
}
coveredSubExpr += localSubExpr;
}
// Return FALSE unconditionally. Only the sample operator can perform
// balancing.
return FALSE;
}
const NAType *ItmBalance::synthesizeType()
{
// returns a signed, non-null integer
return new HEAP SQLInt(HEAP, TRUE,FALSE);
}
double
ItmBalance::getSampleConstValue() const
{
NABoolean negate = FALSE;
ConstValue *sizeExpr = (getSampleSize()
? getSampleSize()->castToConstValue(negate)
: NULL);
CMPASSERT(negate == FALSE);
double size = 0.0;
Lng32 scale;
if(sizeExpr && sizeExpr->canGetExactNumericValue()) {
size = (double)sizeExpr->getExactNumericValue(scale);
while (scale--) size /= 10;
}
return size;
}
double
ItmBalance::getSkipConstValue() const
{
NABoolean negate = FALSE;
ConstValue *skipExpr = (getSkipSize()
? getSkipSize()->castToConstValue(negate)
: NULL);
CMPASSERT(negate == FALSE);
double skip = 0.0;
Lng32 scale;
if(skipExpr && skipExpr->canGetExactNumericValue()) {
skip = (double)skipExpr->getExactNumericValue(scale);
while (scale--) skip /= 10;
}
return skip;
}
double
ItmBalance::getClusterConstValue() const
{
NABoolean negate = FALSE;
ConstValue *clusterExpr = (getClusterSize()
? getClusterSize()->castToConstValue(negate)
: NULL);
CMPASSERT(negate == FALSE);
double cluster = 0.0;
Lng32 scale;
if(clusterExpr && clusterExpr->canGetExactNumericValue()) {
cluster = (double)clusterExpr->getExactNumericValue(scale);
while (scale--) cluster /= 10;
}
return cluster;
}
CostScalar ItmBalance::computeResultSize(CostScalar initialRowCount)
{
CostScalar result = 0;
if(getNextBalance()) {
CMPASSERT(getNextBalance()->getOperatorType() == ITM_BALANCE);
result =
((ItmBalance *)getNextBalance())->computeResultSize(initialRowCount);
}
CostScalar size = getSampleConstValue();
CostScalar skip = getSkipConstValue();
if(!isAbsolute())
size = (size / 100.0) * initialRowCount;
if(!isSkipAbsolute())
skip = (skip / 100.0) * initialRowCount;
switch(sampleType()) {
case RelSample::RANDOM:
case RelSample::FIRSTN:
case RelSample::CLUSTER:
result += size;
break;
case RelSample::PERIODIC:
result += ((size/skip) * initialRowCount);
break;
}
if(result.isZero())
result.minCsOne();
return result;
}
Int32
ItmBalance::checkErrors()
{
RelSample::SampleTypeEnum sampType = sampleType();
NABoolean absolute = isAbsolute();
NABoolean absoluteSkip = isSkipAbsolute();
Int32 error = 0;
ItmBalance *balNode = this;
while(balNode) {
CMPASSERT(balNode->getOperatorType() == ITM_BALANCE);
CMPASSERT(sampType == balNode->sampleType());
if(absolute != balNode->isAbsolute()) {
*CmpCommon::diags() << DgSqlCode(-4112);
error = -1;
}
if(absolute) {
CMPASSERT(getSampleSize());
NABoolean negate = FALSE;
ConstValue *sizeExpr = getSampleSize()->castToConstValue(negate);
CMPASSERT(negate == FALSE);
CMPASSERT(sizeExpr);
Lng32 scale;
sizeExpr->getExactNumericValue(scale);
if(scale > 0) {
*CmpCommon::diags() << DgSqlCode(-4114);
error = -1;
}
}
if(getSkipSize() && absoluteSkip) {
NABoolean negate = FALSE;
ConstValue *skipExpr = getSkipSize()->castToConstValue(negate);
CMPASSERT(negate == FALSE);
CMPASSERT(skipExpr);
Lng32 scale;
skipExpr->getExactNumericValue(scale);
if(scale > 0) {
*CmpCommon::diags() << DgSqlCode(-4114);
error = -1;
}
}
if(sampType == RelSample::PERIODIC) {
double size = getSampleConstValue();
double skip = getSkipConstValue();
if(size > skip) {
*CmpCommon::diags() << DgSqlCode(-4115);
error = -1;
}
}
if(sampType == RelSample::FIRSTN && !balNode->isAbsolute()) {
*CmpCommon::diags() << DgSqlCode(-4113)
<< DgString0("First")
<< DgString1("Absolute");
error = -1;
}
if(sampType == RelSample::PERIODIC &&
(!balNode->isAbsolute() || !balNode->isSkipAbsolute())) {
*CmpCommon::diags() << DgSqlCode(-4113)
<< DgString0("Periodic")
<< DgString1("Absolute");
error = -1;
}
if(sampType == RelSample::RANDOM && balNode->isAbsolute()) {
*CmpCommon::diags() << DgSqlCode(-4113)
<< DgString0("Random")
<< DgString1("Relative");
error = -1;
}
if(sampType == RelSample::CLUSTER && balNode->isAbsolute()) {
*CmpCommon::diags() << DgSqlCode(-4113)
<< DgString0("Cluster")
<< DgString1("Relative");
error = -1;
}
// CLUSTER sampling does not support oversampling.
//
if(sampType == RelSample::CLUSTER) {
double size = getSampleConstValue();
if (size >= 100) {
*CmpCommon::diags() << DgSqlCode(-4113)
<< DgString0("Cluster")
<< DgString1("< 100%");
error = -1;
}
}
balNode = (ItmBalance *)balNode->getNextBalance();
}
return error;
}
// -----------------------------------------------------------------------
// member functions for NotCovered
// -----------------------------------------------------------------------
//
NotCovered::~NotCovered() {};
NABoolean NotCovered::isCovered(const ValueIdSet& newExternalInputs,
const GroupAttributes& newRelExprAnchorGA,
ValueIdSet& referencedInputs,
ValueIdSet& coveredSubExpr,
ValueIdSet& unCoveredExpr) const
{
ValueIdSet localSubExpr;
for(Lng32 i = 0; i < (Lng32)getArity(); i++)
{
if(newRelExprAnchorGA.covers(child(i)->getValueId(),
newExternalInputs,
referencedInputs,
&localSubExpr))
{
coveredSubExpr += child(i)->getValueId();
}
coveredSubExpr += localSubExpr;
}
// ---------------------------------------------------------------------
// The NotCovered function is coerced to fail the coverage test even
// when its operands are isCovered(). This is because only the
// operator owning this expression can evaluate the function. The
// function is associated with a NotCovered node at the very
// beginning and we don't allow it to be pushed down even if the
// function's operands are covered at the node's child.
// ---------------------------------------------------------------------
return FALSE;
}
//++MV 02/27/01
void NotCovered::getLeafValuesForCoverTest(ValueIdSet& leafValues,
const GroupAttributes& coveringGA,
const ValueIdSet & newExternalInputs) const
{
// NotCovered is considered a leaf operator for cover test.
leafValues += getValueId();
}
//--MV 02/27/01
const NAType *NotCovered::synthesizeType()
{
// The type of this node is the same as its child
//
const NAType *childType = &getColumnRef()->getValueId().getType();
return childType->newCopy(HEAP);
}
ItemExpr *
NotCovered::copyTopNode(ItemExpr *derivedNode,
CollHeap* outHeap)
{
ItemExpr *result;
if (derivedNode == NULL)
result = new (outHeap) NotCovered(NULL);
else
result = derivedNode;
return BuiltinFunction::copyTopNode(result, outHeap);
} // NotCovered::copyTopNode()
// -----------------------------------------------------------------------
// Class RandomSelection
// -----------------------------------------------------------------------
//
// -----------------------------------------------------------------------
// member functions for class RandomNum
// -----------------------------------------------------------------------
RandomSelection::~RandomSelection() {}
ItemExpr * RandomSelection::copyTopNode(ItemExpr *derivedNode,
CollHeap* outHeap)
{
ItemExpr *result;
if (derivedNode == NULL)
result = new (outHeap) RandomSelection(getSelProbability());
else
result = derivedNode;
return BuiltinFunction::copyTopNode(result, outHeap);
} // RandomSelection::copyTopNode()
const NAType *RandomSelection::synthesizeType()
{
// returns an int, unsigned and not null
return new HEAP SQLInt(HEAP, FALSE,FALSE);
}