mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-23 04:43:03 +01:00
Refactor blr_via, blr_from, blr_maximum, blr_minimum, blr_count, blr_average and blr_total
This commit is contained in:
parent
dff60ff120
commit
1d702dae81
@ -1136,8 +1136,13 @@ void ArithmeticNode::getDescDialect1(thread_db* /*tdbb*/, dsc* desc, dsc& desc1,
|
||||
desc->dsc_scale = 0;
|
||||
desc->dsc_sub_type = 0;
|
||||
desc->dsc_flags = 0;
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
if (dtype == dtype_quad)
|
||||
IBERROR(224); // msg 224 quad word arithmetic not supported
|
||||
|
||||
ERR_post(Arg::Gds(isc_datype_notsup)); // data type not supported for arithmetic
|
||||
}
|
||||
|
||||
void ArithmeticNode::getDescDialect3(thread_db* /*tdbb*/, dsc* desc, dsc& desc1, dsc& desc2)
|
||||
@ -1329,6 +1334,7 @@ void ArithmeticNode::getDescDialect3(thread_db* /*tdbb*/, dsc* desc, dsc& desc1,
|
||||
#ifdef NATIVE_QUAD
|
||||
return;
|
||||
#endif
|
||||
|
||||
default:
|
||||
fb_assert(false);
|
||||
// FALLINTO
|
||||
@ -1383,6 +1389,11 @@ void ArithmeticNode::getDescDialect3(thread_db* /*tdbb*/, dsc* desc, dsc& desc1,
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (dtype == dtype_quad)
|
||||
IBERROR(224); // msg 224 quad word arithmetic not supported
|
||||
|
||||
ERR_post(Arg::Gds(isc_datype_notsup)); // data type not supported for arithmetic
|
||||
}
|
||||
|
||||
ValueExprNode* ArithmeticNode::copy(thread_db* tdbb, NodeCopier& copier)
|
||||
@ -1535,11 +1546,13 @@ dsc* ArithmeticNode::add(const dsc* desc, impure_value* value, const jrd_nod* no
|
||||
DEV_BLKCHK(node, type_nod);
|
||||
|
||||
const ArithmeticNode* arithmeticNode = ExprNode::as<ArithmeticNode>(node);
|
||||
const SubQueryNode* subQueryNode = ExprNode::as<SubQueryNode>(node);
|
||||
|
||||
fb_assert(
|
||||
(arithmeticNode && arithmeticNode->dialect1 &&
|
||||
(arithmeticNode->blrOp == blr_add || arithmeticNode->blrOp == blr_subtract)) ||
|
||||
ExprNode::is<AggNode>(node) || node->nod_type == nod_total || node->nod_type == nod_average);
|
||||
ExprNode::is<AggNode>(node) ||
|
||||
(subQueryNode && (subQueryNode->blrOp == blr_total || subQueryNode->blrOp == blr_average)));
|
||||
|
||||
dsc* const result = &value->vlu_desc;
|
||||
|
||||
@ -5890,6 +5903,496 @@ dsc* StrLenNode::execute(thread_db* tdbb, jrd_req* request) const
|
||||
//--------------------
|
||||
|
||||
|
||||
// Only blr_via is generated by DSQL.
|
||||
static RegisterNode<SubQueryNode> regSubQueryNodeVia(blr_via);
|
||||
static RegisterNode<SubQueryNode> regSubQueryNodeFrom(blr_from);
|
||||
static RegisterNode<SubQueryNode> regSubQueryNodeAverage(blr_average);
|
||||
static RegisterNode<SubQueryNode> regSubQueryNodeCount(blr_count);
|
||||
static RegisterNode<SubQueryNode> regSubQueryNodeMaximum(blr_maximum);
|
||||
static RegisterNode<SubQueryNode> regSubQueryNodeMinimum(blr_minimum);
|
||||
static RegisterNode<SubQueryNode> regSubQueryNodeTotal(blr_total);
|
||||
|
||||
SubQueryNode::SubQueryNode(MemoryPool& pool, UCHAR aBlrOp, dsql_nod* aDsqlRse,
|
||||
dsql_nod* aValue1, dsql_nod* aValue2)
|
||||
: TypedNode<ValueExprNode, ExprNode::TYPE_SUBQUERY>(pool),
|
||||
blrOp(aBlrOp),
|
||||
dsqlRse(aDsqlRse),
|
||||
dsqlValue1(aValue1),
|
||||
dsqlValue2(aValue2),
|
||||
value1(NULL),
|
||||
value2(NULL),
|
||||
rsb(NULL)
|
||||
{
|
||||
addChildNode(dsqlRse, rse);
|
||||
addChildNode(dsqlValue1, value1);
|
||||
addChildNode(dsqlValue2, value2);
|
||||
}
|
||||
|
||||
DmlNode* SubQueryNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR blrOp)
|
||||
{
|
||||
// We treat blr_from as blr_via after parse.
|
||||
SubQueryNode* node = FB_NEW(pool) SubQueryNode(pool, (blrOp == blr_from ? blr_via : blrOp));
|
||||
|
||||
node->rse = PAR_parse_node(tdbb, csb, TYPE_RSE);
|
||||
|
||||
if (blrOp != blr_count)
|
||||
node->value1 = PAR_parse_node(tdbb, csb, VALUE);
|
||||
|
||||
if (blrOp == blr_via)
|
||||
node->value2 = PAR_parse_node(tdbb, csb, VALUE);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void SubQueryNode::print(string& text, Array<dsql_nod*>& nodes) const
|
||||
{
|
||||
text = "SubQueryNode";
|
||||
ExprNode::print(text, nodes);
|
||||
}
|
||||
|
||||
ValueExprNode* SubQueryNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
||||
{
|
||||
// This node is created after dsqlPass and should never be called.
|
||||
fb_assert(false);
|
||||
return this;
|
||||
}
|
||||
|
||||
void SubQueryNode::setParameterName(dsql_par* parameter) const
|
||||
{
|
||||
MAKE_parameter_names(parameter, dsqlValue1);
|
||||
}
|
||||
|
||||
void SubQueryNode::genBlr(DsqlCompilerScratch* dsqlScratch)
|
||||
{
|
||||
dsqlScratch->appendUChar(blrOp);
|
||||
GEN_expr(dsqlScratch, dsqlRse);
|
||||
GEN_expr(dsqlScratch, dsqlValue1);
|
||||
GEN_expr(dsqlScratch, dsqlValue2);
|
||||
}
|
||||
|
||||
void SubQueryNode::make(DsqlCompilerScratch* dsqlScratch, dsql_nod* /*thisNode*/, dsc* desc)
|
||||
{
|
||||
MAKE_desc(dsqlScratch, desc, dsqlValue1);
|
||||
|
||||
// Set the descriptor flag as nullable. The select expression may or may not return this row
|
||||
// based on the WHERE clause. Setting this flag warns the client to expect null values.
|
||||
// (bug 10379)
|
||||
desc->dsc_flags |= DSC_nullable;
|
||||
}
|
||||
|
||||
bool SubQueryNode::dsqlAggregateFinder(AggregateFinder& visitor)
|
||||
{
|
||||
return !visitor.ignoreSubSelects && visitor.visit(&dsqlRse);
|
||||
}
|
||||
|
||||
bool SubQueryNode::dsqlAggregate2Finder(Aggregate2Finder& visitor)
|
||||
{
|
||||
return visitor.visit(&dsqlRse); // Pass only the rse.
|
||||
}
|
||||
|
||||
bool SubQueryNode::dsqlSubSelectFinder(SubSelectFinder& visitor)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SubQueryNode::dsqlFieldFinder(FieldFinder& visitor)
|
||||
{
|
||||
return visitor.visit(&dsqlRse); // Pass only the rse.
|
||||
}
|
||||
|
||||
bool SubQueryNode::dsqlFieldRemapper(FieldRemapper& visitor)
|
||||
{
|
||||
visitor.visit(&dsqlRse);
|
||||
dsqlValue1 = dsqlRse->nod_arg[Dsql::e_rse_items]->nod_arg[0];
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SubQueryNode::jrdStreamFinder(StreamFinder& visitor)
|
||||
{
|
||||
if (rse && visitor.visit(rse))
|
||||
return true;
|
||||
|
||||
if (value1 && visitor.visit(value1))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SubQueryNode::jrdStreamsCollector(StreamsCollector& visitor)
|
||||
{
|
||||
visitor.visit(rse);
|
||||
visitor.visit(value1);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SubQueryNode::computable(CompilerScratch* csb, SSHORT stream, bool idxUse, bool allowOnlyCurrentStream)
|
||||
{
|
||||
if (value2 && !OPT_computable(csb, value2, stream, idxUse, allowOnlyCurrentStream))
|
||||
return false;
|
||||
|
||||
fb_assert(rse->nod_type == nod_class_recsrcnode_jrd);
|
||||
RseNode* rseNode = reinterpret_cast<RseNode*>(rse->nod_arg[0]);
|
||||
|
||||
return rseNode->computable(csb, stream, idxUse, allowOnlyCurrentStream, value1);
|
||||
}
|
||||
|
||||
void SubQueryNode::findDependentFromStreams(const OptimizerRetrieval* optRet, SortedStreamList* streamList)
|
||||
{
|
||||
if (value2)
|
||||
optRet->findDependentFromStreams(value2, streamList);
|
||||
|
||||
fb_assert(rse->nod_type == nod_class_recsrcnode_jrd);
|
||||
RseNode* rseNode = reinterpret_cast<RseNode*>(rse->nod_arg[0]);
|
||||
|
||||
rseNode->findDependentFromStreams(optRet, streamList);
|
||||
|
||||
// Check value expression, if any.
|
||||
if (value1)
|
||||
optRet->findDependentFromStreams(value1, streamList);
|
||||
}
|
||||
|
||||
void SubQueryNode::getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc)
|
||||
{
|
||||
if (blrOp == blr_count)
|
||||
desc->makeLong(0);
|
||||
else
|
||||
CMP_get_desc(tdbb, csb, value1, desc);
|
||||
|
||||
if (blrOp == blr_average)
|
||||
{
|
||||
if (!(DTYPE_IS_NUMERIC(desc->dsc_dtype) || DTYPE_IS_TEXT(desc->dsc_dtype)))
|
||||
{
|
||||
if (desc->dsc_dtype != dtype_unknown)
|
||||
return;
|
||||
}
|
||||
|
||||
desc->dsc_dtype = DEFAULT_DOUBLE;
|
||||
desc->dsc_length = sizeof(double);
|
||||
desc->dsc_scale = 0;
|
||||
desc->dsc_sub_type = 0;
|
||||
desc->dsc_flags = 0;
|
||||
}
|
||||
else if (blrOp == blr_total)
|
||||
{
|
||||
USHORT dtype;
|
||||
|
||||
switch ((dtype = desc->dsc_dtype))
|
||||
{
|
||||
case dtype_short:
|
||||
desc->dsc_dtype = dtype_long;
|
||||
desc->dsc_length = sizeof(SLONG);
|
||||
node->nod_scale = desc->dsc_scale;
|
||||
desc->dsc_sub_type = 0;
|
||||
desc->dsc_flags = 0;
|
||||
return;
|
||||
|
||||
case dtype_unknown:
|
||||
desc->dsc_dtype = dtype_unknown;
|
||||
desc->dsc_length = 0;
|
||||
node->nod_scale = 0;
|
||||
desc->dsc_sub_type = 0;
|
||||
desc->dsc_flags = 0;
|
||||
return;
|
||||
|
||||
case dtype_long:
|
||||
case dtype_int64:
|
||||
case dtype_real:
|
||||
case dtype_double:
|
||||
case dtype_text:
|
||||
case dtype_cstring:
|
||||
case dtype_varying:
|
||||
desc->dsc_dtype = DEFAULT_DOUBLE;
|
||||
desc->dsc_length = sizeof(double);
|
||||
desc->dsc_scale = 0;
|
||||
desc->dsc_sub_type = 0;
|
||||
desc->dsc_flags = 0;
|
||||
node->nod_flags |= nod_double;
|
||||
return;
|
||||
|
||||
case dtype_quad:
|
||||
desc->dsc_dtype = dtype_quad;
|
||||
desc->dsc_length = sizeof(SQUAD);
|
||||
desc->dsc_sub_type = 0;
|
||||
desc->dsc_flags = 0;
|
||||
node->nod_scale = desc->dsc_scale;
|
||||
node->nod_flags |= nod_quad;
|
||||
#ifdef NATIVE_QUAD
|
||||
return;
|
||||
#endif
|
||||
|
||||
default:
|
||||
fb_assert(false);
|
||||
// fall into
|
||||
|
||||
case dtype_sql_time:
|
||||
case dtype_sql_date:
|
||||
case dtype_timestamp:
|
||||
case dtype_blob:
|
||||
case dtype_array:
|
||||
case dtype_dbkey:
|
||||
// break to error reporting code
|
||||
break;
|
||||
}
|
||||
|
||||
if (dtype == dtype_quad)
|
||||
IBERROR(224); // msg 224 quad word arithmetic not supported
|
||||
|
||||
ERR_post(Arg::Gds(isc_datype_notsup)); // data type not supported for arithmetic
|
||||
}
|
||||
}
|
||||
|
||||
ValueExprNode* SubQueryNode::copy(thread_db* tdbb, NodeCopier& copier)
|
||||
{
|
||||
SubQueryNode* node = FB_NEW(*tdbb->getDefaultPool()) SubQueryNode(*tdbb->getDefaultPool(), blrOp);
|
||||
node->rse = copier.copy(tdbb, rse);
|
||||
node->value1 = copier.copy(tdbb, value1);
|
||||
node->value2 = copier.copy(tdbb, value2);
|
||||
return node;
|
||||
}
|
||||
|
||||
bool SubQueryNode::expressionEqual(thread_db* tdbb, CompilerScratch* csb, /*const*/ ExprNode* other,
|
||||
USHORT stream)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ExprNode* SubQueryNode::pass1(thread_db* tdbb, CompilerScratch* csb)
|
||||
{
|
||||
fb_assert(rse->nod_type == nod_class_recsrcnode_jrd);
|
||||
RseNode* rseNode = reinterpret_cast<RseNode*>(rse->nod_arg[0]);
|
||||
fb_assert(rseNode->type == RseNode::TYPE);
|
||||
|
||||
rseNode->ignoreDbKey(tdbb, csb, csb->csb_view);
|
||||
rseNode->pass1(tdbb, csb, csb->csb_view);
|
||||
|
||||
csb->csb_current_nodes.push(rseNode);
|
||||
|
||||
value1 = CMP_pass1(tdbb, csb, value1);
|
||||
value2 = CMP_pass1(tdbb, csb, value2);
|
||||
|
||||
csb->csb_current_nodes.pop();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
ExprNode* SubQueryNode::pass2(thread_db* tdbb, CompilerScratch* csb)
|
||||
{
|
||||
fb_assert(rse->nod_type == nod_class_recsrcnode_jrd);
|
||||
RseNode* rseNode = reinterpret_cast<RseNode*>(rse->nod_arg[0]);
|
||||
|
||||
if (!rseNode)
|
||||
ERR_post(Arg::Gds(isc_wish_list));
|
||||
|
||||
fb_assert(rseNode->type == RseNode::TYPE);
|
||||
|
||||
if (!(rseNode->flags & RseNode::FLAG_VARIANT))
|
||||
{
|
||||
node->nod_flags |= nod_invariant;
|
||||
csb->csb_invariants.push(&node->nod_impure);
|
||||
}
|
||||
|
||||
rseNode->pass2Rse(tdbb, csb);
|
||||
|
||||
ExprNode::pass2(tdbb, csb);
|
||||
|
||||
node->nod_impure = CMP_impure(csb, sizeof(impure_value_ex));
|
||||
|
||||
if (blrOp == blr_average)
|
||||
node->nod_flags |= nod_double;
|
||||
else if (blrOp == blr_total)
|
||||
{
|
||||
dsc desc;
|
||||
getDesc(tdbb, csb, &desc);
|
||||
}
|
||||
|
||||
// Bind values of invariant nodes to top-level RSE (if present).
|
||||
if ((node->nod_flags & nod_invariant) && csb->csb_current_nodes.hasData())
|
||||
{
|
||||
LegacyNodeOrRseNode& topRseNode = csb->csb_current_nodes[0];
|
||||
fb_assert(topRseNode.rseNode);
|
||||
|
||||
if (!topRseNode.rseNode->rse_invariants)
|
||||
{
|
||||
topRseNode.rseNode->rse_invariants =
|
||||
FB_NEW(*tdbb->getDefaultPool()) VarInvariantArray(*tdbb->getDefaultPool());
|
||||
}
|
||||
|
||||
topRseNode.rseNode->rse_invariants->add(node->nod_impure);
|
||||
}
|
||||
|
||||
// Finish up processing of record selection expressions.
|
||||
|
||||
rsb = CMP_post_rse(tdbb, csb, rseNode);
|
||||
csb->csb_fors.add(rsb);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
// Evaluate a subquery expression.
|
||||
dsc* SubQueryNode::execute(thread_db* tdbb, jrd_req* request) const
|
||||
{
|
||||
impure_value* impure = request->getImpure<impure_value>(node->nod_impure);
|
||||
request->req_flags &= ~req_null;
|
||||
|
||||
dsc* desc = &impure->vlu_desc;
|
||||
USHORT* invariant_flags;
|
||||
|
||||
if (node->nod_flags & nod_invariant)
|
||||
{
|
||||
invariant_flags = &impure->vlu_flags;
|
||||
|
||||
if (*invariant_flags & VLU_computed)
|
||||
{
|
||||
// An invariant node has already been computed.
|
||||
|
||||
if (*invariant_flags & VLU_null)
|
||||
request->req_flags |= req_null;
|
||||
else
|
||||
request->req_flags &= ~req_null;
|
||||
|
||||
return desc;
|
||||
}
|
||||
}
|
||||
|
||||
impure->vlu_misc.vlu_long = 0;
|
||||
impure->vlu_desc.dsc_dtype = dtype_long;
|
||||
impure->vlu_desc.dsc_length = sizeof(SLONG);
|
||||
impure->vlu_desc.dsc_address = (UCHAR*) &impure->vlu_misc.vlu_long;
|
||||
|
||||
ULONG flag = req_null;
|
||||
|
||||
try
|
||||
{
|
||||
rsb->open(tdbb);
|
||||
|
||||
SLONG count = 0;
|
||||
double d;
|
||||
|
||||
// Handle each variety separately
|
||||
switch (blrOp)
|
||||
{
|
||||
case blr_count:
|
||||
flag = 0;
|
||||
while (rsb->getRecord(tdbb))
|
||||
++impure->vlu_misc.vlu_long;
|
||||
break;
|
||||
|
||||
case blr_minimum:
|
||||
case blr_maximum:
|
||||
while (rsb->getRecord(tdbb))
|
||||
{
|
||||
dsc* value = EVL_expr(tdbb, value1);
|
||||
if (request->req_flags & req_null)
|
||||
continue;
|
||||
|
||||
int result;
|
||||
|
||||
if (flag || ((result = MOV_compare(value, desc)) < 0 && blrOp == blr_minimum) ||
|
||||
(blrOp != blr_minimum && result > 0))
|
||||
{
|
||||
flag = 0;
|
||||
EVL_make_value(tdbb, value, impure);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case blr_average: // total or average with dialect-1 semantics
|
||||
case blr_total:
|
||||
while (rsb->getRecord(tdbb))
|
||||
{
|
||||
desc = EVL_expr(tdbb, value1);
|
||||
if (request->req_flags & req_null)
|
||||
continue;
|
||||
|
||||
// Note: if the field being SUMed or AVERAGEd is short or long,
|
||||
// impure will stay long, and the first add() will
|
||||
// set the correct scale; if it is approximate numeric,
|
||||
// the first add() will convert impure to double.
|
||||
ArithmeticNode::add(desc, impure, node, blr_add);
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
desc = &impure->vlu_desc;
|
||||
|
||||
if (blrOp == blr_total)
|
||||
{
|
||||
flag = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!count)
|
||||
break;
|
||||
|
||||
d = MOV_get_double(&impure->vlu_desc);
|
||||
impure->vlu_misc.vlu_double = d / count;
|
||||
impure->vlu_desc.dsc_dtype = DEFAULT_DOUBLE;
|
||||
impure->vlu_desc.dsc_length = sizeof(double);
|
||||
impure->vlu_desc.dsc_scale = 0;
|
||||
flag = 0;
|
||||
break;
|
||||
|
||||
case blr_via:
|
||||
if (rsb->getRecord(tdbb))
|
||||
desc = EVL_expr(tdbb, value1);
|
||||
else
|
||||
{
|
||||
if (value2)
|
||||
desc = EVL_expr(tdbb, value2);
|
||||
else
|
||||
ERR_post(Arg::Gds(isc_from_no_match));
|
||||
}
|
||||
|
||||
flag = request->req_flags;
|
||||
break;
|
||||
|
||||
default:
|
||||
BUGCHECK(233); // msg 233 eval_statistical: invalid operation
|
||||
}
|
||||
}
|
||||
catch (const Exception&)
|
||||
{
|
||||
// Close stream, ignoring any error during it to keep the original error.
|
||||
try
|
||||
{
|
||||
rsb->close(tdbb);
|
||||
request->req_flags &= ~req_null;
|
||||
request->req_flags |= flag;
|
||||
}
|
||||
catch (const Exception&)
|
||||
{
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
// Close stream and return value.
|
||||
|
||||
rsb->close(tdbb);
|
||||
request->req_flags &= ~req_null;
|
||||
request->req_flags |= flag;
|
||||
|
||||
// If this is an invariant node, save the return value. If the descriptor does not point to the
|
||||
// impure area for this node then point this node's descriptor to the correct place;
|
||||
// Copy the whole structure to be absolutely sure.
|
||||
|
||||
if (node->nod_flags & nod_invariant)
|
||||
{
|
||||
*invariant_flags |= VLU_computed;
|
||||
|
||||
if (request->req_flags & req_null)
|
||||
*invariant_flags |= VLU_null;
|
||||
if (desc && (desc != &impure->vlu_desc))
|
||||
impure->vlu_desc = *desc;
|
||||
}
|
||||
|
||||
return (request->req_flags & req_null) ? NULL : desc;
|
||||
}
|
||||
|
||||
|
||||
//--------------------
|
||||
|
||||
|
||||
static RegisterNode<SubstringNode> regSubstringNode(blr_substring);
|
||||
|
||||
SubstringNode::SubstringNode(MemoryPool& pool, dsql_nod* aExpr, dsql_nod* aStart, dsql_nod* aLength)
|
||||
|
@ -32,6 +32,7 @@ class SysFunction;
|
||||
namespace Jrd {
|
||||
|
||||
struct ItemInfo;
|
||||
class RecordSource;
|
||||
|
||||
|
||||
class ArithmeticNode : public TypedNode<ValueExprNode, ExprNode::TYPE_ARITHMETIC>
|
||||
@ -619,6 +620,71 @@ public:
|
||||
};
|
||||
|
||||
|
||||
// This node is used for DSQL subqueries and for legacy (BLR-only) functionality.
|
||||
class SubQueryNode : public TypedNode<ValueExprNode, ExprNode::TYPE_SUBQUERY>
|
||||
{
|
||||
public:
|
||||
explicit SubQueryNode(MemoryPool& pool, UCHAR aBlrOp, dsql_nod* aDsqlRse = NULL,
|
||||
dsql_nod* aValue1 = NULL, dsql_nod* aValue2 = NULL);
|
||||
|
||||
static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR blrOp);
|
||||
|
||||
virtual void print(Firebird::string& text, Firebird::Array<dsql_nod*>& nodes) const;
|
||||
virtual ValueExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch);
|
||||
virtual void setParameterName(dsql_par* parameter) const;
|
||||
virtual void genBlr(DsqlCompilerScratch* dsqlScratch);
|
||||
virtual void make(DsqlCompilerScratch* dsqlScratch, dsql_nod* thisNode, dsc* desc);
|
||||
|
||||
virtual bool dsqlAggregateFinder(AggregateFinder& visitor);
|
||||
virtual bool dsqlAggregate2Finder(Aggregate2Finder& visitor);
|
||||
virtual bool dsqlSubSelectFinder(SubSelectFinder& visitor);
|
||||
virtual bool dsqlFieldFinder(FieldFinder& visitor);
|
||||
virtual bool dsqlFieldRemapper(FieldRemapper& visitor);
|
||||
|
||||
virtual bool jrdVisit(JrdNodeVisitor& visitor)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool jrdUnmappedNodeGetter(UnmappedNodeGetter& visitor)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool jrdPossibleUnknownFinder(PossibleUnknownFinder& /*visitor*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool jrdStreamFinder(StreamFinder& visitor);
|
||||
virtual bool jrdStreamsCollector(StreamsCollector& visitor);
|
||||
|
||||
virtual bool computable(CompilerScratch* csb, SSHORT stream, bool idxUse,
|
||||
bool allowOnlyCurrentStream);
|
||||
|
||||
virtual void findDependentFromStreams(const OptimizerRetrieval* optRet,
|
||||
SortedStreamList* streamList);
|
||||
|
||||
virtual void getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc);
|
||||
virtual ValueExprNode* copy(thread_db* tdbb, NodeCopier& copier);
|
||||
virtual bool expressionEqual(thread_db* tdbb, CompilerScratch* csb, /*const*/ ExprNode* other,
|
||||
USHORT stream) /*const*/;
|
||||
virtual ExprNode* pass1(thread_db* tdbb, CompilerScratch* csb);
|
||||
virtual ExprNode* pass2(thread_db* tdbb, CompilerScratch* csb);
|
||||
virtual dsc* execute(thread_db* tdbb, jrd_req* request) const;
|
||||
|
||||
public:
|
||||
UCHAR blrOp;
|
||||
dsql_nod* dsqlRse;
|
||||
dsql_nod* dsqlValue1;
|
||||
dsql_nod* dsqlValue2;
|
||||
NestConst<jrd_nod> rse;
|
||||
NestConst<jrd_nod> value1;
|
||||
NestConst<jrd_nod> value2;
|
||||
NestConst<RecordSource> rsb;
|
||||
};
|
||||
|
||||
|
||||
class SubstringNode : public TypedNode<ValueExprNode, ExprNode::TYPE_SUBSTRING>
|
||||
{
|
||||
public:
|
||||
|
@ -278,6 +278,7 @@ public:
|
||||
TYPE_RSE_BOOL,
|
||||
TYPE_STR_CASE,
|
||||
TYPE_STR_LEN,
|
||||
TYPE_SUBQUERY,
|
||||
TYPE_SUBSTRING,
|
||||
TYPE_SUBSTRING_SIMILAR,
|
||||
TYPE_SYSFUNC_CALL,
|
||||
|
@ -384,7 +384,6 @@ public:
|
||||
return StreamFinder(csb, stream).visit(node);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool visit(const JrdNode& node);
|
||||
|
||||
private:
|
||||
@ -404,7 +403,6 @@ public:
|
||||
return StreamsCollector(streams).visit(node);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool visit(const JrdNode& node);
|
||||
|
||||
private:
|
||||
|
@ -270,10 +270,6 @@ void GEN_expr(DsqlCompilerScratch* dsqlScratch, dsql_nod* node)
|
||||
GEN_rse(dsqlScratch, node->nod_arg[e_derived_table_rse]);
|
||||
return;
|
||||
|
||||
case nod_via:
|
||||
blr_operator = blr_via;
|
||||
break;
|
||||
|
||||
case nod_coalesce:
|
||||
gen_coalesce(dsqlScratch, node);
|
||||
return;
|
||||
|
@ -478,17 +478,6 @@ void MAKE_desc(DsqlCompilerScratch* dsqlScratch, dsc* desc, dsql_nod* node)
|
||||
}
|
||||
return;
|
||||
|
||||
case nod_via:
|
||||
MAKE_desc(dsqlScratch, desc, node->nod_arg[e_via_value_1]);
|
||||
// Set the descriptor flag as nullable. The
|
||||
// select expression may or may not return
|
||||
// this row based on the WHERE clause. Setting this
|
||||
// flag warns the client to expect null values.
|
||||
// (bug 10379)
|
||||
|
||||
desc->dsc_flags |= DSC_nullable;
|
||||
return;
|
||||
|
||||
case nod_hidden_var:
|
||||
MAKE_desc(dsqlScratch, desc, node->nod_arg[e_hidden_var_expr]);
|
||||
return;
|
||||
@ -962,10 +951,6 @@ void MAKE_parameter_names(dsql_par* parameter, const dsql_nod* item)
|
||||
context = (dsql_ctx*) alias->nod_arg[0]->nod_arg[0];
|
||||
}
|
||||
break;
|
||||
case nod_via:
|
||||
// subquery, aka sub-select
|
||||
MAKE_parameter_names(parameter, item->nod_arg[e_via_value_1]);
|
||||
break;
|
||||
case nod_derived_field:
|
||||
string = (dsql_str*) item->nod_arg[e_derived_field_name];
|
||||
parameter->par_alias = string->str_data;
|
||||
|
@ -122,7 +122,6 @@ enum nod_t
|
||||
nod_flag,
|
||||
nod_join,
|
||||
nod_unique,
|
||||
nod_via,
|
||||
nod_field,
|
||||
nod_dom_value,
|
||||
nod_field_name,
|
||||
@ -492,11 +491,6 @@ enum node_args {
|
||||
e_join_boolean,
|
||||
e_join_count,
|
||||
|
||||
e_via_rse = 0, // nod_via
|
||||
e_via_value_1,
|
||||
e_via_value_2,
|
||||
e_via_count,
|
||||
|
||||
e_while_cond = 0, // nod_while
|
||||
e_while_action,
|
||||
e_while_label,
|
||||
|
@ -373,11 +373,6 @@ bool AggregateFinder::internalVisit(const dsql_nod* node)
|
||||
return visit(&lmap->map_node);
|
||||
}
|
||||
|
||||
case nod_via:
|
||||
if (!ignoreSubSelects)
|
||||
aggregate = visit(&node->nod_arg[e_via_rse]);
|
||||
return aggregate;
|
||||
|
||||
case nod_rse:
|
||||
++currentLevel;
|
||||
aggregate |= visit(&node->nod_arg[e_rse_streams]);
|
||||
@ -468,11 +463,6 @@ bool Aggregate2Finder::internalVisit(const dsql_nod* node)
|
||||
break;
|
||||
}
|
||||
|
||||
case nod_via:
|
||||
// Pass only the rse from the nod_via
|
||||
found |= visit(&node->nod_arg[e_via_rse]);
|
||||
break;
|
||||
|
||||
case nod_rse:
|
||||
{
|
||||
AutoSetRestore<bool> autoCurrentScopeLevelEqual(¤tScopeLevelEqual, false);
|
||||
@ -544,11 +534,6 @@ bool FieldFinder::internalVisit(const dsql_nod* node)
|
||||
break;
|
||||
}
|
||||
|
||||
case nod_via:
|
||||
// Pass only the rse from the nod_via
|
||||
found |= visit(&node->nod_arg[e_via_rse]);
|
||||
break;
|
||||
|
||||
case nod_rse:
|
||||
// Pass rse_boolean (where clause) and rse_items (select items)
|
||||
found |= visit(&node->nod_arg[e_rse_boolean]);
|
||||
@ -743,14 +728,6 @@ bool InvalidReferenceFinder::internalVisit(const dsql_nod* node)
|
||||
}
|
||||
break;
|
||||
|
||||
case nod_via:
|
||||
{
|
||||
const dsql_nod* const* ptr = node->nod_arg;
|
||||
for (const dsql_nod* const* const end = ptr + node->nod_count; ptr < end; ptr++)
|
||||
invalid |= visit(ptr);
|
||||
break;
|
||||
}
|
||||
|
||||
case nod_coalesce:
|
||||
case nod_unique:
|
||||
case nod_rse:
|
||||
@ -864,11 +841,6 @@ bool FieldRemapper::internalVisit(dsql_nod* node)
|
||||
break;
|
||||
}
|
||||
|
||||
case nod_via:
|
||||
visit(&node->nod_arg[e_via_rse]);
|
||||
node->nod_arg[e_via_value_1] = node->nod_arg[e_via_rse]->nod_arg[e_rse_items]->nod_arg[0];
|
||||
break;
|
||||
|
||||
case nod_rse:
|
||||
{
|
||||
AutoSetRestore<USHORT> autoCurrentLevel(¤tLevel, currentLevel + 1);
|
||||
@ -944,9 +916,6 @@ bool SubSelectFinder::internalVisit(const dsql_nod* node)
|
||||
break;
|
||||
}
|
||||
|
||||
case nod_via:
|
||||
return true;
|
||||
|
||||
case nod_aggregate:
|
||||
case nod_map:
|
||||
|
||||
@ -1293,17 +1262,20 @@ dsql_nod* PASS1_node(DsqlCompilerScratch* dsqlScratch, dsql_nod* input)
|
||||
case nod_select_expr:
|
||||
{
|
||||
const DsqlContextStack::iterator base(*dsqlScratch->context);
|
||||
node = MAKE_node(nod_via, e_via_count);
|
||||
dsql_nod* rse = PASS1_rse(dsqlScratch, input, NULL);
|
||||
node->nod_arg[e_via_rse] = rse;
|
||||
node->nod_arg[e_via_value_1] = rse->nod_arg[e_rse_items]->nod_arg[0];
|
||||
|
||||
node->nod_arg[e_via_value_2] = MAKE_node(nod_class_exprnode, 1);
|
||||
node->nod_arg[e_via_value_2]->nod_arg[0] = reinterpret_cast<dsql_nod*>(
|
||||
dsql_nod* rse = PASS1_rse(dsqlScratch, input, NULL);
|
||||
|
||||
SubQueryNode* subQueryNode = FB_NEW(*tdbb->getDefaultPool()) SubQueryNode(*tdbb->getDefaultPool(),
|
||||
blr_via, rse, rse->nod_arg[e_rse_items]->nod_arg[0], MAKE_node(nod_class_exprnode, 1));
|
||||
subQueryNode->dsqlValue2->nod_arg[0] = reinterpret_cast<dsql_nod*>(
|
||||
FB_NEW(*tdbb->getDefaultPool()) NullNode(*tdbb->getDefaultPool()));
|
||||
|
||||
// Finish off by cleaning up contexts
|
||||
dsqlScratch->context->clear(base);
|
||||
|
||||
node = MAKE_node(nod_class_exprnode, 1);
|
||||
node->nod_arg[0] = reinterpret_cast<dsql_nod*>(subQueryNode);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
@ -5405,19 +5377,24 @@ static dsql_nod* pass1_make_derived_field(DsqlCompilerScratch* dsqlScratch, thre
|
||||
return select_item;
|
||||
}
|
||||
|
||||
case nod_via:
|
||||
case nod_class_exprnode:
|
||||
{
|
||||
SubQueryNode* subQueryNode;
|
||||
|
||||
if ((subQueryNode = ExprNode::as<SubQueryNode>(select_item)))
|
||||
{
|
||||
// Try to generate derived field from sub-select
|
||||
dsql_nod* derived_field = pass1_make_derived_field(dsqlScratch, tdbb,
|
||||
select_item->nod_arg[e_via_value_1]);
|
||||
subQueryNode->dsqlValue1);
|
||||
|
||||
if (derived_field->nod_type == nod_derived_field)
|
||||
{
|
||||
derived_field->nod_arg[e_derived_field_value] = select_item;
|
||||
return derived_field;
|
||||
}
|
||||
}
|
||||
|
||||
return select_item;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
@ -8819,9 +8796,6 @@ void DSQL_pretty(const dsql_nod* node, int column)
|
||||
case nod_unique:
|
||||
verb = "unique";
|
||||
break;
|
||||
case nod_via:
|
||||
verb = "via";
|
||||
break;
|
||||
|
||||
case nod_coalesce:
|
||||
verb = "coalesce";
|
||||
|
@ -175,28 +175,6 @@ bool OPT_computable(CompilerScratch* csb, jrd_nod* node, SSHORT stream,
|
||||
return false;
|
||||
}
|
||||
return csb->csb_rpt[n].csb_flags & csb_active;
|
||||
|
||||
case nod_min:
|
||||
case nod_max:
|
||||
case nod_average:
|
||||
case nod_total:
|
||||
case nod_count:
|
||||
case nod_from:
|
||||
{
|
||||
jrd_nod* sub;
|
||||
|
||||
if ((sub = node->nod_arg[e_stat_default]) &&
|
||||
!OPT_computable(csb, sub, stream, idx_use, allowOnlyCurrentStream))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
fb_assert(node->nod_arg[e_stat_rse]->nod_type == nod_class_recsrcnode_jrd);
|
||||
RseNode* rse = reinterpret_cast<RseNode*>(node->nod_arg[e_stat_rse]->nod_arg[0]);
|
||||
|
||||
return rse->computable(csb, stream, idx_use, allowOnlyCurrentStream,
|
||||
node->nod_arg[e_stat_value]);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -787,32 +765,6 @@ void OptimizerRetrieval::findDependentFromStreams(jrd_nod* node, SortedStreamLis
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
case nod_min:
|
||||
case nod_max:
|
||||
case nod_average:
|
||||
case nod_total:
|
||||
case nod_count:
|
||||
case nod_from:
|
||||
{
|
||||
jrd_nod* sub;
|
||||
|
||||
if (sub = node->nod_arg[e_stat_default])
|
||||
findDependentFromStreams(sub, streamList);
|
||||
|
||||
fb_assert(node->nod_arg[e_stat_rse]->nod_type == nod_class_recsrcnode_jrd);
|
||||
RseNode* rse = reinterpret_cast<RseNode*>(node->nod_arg[e_stat_rse]->nod_arg[0]);
|
||||
|
||||
rse->findDependentFromStreams(this, streamList);
|
||||
|
||||
jrd_nod* value = node->nod_arg[e_stat_value];
|
||||
|
||||
// Check value expression, if any
|
||||
if (value)
|
||||
findDependentFromStreams(value, streamList);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
169
src/jrd/cmp.cpp
169
src/jrd/cmp.cpp
@ -412,83 +412,6 @@ void CMP_get_desc(thread_db* tdbb, CompilerScratch* csb, jrd_nod* node, DSC* des
|
||||
|
||||
switch (node->nod_type)
|
||||
{
|
||||
case nod_max:
|
||||
case nod_min:
|
||||
case nod_from:
|
||||
CMP_get_desc(tdbb, csb, node->nod_arg[e_stat_value], desc);
|
||||
return;
|
||||
|
||||
case nod_total:
|
||||
if (node->nod_type == nod_total)
|
||||
CMP_get_desc(tdbb, csb, node->nod_arg[e_stat_value], desc);
|
||||
else
|
||||
CMP_get_desc(tdbb, csb, node->nod_arg[0], desc);
|
||||
switch (dtype = desc->dsc_dtype)
|
||||
{
|
||||
case dtype_short:
|
||||
desc->dsc_dtype = dtype_long;
|
||||
desc->dsc_length = sizeof(SLONG);
|
||||
node->nod_scale = desc->dsc_scale;
|
||||
desc->dsc_sub_type = 0;
|
||||
desc->dsc_flags = 0;
|
||||
return;
|
||||
|
||||
case dtype_unknown:
|
||||
desc->dsc_dtype = dtype_unknown;
|
||||
desc->dsc_length = 0;
|
||||
node->nod_scale = 0;
|
||||
desc->dsc_sub_type = 0;
|
||||
desc->dsc_flags = 0;
|
||||
return;
|
||||
|
||||
case dtype_long:
|
||||
case dtype_int64:
|
||||
case dtype_real:
|
||||
case dtype_double:
|
||||
case dtype_text:
|
||||
case dtype_cstring:
|
||||
case dtype_varying:
|
||||
desc->dsc_dtype = DEFAULT_DOUBLE;
|
||||
desc->dsc_length = sizeof(double);
|
||||
desc->dsc_scale = 0;
|
||||
desc->dsc_sub_type = 0;
|
||||
desc->dsc_flags = 0;
|
||||
node->nod_flags |= nod_double;
|
||||
return;
|
||||
|
||||
case dtype_quad:
|
||||
desc->dsc_dtype = dtype_quad;
|
||||
desc->dsc_length = sizeof(SQUAD);
|
||||
desc->dsc_sub_type = 0;
|
||||
desc->dsc_flags = 0;
|
||||
node->nod_scale = desc->dsc_scale;
|
||||
node->nod_flags |= nod_quad;
|
||||
#ifdef NATIVE_QUAD
|
||||
return;
|
||||
#endif
|
||||
|
||||
default:
|
||||
fb_assert(false);
|
||||
// FALLINTO
|
||||
case dtype_sql_time:
|
||||
case dtype_sql_date:
|
||||
case dtype_timestamp:
|
||||
case dtype_blob:
|
||||
case dtype_array:
|
||||
case dtype_dbkey:
|
||||
// break to error reporting code
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case nod_count:
|
||||
desc->dsc_dtype = dtype_long;
|
||||
desc->dsc_length = sizeof(SLONG);
|
||||
desc->dsc_scale = 0;
|
||||
desc->dsc_sub_type = 0;
|
||||
desc->dsc_flags = 0;
|
||||
return;
|
||||
|
||||
case nod_field:
|
||||
{
|
||||
const USHORT stream = (USHORT) (IPTR) node->nod_arg[e_fld_stream];
|
||||
@ -544,22 +467,6 @@ void CMP_get_desc(thread_db* tdbb, CompilerScratch* csb, jrd_nod* node, DSC* des
|
||||
return;
|
||||
}
|
||||
|
||||
case nod_average:
|
||||
CMP_get_desc(tdbb, csb, node->nod_arg[e_stat_value], desc);
|
||||
|
||||
if (!(DTYPE_IS_NUMERIC(desc->dsc_dtype) || DTYPE_IS_TEXT(desc->dsc_dtype)))
|
||||
{
|
||||
if (desc->dsc_dtype != dtype_unknown)
|
||||
break;
|
||||
}
|
||||
|
||||
desc->dsc_dtype = DEFAULT_DOUBLE;
|
||||
desc->dsc_length = sizeof(double);
|
||||
desc->dsc_scale = 0;
|
||||
desc->dsc_sub_type = 0;
|
||||
desc->dsc_flags = 0;
|
||||
return;
|
||||
|
||||
case nod_class_exprnode_jrd:
|
||||
{
|
||||
ValueExprNode* exprNode = reinterpret_cast<ValueExprNode*>(node->nod_arg[0]);
|
||||
@ -1125,15 +1032,6 @@ jrd_nod* NodeCopier::copy(thread_db* tdbb, jrd_nod* input)
|
||||
return node;
|
||||
}
|
||||
|
||||
case nod_count:
|
||||
case nod_max:
|
||||
case nod_min:
|
||||
case nod_total:
|
||||
case nod_average:
|
||||
case nod_from:
|
||||
args = e_stat_length;
|
||||
break;
|
||||
|
||||
case nod_class_recsrcnode_jrd:
|
||||
node = PAR_make_node(tdbb, 1);
|
||||
node->nod_type = input->nod_type;
|
||||
@ -1895,25 +1793,6 @@ jrd_nod* CMP_pass1(thread_db* tdbb, CompilerScratch* csb, jrd_nod* node)
|
||||
node->nod_arg[e_cursor_stmt_into] = CMP_pass1(tdbb, csb, node->nod_arg[e_cursor_stmt_into]);
|
||||
break;
|
||||
|
||||
case nod_max:
|
||||
case nod_min:
|
||||
case nod_average:
|
||||
case nod_from:
|
||||
case nod_count:
|
||||
case nod_total:
|
||||
{
|
||||
fb_assert(node->nod_arg[e_stat_rse]->nod_type == nod_class_recsrcnode_jrd);
|
||||
RseNode* rseNode = reinterpret_cast<RseNode*>(node->nod_arg[e_stat_rse]->nod_arg[0]);
|
||||
fb_assert(rseNode->type == RseNode::TYPE);
|
||||
rseNode->ignoreDbKey(tdbb, csb, view);
|
||||
rseNode->pass1(tdbb, csb, csb->csb_view);
|
||||
csb->csb_current_nodes.push(rseNode);
|
||||
node->nod_arg[e_stat_value] = CMP_pass1(tdbb, csb, node->nod_arg[e_stat_value]);
|
||||
node->nod_arg[e_stat_default] = CMP_pass1(tdbb, csb, node->nod_arg[e_stat_default]);
|
||||
csb->csb_current_nodes.pop();
|
||||
}
|
||||
return node;
|
||||
|
||||
case nod_class_recsrcnode_jrd:
|
||||
reinterpret_cast<RecordSourceNode*>(node->nod_arg[0])->pass1(tdbb, csb, view);
|
||||
break;
|
||||
@ -2719,7 +2598,6 @@ jrd_nod* CMP_pass2(thread_db* tdbb, CompilerScratch* csb, jrd_nod* const node, j
|
||||
|
||||
DEBUG;
|
||||
RseNode* rse_node = NULL;
|
||||
RecordSource** rsb_ptr = NULL;
|
||||
Cursor** cursor_ptr = NULL;
|
||||
|
||||
switch (node->nod_type)
|
||||
@ -2740,29 +2618,6 @@ jrd_nod* CMP_pass2(thread_db* tdbb, CompilerScratch* csb, jrd_nod* const node, j
|
||||
CMP_pass2(tdbb, csb, node->nod_arg[e_cursor_stmt_into], node);
|
||||
break;
|
||||
|
||||
case nod_max:
|
||||
case nod_min:
|
||||
case nod_count:
|
||||
case nod_average:
|
||||
case nod_total:
|
||||
case nod_from:
|
||||
fb_assert(node->nod_arg[e_stat_rse]->nod_type == nod_class_recsrcnode_jrd);
|
||||
rse_node = reinterpret_cast<RseNode*>(node->nod_arg[e_stat_rse]->nod_arg[0]);
|
||||
|
||||
if (!rse_node)
|
||||
ERR_post(Arg::Gds(isc_wish_list));
|
||||
|
||||
fb_assert(rse_node->type == RseNode::TYPE);
|
||||
|
||||
if (!(rse_node->flags & RseNode::FLAG_VARIANT))
|
||||
{
|
||||
node->nod_flags |= nod_invariant;
|
||||
csb->csb_invariants.push(&node->nod_impure);
|
||||
}
|
||||
|
||||
rsb_ptr = (RecordSource**) &node->nod_arg[e_stat_rsb];
|
||||
break;
|
||||
|
||||
case nod_src_info:
|
||||
node->nod_arg[e_src_info_node] = CMP_pass2(tdbb, csb, node->nod_arg[e_src_info_node], node);
|
||||
return node;
|
||||
@ -2839,18 +2694,6 @@ jrd_nod* CMP_pass2(thread_db* tdbb, CompilerScratch* csb, jrd_nod* const node, j
|
||||
CMP_pass2(tdbb, csb, node->nod_arg[e_asgn_missing2], node);
|
||||
break;
|
||||
|
||||
case nod_average:
|
||||
node->nod_flags |= nod_double;
|
||||
// FALL INTO
|
||||
|
||||
case nod_max:
|
||||
case nod_min:
|
||||
case nod_from:
|
||||
case nod_count:
|
||||
node->nod_count = 0;
|
||||
node->nod_impure = CMP_impure(csb, sizeof(impure_value_ex));
|
||||
break;
|
||||
|
||||
case nod_block:
|
||||
node->nod_impure = CMP_impure(csb, sizeof(SLONG));
|
||||
break;
|
||||
@ -2862,15 +2705,6 @@ jrd_nod* CMP_pass2(thread_db* tdbb, CompilerScratch* csb, jrd_nod* const node, j
|
||||
}
|
||||
break;
|
||||
|
||||
case nod_total:
|
||||
{
|
||||
node->nod_count = 0;
|
||||
node->nod_impure = CMP_impure(csb, sizeof(impure_value_ex));
|
||||
dsc descriptor_a;
|
||||
CMP_get_desc(tdbb, csb, node, &descriptor_a);
|
||||
}
|
||||
break;
|
||||
|
||||
case nod_message:
|
||||
{
|
||||
const Format* format = (Format*) node->nod_arg[e_msg_format];
|
||||
@ -2992,9 +2826,6 @@ jrd_nod* CMP_pass2(thread_db* tdbb, CompilerScratch* csb, jrd_nod* const node, j
|
||||
|
||||
csb->csb_fors.add(rsb);
|
||||
|
||||
if (rsb_ptr)
|
||||
*rsb_ptr = rsb;
|
||||
|
||||
if (cursor_ptr)
|
||||
{
|
||||
Cursor* const cursor = FB_NEW(*tdbb->getDefaultPool()) Cursor(
|
||||
|
182
src/jrd/evl.cpp
182
src/jrd/evl.cpp
@ -119,7 +119,6 @@ using namespace Jrd;
|
||||
using namespace Firebird;
|
||||
|
||||
static dsc* dbkey(thread_db*, const jrd_nod*, impure_value*);
|
||||
static dsc* eval_statistical(thread_db*, const jrd_nod*, impure_value*);
|
||||
static dsc* record_version(thread_db*, const jrd_nod*, impure_value*);
|
||||
static dsc* scalar(thread_db*, const jrd_nod*, impure_value*);
|
||||
|
||||
@ -462,14 +461,6 @@ dsc* EVL_expr(thread_db* tdbb, const jrd_nod* node)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
case nod_max:
|
||||
case nod_min:
|
||||
case nod_count:
|
||||
case nod_average:
|
||||
case nod_total:
|
||||
case nod_from:
|
||||
return eval_statistical(tdbb, node, impure);
|
||||
|
||||
case nod_scalar:
|
||||
return scalar(tdbb, node, impure);
|
||||
|
||||
@ -864,179 +855,6 @@ static dsc* dbkey(thread_db* tdbb, const jrd_nod* node, impure_value* impure)
|
||||
}
|
||||
|
||||
|
||||
static dsc* eval_statistical(thread_db* tdbb, const jrd_nod* node, impure_value* impure)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* e v a l _ s t a t i s t i c a l
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Evaluate a statistical expression.
|
||||
*
|
||||
**************************************/
|
||||
USHORT* invariant_flags;
|
||||
|
||||
SET_TDBB(tdbb);
|
||||
|
||||
DEV_BLKCHK(node, type_nod);
|
||||
|
||||
// Get started by opening stream
|
||||
|
||||
jrd_req* request = tdbb->getRequest();
|
||||
dsc* desc = &impure->vlu_desc;
|
||||
|
||||
if (node->nod_flags & nod_invariant)
|
||||
{
|
||||
invariant_flags = &impure->vlu_flags;
|
||||
if (*invariant_flags & VLU_computed)
|
||||
{
|
||||
// An invariant node has already been computed.
|
||||
|
||||
if (*invariant_flags & VLU_null)
|
||||
request->req_flags |= req_null;
|
||||
else
|
||||
request->req_flags &= ~req_null;
|
||||
return desc;
|
||||
}
|
||||
}
|
||||
|
||||
impure->vlu_misc.vlu_long = 0;
|
||||
impure->vlu_desc.dsc_dtype = dtype_long;
|
||||
impure->vlu_desc.dsc_length = sizeof(SLONG);
|
||||
impure->vlu_desc.dsc_address = (UCHAR*) &impure->vlu_misc.vlu_long;
|
||||
|
||||
const RecordSource* const rsb = reinterpret_cast<const RecordSource*>(node->nod_arg[e_stat_rsb]);
|
||||
rsb->open(tdbb);
|
||||
|
||||
SLONG count = 0;
|
||||
ULONG flag = req_null;
|
||||
double d;
|
||||
|
||||
try
|
||||
{
|
||||
// Handle each variety separately
|
||||
|
||||
switch (node->nod_type)
|
||||
{
|
||||
case nod_count:
|
||||
flag = 0;
|
||||
while (rsb->getRecord(tdbb))
|
||||
{
|
||||
++impure->vlu_misc.vlu_long;
|
||||
}
|
||||
break;
|
||||
|
||||
case nod_min:
|
||||
case nod_max:
|
||||
while (rsb->getRecord(tdbb))
|
||||
{
|
||||
dsc* value = EVL_expr(tdbb, node->nod_arg[e_stat_value]);
|
||||
if (request->req_flags & req_null) {
|
||||
continue;
|
||||
}
|
||||
int result;
|
||||
if (flag || ((result = MOV_compare(value, desc)) < 0 && node->nod_type == nod_min) ||
|
||||
(node->nod_type != nod_min && result > 0))
|
||||
{
|
||||
flag = 0;
|
||||
EVL_make_value(tdbb, value, impure);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case nod_from:
|
||||
if (rsb->getRecord(tdbb))
|
||||
{
|
||||
desc = EVL_expr(tdbb, node->nod_arg[e_stat_value]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (node->nod_arg[e_stat_default])
|
||||
desc = EVL_expr(tdbb, node->nod_arg[e_stat_default]);
|
||||
else
|
||||
ERR_post(Arg::Gds(isc_from_no_match));
|
||||
}
|
||||
flag = request->req_flags;
|
||||
break;
|
||||
|
||||
case nod_average: // total or average with dialect-1 semantics
|
||||
case nod_total:
|
||||
while (rsb->getRecord(tdbb))
|
||||
{
|
||||
desc = EVL_expr(tdbb, node->nod_arg[e_stat_value]);
|
||||
if (request->req_flags & req_null) {
|
||||
continue;
|
||||
}
|
||||
// Note: if the field being SUMed or AVERAGEd is short or long,
|
||||
// impure will stay long, and the first add() will
|
||||
// set the correct scale; if it is approximate numeric,
|
||||
// the first add() will convert impure to double.
|
||||
ArithmeticNode::add(desc, impure, node, blr_add);
|
||||
|
||||
count++;
|
||||
}
|
||||
desc = &impure->vlu_desc;
|
||||
if (node->nod_type == nod_total)
|
||||
{
|
||||
flag = 0;
|
||||
break;
|
||||
}
|
||||
if (!count)
|
||||
break;
|
||||
d = MOV_get_double(&impure->vlu_desc);
|
||||
impure->vlu_misc.vlu_double = d / count;
|
||||
impure->vlu_desc.dsc_dtype = DEFAULT_DOUBLE;
|
||||
impure->vlu_desc.dsc_length = sizeof(double);
|
||||
impure->vlu_desc.dsc_scale = 0;
|
||||
flag = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
BUGCHECK(233); // msg 233 eval_statistical: invalid operation
|
||||
}
|
||||
}
|
||||
catch (const Firebird::Exception&)
|
||||
{
|
||||
// close stream
|
||||
// ignore any error during it to keep original
|
||||
try
|
||||
{
|
||||
rsb->close(tdbb);
|
||||
request->req_flags &= ~req_null;
|
||||
request->req_flags |= flag;
|
||||
}
|
||||
catch (const Firebird::Exception&)
|
||||
{} // no-op
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
// Close stream and return value
|
||||
|
||||
rsb->close(tdbb);
|
||||
request->req_flags &= ~req_null;
|
||||
request->req_flags |= flag;
|
||||
|
||||
// If this is an invariant node, save the return value. If the
|
||||
// descriptor does not point to the impure area for this node then
|
||||
// point this node's descriptor to the correct place; copy the whole
|
||||
// structure to be absolutely sure
|
||||
|
||||
if (node->nod_flags & nod_invariant)
|
||||
{
|
||||
*invariant_flags |= VLU_computed;
|
||||
if (request->req_flags & req_null)
|
||||
*invariant_flags |= VLU_null;
|
||||
if (desc && (desc != &impure->vlu_desc))
|
||||
impure->vlu_desc = *desc;
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
|
||||
static dsc* record_version(thread_db* tdbb, const jrd_nod* node, impure_value* impure)
|
||||
{
|
||||
/**************************************
|
||||
|
@ -222,14 +222,6 @@ const int e_val_boolean = 0;
|
||||
const int e_val_value = 1;
|
||||
const int e_val_length = 2;
|
||||
|
||||
// Statistical expressions
|
||||
|
||||
const int e_stat_rse = 0;
|
||||
const int e_stat_value = 1;
|
||||
const int e_stat_default = 2;
|
||||
const int e_stat_rsb = 3;
|
||||
const int e_stat_length = 4;
|
||||
|
||||
// Execute stored procedure
|
||||
|
||||
const int e_esp_inputs = 0;
|
||||
|
@ -59,7 +59,6 @@ NODE(nod_set_generator2, set_generator, "")
|
||||
|
||||
NODE(nod_dbkey, dbkey, "ROWID")
|
||||
NODE(nod_field, field, "")
|
||||
NODE(nod_from, from, "")
|
||||
NODE(nod_scalar, scalar, "")
|
||||
NODE(nod_rec_version, record_version, "RECORD VERSION")
|
||||
NODE(nod_domain_validation, domain_validation, "")
|
||||
@ -67,12 +66,6 @@ NODE(nod_derived_expr, derived_expr, "derived_expr")
|
||||
|
||||
NODE(nod_stmt_expr, stmt_expr, "stmt_expr")
|
||||
|
||||
NODE(nod_average, average, "AVG")
|
||||
NODE(nod_count, count, "COUNT")
|
||||
NODE(nod_max, max, "MAX")
|
||||
NODE(nod_min, min, "MIN")
|
||||
NODE(nod_total, total, "SUM")
|
||||
|
||||
NODE(nod_class_exprnode_jrd, class_exprnode_jrd, "class_exprnode_jrd")
|
||||
NODE(nod_class_stmtnode_jrd, class_stmtnode_jrd, "class_stmtnode_jrd")
|
||||
NODE(nod_class_recsrcnode_jrd, class_recsrcnode_jrd, "class_recsrcnode_jrd")
|
||||
|
@ -231,24 +231,6 @@ bool StreamFinder::visit(const JrdNode& node)
|
||||
break;
|
||||
}
|
||||
|
||||
case nod_average:
|
||||
case nod_count:
|
||||
case nod_from:
|
||||
case nod_max:
|
||||
case nod_min:
|
||||
case nod_total:
|
||||
{
|
||||
jrd_nod* nodeDefault = jrdNode->nod_arg[e_stat_rse];
|
||||
if (nodeDefault && visit(nodeDefault))
|
||||
return true;
|
||||
|
||||
jrd_nod* value = jrdNode->nod_arg[e_stat_value];
|
||||
if (value && visit(value))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
default:
|
||||
return visitChildren(node);
|
||||
}
|
||||
@ -320,16 +302,6 @@ bool StreamsCollector::visit(const JrdNode& node)
|
||||
break;
|
||||
}
|
||||
|
||||
case nod_average:
|
||||
case nod_count:
|
||||
case nod_from:
|
||||
case nod_max:
|
||||
case nod_min:
|
||||
case nod_total:
|
||||
visit(jrdNode->nod_arg[e_stat_rse]);
|
||||
visit(jrdNode->nod_arg[e_stat_value]);
|
||||
break;
|
||||
|
||||
default:
|
||||
return visitChildren(node);
|
||||
}
|
||||
@ -1579,19 +1551,16 @@ static bool check_for_nod_from(const jrd_nod* node)
|
||||
* Check for nod_from under >=0 CastNode nodes.
|
||||
*
|
||||
**************************************/
|
||||
const CastNode* castNode = ExprNode::as<CastNode>(node);
|
||||
const CastNode* castNode;
|
||||
const SubQueryNode* subQueryNode;
|
||||
|
||||
if (castNode)
|
||||
if ((castNode = ExprNode::as<CastNode>(node)))
|
||||
return check_for_nod_from(castNode->source);
|
||||
|
||||
switch (node->nod_type)
|
||||
{
|
||||
case nod_from:
|
||||
else if ((subQueryNode = ExprNode::as<SubQueryNode>(node)) && subQueryNode->blrOp == blr_via)
|
||||
return true;
|
||||
default:
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static SLONG decompose(thread_db* tdbb, BoolExprNode* boolNode, BoolExprNodeStack& stack,
|
||||
CompilerScratch* csb)
|
||||
|
@ -2582,20 +2582,6 @@ jrd_nod* PAR_parse_node(thread_db* tdbb, CompilerScratch* csb, USHORT expected)
|
||||
node->nod_arg[0] = (jrd_nod*)(IPTR) csb->csb_blr_reader.getByte();
|
||||
break;
|
||||
|
||||
case blr_maximum:
|
||||
case blr_minimum:
|
||||
case blr_count:
|
||||
case blr_average:
|
||||
case blr_total:
|
||||
case blr_from:
|
||||
case blr_via:
|
||||
node->nod_arg[e_stat_rse] = PAR_parse_node(tdbb, csb, TYPE_RSE);
|
||||
if (blr_operator != blr_count)
|
||||
node->nod_arg[e_stat_value] = PAR_parse_node(tdbb, csb, VALUE);
|
||||
if (blr_operator == blr_via)
|
||||
node->nod_arg[e_stat_default] = PAR_parse_node(tdbb, csb, VALUE);
|
||||
break;
|
||||
|
||||
case blr_init_variable:
|
||||
{
|
||||
n = csb->csb_blr_reader.getWord();
|
||||
|
@ -115,23 +115,20 @@ static const VERB verbs[] =
|
||||
PAIR(nod_class_exprnode_jrd, blr_parameter3, 1, 0, VALUE, VALUE),
|
||||
PAIR(nod_class_exprnode_jrd, blr_variable, 1, 0, VALUE, VALUE),
|
||||
PAIR(nod_class_exprnode_jrd, blr_user_name, 1, 0, VALUE, VALUE),
|
||||
PAIR(nod_average, blr_average, e_stat_length, 2, VALUE, VALUE),
|
||||
PAIR(nod_class_exprnode_jrd, blr_average, 1, 0, VALUE, VALUE),
|
||||
PAIR(nod_class_exprnode_jrd, blr_concatenate, 1, 0, VALUE, VALUE),
|
||||
PAIR(nod_count, blr_count, e_stat_length, 1, VALUE, VALUE),
|
||||
/* count2
|
||||
, PAIR (nod_count2, blr_count2, e_stat_length, 2, VALUE, VALUE)
|
||||
*/
|
||||
PAIR(nod_class_exprnode_jrd, blr_count, 1, 0, VALUE, VALUE),
|
||||
PAIR(nod_dbkey, blr_dbkey, 1, 0, VALUE, VALUE),
|
||||
PAIR(nod_class_exprnode_jrd, blr_divide, 1, 0, VALUE, VALUE),
|
||||
PAIR(nod_field, blr_fid, 0, 0, VALUE, VALUE),
|
||||
PAIR(nod_field, blr_field, 0, 0, VALUE, VALUE),
|
||||
PAIR(nod_from, blr_via, e_stat_length, 3, VALUE, OTHER),
|
||||
PAIR(nod_from, blr_from, e_stat_length, 2, VALUE, OTHER),
|
||||
PAIR(nod_class_exprnode_jrd, blr_via, 1, 0, VALUE, OTHER),
|
||||
PAIR(nod_class_exprnode_jrd, blr_from, 1, 0, VALUE, OTHER),
|
||||
PAIR(nod_class_exprnode_jrd, blr_function, 1, 0, VALUE, VALUE),
|
||||
PAIR(nod_class_exprnode_jrd, blr_literal, 1, 0, VALUE, OTHER),
|
||||
PAIR(nod_scalar, blr_index, 2, 2, VALUE, VALUE),
|
||||
PAIR(nod_max, blr_maximum, e_stat_length, 2, VALUE, VALUE),
|
||||
PAIR(nod_min, blr_minimum, e_stat_length, 2, VALUE, VALUE),
|
||||
PAIR(nod_class_exprnode_jrd, blr_maximum, 1, 0, VALUE, VALUE),
|
||||
PAIR(nod_class_exprnode_jrd, blr_minimum, 1, 0, VALUE, VALUE),
|
||||
PAIR(nod_class_exprnode_jrd, blr_null, 1, 0, VALUE, VALUE),
|
||||
PAIR(nod_class_exprnode_jrd, blr_multiply, 1, 0, VALUE, VALUE),
|
||||
PAIR(nod_class_exprnode_jrd, blr_negate, 1, 0, VALUE, VALUE),
|
||||
@ -139,7 +136,7 @@ static const VERB verbs[] =
|
||||
PAIR(nod_class_exprnode_jrd, blr_upcase, 1, 0, VALUE, VALUE),
|
||||
PAIR(nod_class_exprnode_jrd, blr_substring, 1, 0, VALUE, VALUE),
|
||||
PAIR(nod_class_exprnode_jrd, blr_subtract, 1, 0, VALUE, VALUE),
|
||||
PAIR(nod_total, blr_total, e_stat_length, 2, VALUE, VALUE),
|
||||
PAIR(nod_class_exprnode_jrd, blr_total, 1, 0, VALUE, VALUE),
|
||||
PAIR(nod_class_exprnode_jrd, blr_value_if, 1, 0, VALUE, OTHER),
|
||||
PAIR(nod_class_exprnode_jrd, blr_equiv, 1, 0, TYPE_BOOL, VALUE),
|
||||
PAIR(nod_class_exprnode_jrd, blr_eql, 1, 0, TYPE_BOOL, VALUE),
|
||||
|
Loading…
Reference in New Issue
Block a user