blob: 1ba28a791263d5fb3004c1d2db11b45cac355fa2 [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 "Generator.h"
#include "GenExpGenerator.h"
#include "exp_function.h"
#include "exp_math_func.h"
#include "CharType.h"
#include "NumericType.h"
#include "ItemSample.h"
#include "ItmFlowControlFunction.h"
// ItmBalance::preCodeGen
//
// Generate the code to implmenent FIRSTN, PERIODIC, and RANDOM sampling
// for this branch of a balance node tree.
//
ItemExpr *ItmBalance::preCodeGen(Generator *generator)
{
// Get a local handle on some things...
//
ExpGenerator *expGen = generator->getExpGenerator();
CollHeap *wHeap = generator->wHeap();
// For both FIRSTN and PERIODIC sampling, allocate an integer index
// counter and an expression to increment the counter.
//
ItemExpr *counterExpr = NULL, *incrementExpr = NULL;
if((sampleType() == RelSample::FIRSTN) ||
(sampleType() == RelSample::PERIODIC))
{
counterExpr = new(wHeap) ItmPersistentExpressionVar(0);
incrementExpr = new(wHeap) ItmBlockFunction
(counterExpr,
new(wHeap) Assign(counterExpr,
new(wHeap) BiArith(ITM_PLUS,
counterExpr,
new (wHeap) ConstValue(1))));
}
// Create the expression to evaluate the <sample condition> for this
// branch of the balance clause. The sample condition returns an integer
// indicating the number of times to return the current row or -1 if
// sampling if completely finished. The integer is typically 0 or 1.
//
// Aftet the sample condition expression is created, it is combined with
// any child balance branches to create an expression for the entire
// balance subtree rooted at this node.
//
ItemExpr *sampleCondition = NULL;
// First N sampling.
//
// Initialization:
// Counter = 0;
// Per Row:
// if Counter < SampleSize then Counter++, 1; else 0;
//
if(sampleType() == RelSample::FIRSTN)
{
// Create the expression Counter++, 1;
//
ItemExpr *conditionTrue = new(wHeap) ItmBlockFunction
(incrementExpr,
new(wHeap) ConstValue(1));
// Construct the expression used when we are done with this
// FIRSTN counter.
//
// Returning 0, causes sample to continue to process rows
// Returning -1 causes sample to cancel the request.
//
// We would like to cancel the request when we have satisfied
// the FIRSTN. However, If there are nested FIRSTN counters, we
// must wait for all counters to complete before returning -1.
// For now just punt and return 0 in the case of nested FIRSTN.
// This will cause the scan and sample to continue processing
// rows, even after the sample is complete. At some point we
// should extend this expression to account for this case.
// Maybe have the doneValue be something like:
//
// (case when (counter1 >= sampleSize1 and counter2 >= sampleSize2 and ...)
// then -1
// else 0
// end)
//
// The problem is that we do not have a handle on all the
// counters and sizes at this point.
//
ItemExpr *doneValue;
if (getNextBalance() || generator->inNestedFIRSTNExpr()) {
// set flag in generator to indicate to Balance expressions
// below that we are in a nested balance expression. Need
// this flag since the leaf balance expression will not have a
// nextBalance expression and will not know that it is nested.
//
generator->setInNestedFIRSTNExpr(TRUE);
// Punt and just allow the scan/sample to continue in the case
// of nested FISRTN sampling.
//
doneValue = new(wHeap) ConstValue(0);
} else {
// Cause the Sample to cancel the request and stop processing
// rows.
//
doneValue = new(wHeap) ConstValue(-1);
}
// Create the remainder of the expression.
//
sampleCondition = expGen->createExprTree
("CASE WHEN @A1 < @A2 THEN @A3 ELSE @A4 END",
0, 4,
counterExpr, // row counter
getSampleSize(), // sample size
conditionTrue, // expression if row qualifies
doneValue // expression if we are done with
// this FIRSTN
);
}
// Periodic sampling.
//
// Initialization:
// Counter = 0;
// Per Row:
// Counter++, if Counter <= 0 then 0; else if(Counter <= sampleSize) 1;
// else Counter = - samplePeriod, 0;
else if(sampleType() == RelSample::PERIODIC)
{
// Compute - samplePeriod.
//
ItemExpr *sampleSkip = new(wHeap) BiArith(ITM_MINUS,
getSampleSize(),
getSkipSize());
// Create the expression Counter = sampleSkip, 1;
//
ItemExpr *resetExpr = new(wHeap) ItmBlockFunction
(new(wHeap) Assign(counterExpr, sampleSkip),
new(wHeap) ConstValue(1));
// Create the remainder of the expression.
//
ItemExpr *caseExpr = expGen->createExprTree
("CASE WHEN @A1 <= 0 THEN 0 "
" WHEN @A1 < @A2 THEN 1 "
" WHEN @A2 > 0 THEN @A3 "
" ELSE 0 END",
0, 4,
counterExpr, // row counter
getSampleSize(),// sample size
resetExpr // reset expression and return 1
);
// Always increment the counter, then apply the case expression
// and returns it's result.
//
sampleCondition = new(wHeap) ItmBlockFunction
(incrementExpr, caseExpr);
}
else if(sampleType() == RelSample::RANDOM)
{
CMPASSERT(!isAbsolute());
NABoolean negate = FALSE;
ConstValue *sizeExpr = (child(1)
? child(1)->castToConstValue(negate)
: NULL);
CMPASSERT(negate == FALSE);
double size = getSampleConstValue();
size = size / 100; // Size specified as percent
sampleCondition = new (wHeap) RandomSelection((float)size);
}
else if(sampleType() == RelSample::CLUSTER)
{
*CmpCommon::diags() << DgSqlCode(-7003);
GenExit();
return NULL;
}
else
GenAssert(0, "ItmBalance::codeGen: Unknown sampling method!");
// At this point the expression for the sample condition for this
// branch of the balance clause has been computed. Now, combine this
// expression with any balance predicate and child balance branchs
// to get an expression representing the entire subtree for this node.
//
// PseudoCode:
// if(predicate) then sampleCondition else nextBranch;
//
// Hack until compiler is changed... set the predicate to null if child(0)
// is simply ITM_TRUE, otherwise use the predicate.
//
ItemExpr *nextBranch = getNextBalance();
ItemExpr *predicate = getPredicate();
if(predicate->getOperatorType() == ITM_RETURN_TRUE) predicate = NULL;
// There cannot be a child branch without a predicate.
//
GenAssert(predicate || !nextBranch,
"Sampling: Balance: Predicate and nextBranch mismatch!");
// If there is no predicate the result expression is simply the
// sampling condition. Otherwise, the result is the sampling condition
// only if the predicate is true and is the child balance branch if
// the predicate is false.
//
ItemExpr *balanceExpr = sampleCondition;
if(predicate)
{
balanceExpr = new(wHeap)
Case(NULL,
new(wHeap) IfThenElse(predicate, sampleCondition, nextBranch));
}
GenAssert(balanceExpr, "balanceExpr failed compilation!");
// Synthesize the types and value Ids for the new items.
//
balanceExpr->synthTypeAndValueId(TRUE);
// Repalce the orginal value ID with the new item expression.
//
getValueId().replaceItemExpr(balanceExpr);
balanceExpr = balanceExpr->preCodeGen(generator);
// Clear the nested FIRSTN flag in case it was set.
//
generator->setInNestedFIRSTNExpr(FALSE);
// return the preCodeGen of the new expression.
//
return balanceExpr;
}
// ItmBalance::codeGen
//
// ItmBalance should have been transformed away in preCodeGen -- see above.
//
short ItmBalance::codeGen(Generator * /*generator*/)
{
GenAssert(0, "ItmBalance::codeGen -- Should never get here!");
return 0;
}
// NotCovered::codeGen NotCovered is codegenned to be a convert clause
// (copy). Basically, it is a NOOP, but the convert is added here to
// make things simplier. The extra move should be optimized away
// during PCode generation. Alternatively, the map table could have
// been modified to map the result of this operation to be the same as
// the result of child(0).
//
short NotCovered::codeGen(Generator *generator)
{
Attributes** attr;
if(generator->getExpGenerator()->genItemExpr(this,
&attr,
1 + getArity(),
-1) == 1)
return 0;
ex_conv_clause * conv_clause =
new(generator->getSpace()) ex_conv_clause(ITM_CAST,
attr,
generator->getSpace());
generator->getExpGenerator()->linkClause(this, conv_clause);
return 0;
}
////////////////////////////////////////////////////////////////////////////
// class RandomSelection
////////////////////////////////////////////////////////////////////////////
short RandomSelection::codeGen(Generator *generator)
{
Attributes **attr;
Space *space = generator->getSpace();
if (generator->getExpGenerator()->genItemExpr(this,
&attr,
(1 + getArity()),
-1
) == 1)
return 0;
ex_clause *function_clause = new (space)
ExFunctionRandomSelection(ITM_RAND_SELECTION,
attr,
space,
getSelProbability()
);
if (function_clause)
generator->getExpGenerator()->linkClause(this, function_clause);
return 0;
}