8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-22 18:43:02 +01:00

1) Refactor nod_value_if.

2) Created ExprNode::expressionEqual method to replace a new big and ugly switch.
3) Make boolean referencers use BoolExprNode instead of jrd_nod, except nod_validate for now. This includes BinaryBoolNode and NotBoolNode working without jrd_nod references.
4) Rework in the impure allocation code (replace "csb_impure += ..." by CMP_impure calls).
This commit is contained in:
asfernandes 2010-09-20 16:07:50 +00:00
parent 9e786f0c8a
commit 9b8171d5c1
39 changed files with 1515 additions and 1163 deletions

View File

@ -28,6 +28,7 @@
#include "../jrd/quad.h"
#include "../jrd/tra.h"
#include "../jrd/recsrc/RecordSource.h"
#include "../jrd/Optimizer.h"
#include "../jrd/blb_proto.h"
#include "../jrd/cmp_proto.h"
#include "../jrd/evl_proto.h"
@ -82,8 +83,49 @@ namespace
//--------------------
static RegisterNode<BinaryBoolNode> regBinaryBoolNodeAnd(blr_and);
static RegisterNode<BinaryBoolNode> regBinaryBoolNodeOr(blr_or);
bool BoolExprNode::computable(CompilerScratch* csb, SSHORT stream, bool idxUse,
bool allowOnlyCurrentStream)
{
if (flags & FLAG_DEOPTIMIZE)
return false;
return ExprNode::computable(csb, stream, idxUse, allowOnlyCurrentStream);
}
BoolExprNode* BoolExprNode::pass2(thread_db* tdbb, CompilerScratch* csb)
{
pass2Boolean1(tdbb, csb);
ExprNode::pass2(tdbb, csb);
pass2Boolean2(tdbb, csb);
if (flags & FLAG_INVARIANT)
{
// Bind values of invariant nodes to top-level RSE (if present)
if (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(impureOffset);
}
}
return this;
}
//--------------------
static RegisterBoolNode<BinaryBoolNode> regBinaryBoolNodeAnd(blr_and);
static RegisterBoolNode<BinaryBoolNode> regBinaryBoolNodeOr(blr_or);
BinaryBoolNode::BinaryBoolNode(MemoryPool& pool, UCHAR aBlrOp, dsql_nod* aArg1, dsql_nod* aArg2)
: TypedNode<BoolExprNode, ExprNode::TYPE_BINARY_BOOL>(pool),
@ -97,18 +139,18 @@ BinaryBoolNode::BinaryBoolNode(MemoryPool& pool, UCHAR aBlrOp, dsql_nod* aArg1,
addChildNode(dsqlArg2, arg2);
}
DmlNode* BinaryBoolNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR blrOp)
BoolExprNode* BinaryBoolNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR blrOp)
{
BinaryBoolNode* node = FB_NEW(pool) BinaryBoolNode(pool, blrOp);
node->arg1 = PAR_parse_node(tdbb, csb, TYPE_BOOL);
node->arg2 = PAR_parse_node(tdbb, csb, TYPE_BOOL);
node->arg1 = PAR_parse_boolean(tdbb, csb);
node->arg2 = PAR_parse_boolean(tdbb, csb);
return node;
}
void BinaryBoolNode::print(string& text, Array<dsql_nod*>& nodes) const
{
text.printf("BinaryBoolNode (%d)", blrOp);
ExprNode::print(text, nodes);
BoolExprNode::print(text, nodes);
}
BoolExprNode* BinaryBoolNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
@ -135,12 +177,32 @@ bool BinaryBoolNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const
return blrOp == o->blrOp;
}
bool BinaryBoolNode::expressionEqual(thread_db* tdbb, CompilerScratch* csb, /*const*/ ExprNode* other,
USHORT stream)
{
BinaryBoolNode* otherNode = other->as<BinaryBoolNode>();
if (!otherNode || blrOp != otherNode->blrOp)
return false;
if (arg1->expressionEqual(tdbb, csb, otherNode->arg1, stream) &&
arg2->expressionEqual(tdbb, csb, otherNode->arg2, stream))
{
return true;
}
// A AND B is equivalent to B AND A, ditto for A OR B and B OR A.
return arg1->expressionEqual(tdbb, csb, otherNode->arg2, stream) &&
arg2->expressionEqual(tdbb, csb, otherNode->arg1, stream);
}
BoolExprNode* BinaryBoolNode::copy(thread_db* tdbb, NodeCopier& copier)
{
BinaryBoolNode* node = FB_NEW(*tdbb->getDefaultPool()) BinaryBoolNode(*tdbb->getDefaultPool(),
blrOp);
node->arg1 = copier.copy(tdbb, arg1);
node->arg2 = copier.copy(tdbb, arg2);
node->flags = flags;
node->arg1 = arg1->copy(tdbb, copier);
node->arg2 = arg2->copy(tdbb, copier);
return node;
}
@ -177,7 +239,7 @@ bool BinaryBoolNode::executeAnd(thread_db* tdbb, jrd_req* request) const
// N T N
// N N N
const bool value1 = EVL_boolean(tdbb, arg1);
const bool value1 = arg1->execute(tdbb, request);
// Save null state and get other operand.
const USHORT firstnull = request->req_flags & req_null;
@ -190,7 +252,7 @@ bool BinaryBoolNode::executeAnd(thread_db* tdbb, jrd_req* request) const
return false;
}
const bool value2 = EVL_boolean(tdbb, arg2);
const bool value2 = arg2->execute(tdbb, request);
const USHORT secondnull = request->req_flags & req_null;
request->req_flags &= ~req_null;
@ -227,7 +289,7 @@ bool BinaryBoolNode::executeOr(thread_db* tdbb, jrd_req* request) const
// evaluate second operand, since latter field mappings may
// depend on the evaluation.
const bool value1 = EVL_boolean(tdbb, arg1);
const bool value1 = arg1->execute(tdbb, request);
const ULONG flags = request->req_flags;
request->req_flags &= ~req_null;
@ -239,7 +301,7 @@ bool BinaryBoolNode::executeOr(thread_db* tdbb, jrd_req* request) const
return true;
}
const bool value2 = EVL_boolean(tdbb, arg2);
const bool value2 = arg2->execute(tdbb, request);
if (value1 || value2)
{
@ -259,21 +321,21 @@ bool BinaryBoolNode::executeOr(thread_db* tdbb, jrd_req* request) const
//--------------------
static RegisterNode<ComparativeBoolNode> regComparativeBoolNodeEql(blr_eql);
static RegisterNode<ComparativeBoolNode> regComparativeBoolNodeGeq(blr_geq);
static RegisterNode<ComparativeBoolNode> regComparativeBoolNodeGtr(blr_gtr);
static RegisterNode<ComparativeBoolNode> regComparativeBoolNodeLeq(blr_leq);
static RegisterNode<ComparativeBoolNode> regComparativeBoolNodeLss(blr_lss);
static RegisterNode<ComparativeBoolNode> regComparativeBoolNodeNeq(blr_neq);
static RegisterNode<ComparativeBoolNode> regComparativeBoolNodeEquiv(blr_equiv);
static RegisterNode<ComparativeBoolNode> regComparativeBoolNodeBetween(blr_between);
static RegisterNode<ComparativeBoolNode> regComparativeBoolNodeLike(blr_like);
static RegisterNode<ComparativeBoolNode> regComparativeBoolNodeAnsiLike(blr_ansi_like);
static RegisterNode<ComparativeBoolNode> regComparativeBoolNodeContaining(blr_containing);
static RegisterNode<ComparativeBoolNode> regComparativeBoolNodeStarting(blr_starting);
static RegisterNode<ComparativeBoolNode> regComparativeBoolNodeSimilar(blr_similar);
static RegisterNode<ComparativeBoolNode> regComparativeBoolNodeMatching(blr_matching);
static RegisterNode<ComparativeBoolNode> regComparativeBoolNodeMatching2(blr_matching2); // sleuth
static RegisterBoolNode<ComparativeBoolNode> regComparativeBoolNodeEql(blr_eql);
static RegisterBoolNode<ComparativeBoolNode> regComparativeBoolNodeGeq(blr_geq);
static RegisterBoolNode<ComparativeBoolNode> regComparativeBoolNodeGtr(blr_gtr);
static RegisterBoolNode<ComparativeBoolNode> regComparativeBoolNodeLeq(blr_leq);
static RegisterBoolNode<ComparativeBoolNode> regComparativeBoolNodeLss(blr_lss);
static RegisterBoolNode<ComparativeBoolNode> regComparativeBoolNodeNeq(blr_neq);
static RegisterBoolNode<ComparativeBoolNode> regComparativeBoolNodeEquiv(blr_equiv);
static RegisterBoolNode<ComparativeBoolNode> regComparativeBoolNodeBetween(blr_between);
static RegisterBoolNode<ComparativeBoolNode> regComparativeBoolNodeLike(blr_like);
static RegisterBoolNode<ComparativeBoolNode> regComparativeBoolNodeAnsiLike(blr_ansi_like);
static RegisterBoolNode<ComparativeBoolNode> regComparativeBoolNodeContaining(blr_containing);
static RegisterBoolNode<ComparativeBoolNode> regComparativeBoolNodeStarting(blr_starting);
static RegisterBoolNode<ComparativeBoolNode> regComparativeBoolNodeSimilar(blr_similar);
static RegisterBoolNode<ComparativeBoolNode> regComparativeBoolNodeMatching(blr_matching);
static RegisterBoolNode<ComparativeBoolNode> regComparativeBoolNodeMatching2(blr_matching2); // sleuth
ComparativeBoolNode::ComparativeBoolNode(MemoryPool& pool, UCHAR aBlrOp,
dsql_nod* aArg1, dsql_nod* aArg2, dsql_nod* aArg3)
@ -292,7 +354,7 @@ ComparativeBoolNode::ComparativeBoolNode(MemoryPool& pool, UCHAR aBlrOp,
addChildNode(dsqlArg3, arg3);
}
DmlNode* ComparativeBoolNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR blrOp)
BoolExprNode* ComparativeBoolNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR blrOp)
{
ComparativeBoolNode* node = FB_NEW(pool) ComparativeBoolNode(pool, blrOp);
@ -318,7 +380,7 @@ DmlNode* ComparativeBoolNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerS
void ComparativeBoolNode::print(string& text, Array<dsql_nod*>& nodes) const
{
text.printf("ComparativeBoolNode (%d)", blrOp);
ExprNode::print(text, nodes);
BoolExprNode::print(text, nodes);
}
BoolExprNode* ComparativeBoolNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
@ -462,10 +524,48 @@ bool ComparativeBoolNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) c
return dsqlFlag == o->dsqlFlag && blrOp == o->blrOp;
}
bool ComparativeBoolNode::expressionEqual(thread_db* tdbb, CompilerScratch* csb,
/*const*/ ExprNode* other, USHORT stream)
{
ComparativeBoolNode* otherNode = other->as<ComparativeBoolNode>();
if (!otherNode || blrOp != otherNode->blrOp)
return false;
bool matching = OPT_expression_equal2(tdbb, csb, arg1, otherNode->arg1, stream) &&
OPT_expression_equal2(tdbb, csb, arg2, otherNode->arg2, stream);
if (matching)
{
matching = !arg3 == !otherNode->arg3 &&
(!arg3 || OPT_expression_equal2(tdbb, csb, arg3, otherNode->arg3, stream));
if (matching)
return true;
}
// TODO match A > B to B <= A, etc
if (blrOp == blr_eql || blrOp == blr_equiv || blrOp == blr_neq)
{
// A = B is equivalent to B = A, etc.
if (OPT_expression_equal2(tdbb, csb, arg1, otherNode->arg2, stream) &&
OPT_expression_equal2(tdbb, csb, arg2, otherNode->arg1, stream))
{
return true;
}
}
return false;
}
BoolExprNode* ComparativeBoolNode::copy(thread_db* tdbb, NodeCopier& copier)
{
ComparativeBoolNode* node = FB_NEW(*tdbb->getDefaultPool()) ComparativeBoolNode(
*tdbb->getDefaultPool(), blrOp);
node->flags = flags;
node->arg1 = copier.copy(tdbb, arg1);
node->arg2 = copier.copy(tdbb, arg2);
@ -475,23 +575,12 @@ BoolExprNode* ComparativeBoolNode::copy(thread_db* tdbb, NodeCopier& copier)
return node;
}
ExprNode* ComparativeBoolNode::pass1(thread_db* tdbb, CompilerScratch* csb)
BoolExprNode* ComparativeBoolNode::pass1(thread_db* tdbb, CompilerScratch* csb)
{
bool invariantCheck = false;
switch (blrOp)
{
case blr_eql:
case blr_equiv:
case blr_gtr:
case blr_geq:
case blr_lss:
case blr_leq:
case blr_neq:
case blr_between:
node->nod_flags |= nod_comparison;
break;
case blr_like:
case blr_similar:
case blr_containing:
@ -505,8 +594,8 @@ ExprNode* ComparativeBoolNode::pass1(thread_db* tdbb, CompilerScratch* csb)
if (invariantCheck)
{
// We need to take care of invariantness expressions to be able to pre-compile the pattern.
node->nod_flags |= nod_invariant;
csb->csb_current_nodes.push(node.getObject());
flags |= FLAG_INVARIANT;
csb->csb_current_nodes.push(this);
}
arg2 = CMP_pass1(tdbb, csb, arg2);
@ -520,7 +609,7 @@ ExprNode* ComparativeBoolNode::pass1(thread_db* tdbb, CompilerScratch* csb)
// If there is no top-level RSE present and patterns are not constant, unmark node as invariant
// because it may be dependent on data or variables.
if ((node->nod_flags & nod_invariant) &&
if ((flags & FLAG_INVARIANT) &&
(arg2->nod_type != nod_literal || (arg3 && arg3->nod_type != nod_literal)))
{
const LegacyNodeOrRseNode* ctx_node, *end;
@ -532,20 +621,21 @@ ExprNode* ComparativeBoolNode::pass1(thread_db* tdbb, CompilerScratch* csb)
}
if (ctx_node >= end)
node->nod_flags &= ~nod_invariant;
flags &= ~FLAG_INVARIANT;
}
}
return this;
}
ExprNode* ComparativeBoolNode::pass2(thread_db* tdbb, CompilerScratch* csb)
void ComparativeBoolNode::pass2Boolean1(thread_db* tdbb, CompilerScratch* csb)
{
if (node->nod_flags & nod_invariant)
csb->csb_invariants.push(node);
ExprNode::pass2(tdbb, csb);
if (flags & FLAG_INVARIANT)
csb->csb_invariants.push(&impureOffset);
}
void ComparativeBoolNode::pass2Boolean2(thread_db* tdbb, CompilerScratch* csb)
{
if (arg3)
{
if (arg3->nod_flags & nod_agg_dbkey)
@ -573,13 +663,11 @@ ExprNode* ComparativeBoolNode::pass2(thread_db* tdbb, CompilerScratch* csb)
else if (DTYPE_IS_DATE(descriptor_b.dsc_dtype))
arg1->nod_flags |= nod_date;
if (node->nod_flags & nod_invariant)
if (flags & FLAG_INVARIANT)
{
// This may currently happen for nod_like, nod_contains and nod_similar
csb->csb_impure += sizeof(impure_value);
impureOffset = CMP_impure(csb, sizeof(impure_value));
}
return this;
}
bool ComparativeBoolNode::execute(thread_db* tdbb, jrd_req* request) const
@ -602,9 +690,9 @@ bool ComparativeBoolNode::execute(thread_db* tdbb, jrd_req* request) const
force_equal |= request->req_flags & req_same_tx_upd;
// Currently only nod_like, nod_contains, nod_starts and nod_similar may be marked invariant
if (node->nod_flags & nod_invariant)
if (flags & FLAG_INVARIANT)
{
impure_value* impure = request->getImpure<impure_value>(node->nod_impure);
impure_value* impure = request->getImpure<impure_value>(impureOffset);
// Check that data type of operand is still the same.
// It may change due to multiple formats present in stream
@ -692,8 +780,18 @@ bool ComparativeBoolNode::execute(thread_db* tdbb, jrd_req* request) const
force_equal |= request->req_flags & req_same_tx_upd;
if (node->nod_flags & nod_comparison)
comparison = MOV_compare(desc[0], desc[1]);
switch (blrOp)
{
case blr_eql:
case blr_equiv:
case blr_gtr:
case blr_geq:
case blr_lss:
case blr_leq:
case blr_neq:
case blr_between:
comparison = MOV_compare(desc[0], desc[1]);
}
// If we are checking equality of record_version
// and same transaction updated the record, force equality.
@ -831,9 +929,9 @@ bool ComparativeBoolNode::stringBoolean(thread_db* tdbb, jrd_req* request, dsc*
if (request->req_flags & req_null)
{
if (node->nod_flags & nod_invariant)
if (flags & FLAG_INVARIANT)
{
impure_value* impure = request->getImpure<impure_value>(node->nod_impure);
impure_value* impure = request->getImpure<impure_value>(impureOffset);
impure->vlu_flags |= VLU_computed;
impure->vlu_flags |= VLU_null;
}
@ -864,9 +962,9 @@ bool ComparativeBoolNode::stringBoolean(thread_db* tdbb, jrd_req* request, dsc*
PatternMatcher* evaluator;
if (node->nod_flags & nod_invariant)
if (flags & FLAG_INVARIANT)
{
impure_value* impure = request->getImpure<impure_value>(node->nod_impure);
impure_value* impure = request->getImpure<impure_value>(impureOffset);
if (!(impure->vlu_flags & VLU_computed))
{
@ -910,7 +1008,7 @@ bool ComparativeBoolNode::stringBoolean(thread_db* tdbb, jrd_req* request, dsc*
ret_val = evaluator->result();
if (!(node->nod_flags & nod_invariant))
if (!(flags & FLAG_INVARIANT))
delete evaluator;
break;
@ -921,9 +1019,9 @@ bool ComparativeBoolNode::stringBoolean(thread_db* tdbb, jrd_req* request, dsc*
{
PatternMatcher* evaluator;
if (node->nod_flags & nod_invariant)
if (flags & FLAG_INVARIANT)
{
impure_value* impure = request->getImpure<impure_value>(node->nod_impure);
impure_value* impure = request->getImpure<impure_value>(impureOffset);
if (!(impure->vlu_flags & VLU_computed))
{
delete impure->vlu_misc.vlu_invariant;
@ -964,7 +1062,7 @@ bool ComparativeBoolNode::stringBoolean(thread_db* tdbb, jrd_req* request, dsc*
ret_val = evaluator->result();
if (!(node->nod_flags & nod_invariant))
if (!(flags & FLAG_INVARIANT))
delete evaluator;
break;
@ -989,9 +1087,9 @@ bool ComparativeBoolNode::stringFunction(thread_db* tdbb, jrd_req* request,
// Handle contains and starts
if (blrOp == blr_containing || blrOp == blr_starting)
{
if (node->nod_flags & nod_invariant)
if (flags & FLAG_INVARIANT)
{
impure_value* impure = request->getImpure<impure_value>(node->nod_impure);
impure_value* impure = request->getImpure<impure_value>(impureOffset);
PatternMatcher* evaluator;
if (!(impure->vlu_flags & VLU_computed))
{
@ -1041,9 +1139,9 @@ bool ComparativeBoolNode::stringFunction(thread_db* tdbb, jrd_req* request,
dsc* desc = EVL_expr(tdbb, arg3);
if (request->req_flags & req_null)
{
if (node->nod_flags & nod_invariant)
if (flags & FLAG_INVARIANT)
{
impure_value* impure = request->getImpure<impure_value>(node->nod_impure);
impure_value* impure = request->getImpure<impure_value>(impureOffset);
impure->vlu_flags |= VLU_computed;
impure->vlu_flags |= VLU_null;
}
@ -1070,9 +1168,9 @@ bool ComparativeBoolNode::stringFunction(thread_db* tdbb, jrd_req* request,
}
}
if (node->nod_flags & nod_invariant)
if (flags & FLAG_INVARIANT)
{
impure_value* impure = request->getImpure<impure_value>(node->nod_impure);
impure_value* impure = request->getImpure<impure_value>(impureOffset);
PatternMatcher* evaluator;
if (!(impure->vlu_flags & VLU_computed))
@ -1235,7 +1333,7 @@ BoolExprNode* ComparativeBoolNode::createRseNode(DsqlCompilerScratch* dsqlScratc
//--------------------
static RegisterNode<MissingBoolNode> regMissingBoolNode(blr_missing);
static RegisterBoolNode<MissingBoolNode> regMissingBoolNode(blr_missing);
MissingBoolNode::MissingBoolNode(MemoryPool& pool, dsql_nod* aArg)
: TypedNode<BoolExprNode, ExprNode::TYPE_MISSING_BOOL>(pool),
@ -1245,17 +1343,17 @@ MissingBoolNode::MissingBoolNode(MemoryPool& pool, dsql_nod* aArg)
addChildNode(dsqlArg, arg);
}
DmlNode* MissingBoolNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR /*blrOp*/)
BoolExprNode* MissingBoolNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR /*blrOp*/)
{
MissingBoolNode* node = FB_NEW(pool) MissingBoolNode(pool);
node->arg = PAR_parse_node(tdbb, csb, TYPE_BOOL);
node->arg = PAR_parse_node(tdbb, csb, VALUE);
return node;
}
void MissingBoolNode::print(string& text, Array<dsql_nod*>& nodes) const
{
text = "MissingBoolNode";
ExprNode::print(text, nodes);
BoolExprNode::print(text, nodes);
}
BoolExprNode* MissingBoolNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
@ -1278,16 +1376,17 @@ BoolExprNode* MissingBoolNode::copy(thread_db* tdbb, NodeCopier& copier)
{
MissingBoolNode* node = FB_NEW(*tdbb->getDefaultPool()) MissingBoolNode(
*tdbb->getDefaultPool());
node->flags = flags;
node->arg = copier.copy(tdbb, arg);
return node;
}
ExprNode* MissingBoolNode::pass1(thread_db* tdbb, CompilerScratch* csb)
BoolExprNode* MissingBoolNode::pass1(thread_db* tdbb, CompilerScratch* csb)
{
return BoolExprNode::pass1(tdbb, csb);
}
ExprNode* MissingBoolNode::pass2(thread_db* tdbb, CompilerScratch* csb)
void MissingBoolNode::pass2Boolean2(thread_db* tdbb, CompilerScratch* csb)
{
if (arg->nod_flags & nod_agg_dbkey)
ERR_post(Arg::Gds(isc_bad_dbkey));
@ -1295,8 +1394,6 @@ ExprNode* MissingBoolNode::pass2(thread_db* tdbb, CompilerScratch* csb)
// check for syntax errors in the calculation
dsc descriptor_a;
CMP_get_desc(tdbb, csb, arg, &descriptor_a);
return BoolExprNode::pass2(tdbb, csb);
}
bool MissingBoolNode::execute(thread_db* tdbb, jrd_req* request) const
@ -1316,7 +1413,7 @@ bool MissingBoolNode::execute(thread_db* tdbb, jrd_req* request) const
//--------------------
static RegisterNode<NotBoolNode> regNotBoolNode(blr_not);
static RegisterBoolNode<NotBoolNode> regNotBoolNode(blr_not);
NotBoolNode::NotBoolNode(MemoryPool& pool, dsql_nod* aArg)
: TypedNode<BoolExprNode, ExprNode::TYPE_NOT_BOOL>(pool),
@ -1326,17 +1423,17 @@ NotBoolNode::NotBoolNode(MemoryPool& pool, dsql_nod* aArg)
addChildNode(dsqlArg, arg);
}
DmlNode* NotBoolNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR /*blrOp*/)
BoolExprNode* NotBoolNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR /*blrOp*/)
{
NotBoolNode* node = FB_NEW(pool) NotBoolNode(pool);
node->arg = PAR_parse_node(tdbb, csb, TYPE_BOOL);
node->arg = PAR_parse_boolean(tdbb, csb);
return node;
}
void NotBoolNode::print(string& text, Array<dsql_nod*>& nodes) const
{
text = "NotBoolNode";
ExprNode::print(text, nodes);
BoolExprNode::print(text, nodes);
}
BoolExprNode* NotBoolNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
@ -1353,20 +1450,21 @@ void NotBoolNode::genBlr(DsqlCompilerScratch* dsqlScratch)
BoolExprNode* NotBoolNode::copy(thread_db* tdbb, NodeCopier& copier)
{
NotBoolNode* node = FB_NEW(*tdbb->getDefaultPool()) NotBoolNode(*tdbb->getDefaultPool());
node->arg = copier.copy(tdbb, arg);
node->flags = flags;
node->arg = arg->copy(tdbb, copier);
return node;
}
ExprNode* NotBoolNode::pass1(thread_db* tdbb, CompilerScratch* csb)
BoolExprNode* NotBoolNode::pass1(thread_db* tdbb, CompilerScratch* csb)
{
RseBoolNode* rseBoolean = ExprNode::as<RseBoolNode>(arg.getObject());
RseBoolNode* rseBoolean = arg->as<RseBoolNode>();
if (rseBoolean && rseBoolean->getNode())
if (rseBoolean)
{
if (rseBoolean->blrOp == blr_ansi_any)
rseBoolean->getNode()->nod_flags |= nod_deoptimize;
rseBoolean->flags |= FLAG_DEOPTIMIZE;
if (rseBoolean->blrOp == blr_ansi_any || rseBoolean->blrOp == blr_ansi_all)
rseBoolean->getNode()->nod_flags |= nod_ansi_not;
rseBoolean->flags |= FLAG_ANSI_NOT;
}
return BoolExprNode::pass1(tdbb, csb);
@ -1374,7 +1472,7 @@ ExprNode* NotBoolNode::pass1(thread_db* tdbb, CompilerScratch* csb)
bool NotBoolNode::execute(thread_db* tdbb, jrd_req* request) const
{
bool value = EVL_boolean(tdbb, arg);
bool value = arg->execute(tdbb, request);
if (request->req_flags & req_null)
return false;
@ -1505,11 +1603,11 @@ BoolExprNode* NotBoolNode::process(DsqlCompilerScratch* dsqlScratch, bool invert
//--------------------
static RegisterNode<RseBoolNode> regRseBoolNodeAny(blr_any);
static RegisterNode<RseBoolNode> regRseBoolNodeUnique(blr_unique);
static RegisterNode<RseBoolNode> regRseBoolNodeAnsiAny(blr_ansi_any);
static RegisterNode<RseBoolNode> regRseBoolNodeAnsiAll(blr_ansi_all);
static RegisterNode<RseBoolNode> regRseBoolNodeExists(blr_exists); // ASF: Where is this handled?
static RegisterBoolNode<RseBoolNode> regRseBoolNodeAny(blr_any);
static RegisterBoolNode<RseBoolNode> regRseBoolNodeUnique(blr_unique);
static RegisterBoolNode<RseBoolNode> regRseBoolNodeAnsiAny(blr_ansi_any);
static RegisterBoolNode<RseBoolNode> regRseBoolNodeAnsiAll(blr_ansi_all);
static RegisterBoolNode<RseBoolNode> regRseBoolNodeExists(blr_exists); // ASF: Where is this handled?
RseBoolNode::RseBoolNode(MemoryPool& pool, UCHAR aBlrOp, dsql_nod* aDsqlRse)
: TypedNode<BoolExprNode, ExprNode::TYPE_RSE_BOOL>(pool),
@ -1521,7 +1619,7 @@ RseBoolNode::RseBoolNode(MemoryPool& pool, UCHAR aBlrOp, dsql_nod* aDsqlRse)
addChildNode(dsqlRse, rse);
}
DmlNode* RseBoolNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR blrOp)
BoolExprNode* RseBoolNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR blrOp)
{
RseBoolNode* node = FB_NEW(pool) RseBoolNode(pool, blrOp);
node->rse = PAR_parse_node(tdbb, csb, TYPE_RSE);
@ -1531,7 +1629,7 @@ DmlNode* RseBoolNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch*
void RseBoolNode::print(string& text, Array<dsql_nod*>& nodes) const
{
text.printf("RseBoolNode (%d)", blrOp);
ExprNode::print(text, nodes);
BoolExprNode::print(text, nodes);
}
BoolExprNode* RseBoolNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
@ -1564,16 +1662,29 @@ bool RseBoolNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const
return blrOp == o->blrOp;
}
bool RseBoolNode::expressionEqual(thread_db* tdbb, CompilerScratch* csb, /*const*/ ExprNode* other,
USHORT stream)
{
if (!BoolExprNode::expressionEqual(tdbb, csb, other, stream))
return false;
RseBoolNode* otherNode = other->as<RseBoolNode>();
fb_assert(otherNode);
return blrOp == otherNode->blrOp;
}
BoolExprNode* RseBoolNode::copy(thread_db* tdbb, NodeCopier& copier)
{
RseBoolNode* node = FB_NEW(*tdbb->getDefaultPool()) RseBoolNode(
*tdbb->getDefaultPool(), blrOp);
node->flags = flags;
node->rse = copier.copy(tdbb, rse);
return node;
}
ExprNode* RseBoolNode::pass1(thread_db* tdbb, CompilerScratch* csb)
BoolExprNode* RseBoolNode::pass1(thread_db* tdbb, CompilerScratch* csb)
{
switch (blrOp)
{
@ -1583,32 +1694,32 @@ ExprNode* RseBoolNode::pass1(thread_db* tdbb, CompilerScratch* csb)
if (newNode)
return newNode->pass1(tdbb, csb);
node->nod_flags |= nod_deoptimize;
flags |= FLAG_DEOPTIMIZE;
}
// fall into
case blr_ansi_any:
if (node->nod_flags & nod_deoptimize)
if (flags & FLAG_DEOPTIMIZE)
{
node->nod_flags &= ~nod_deoptimize;
flags &= ~FLAG_DEOPTIMIZE;
fb_assert(rse->nod_type == nod_class_recsrcnode_jrd);
RseNode* rseNode = reinterpret_cast<RseNode*>(rse->nod_arg[0]);
fb_assert(rseNode->type == RseNode::TYPE);
// Deoptimize the conjunct, not the ALL node itself
jrd_nod* boolean = rseNode->rse_boolean;
BoolExprNode* boolean = rseNode->rse_boolean;
if (boolean)
{
BinaryBoolNode* booleanNode = ExprNode::as<BinaryBoolNode>(boolean);
if (booleanNode && booleanNode->blrOp == blr_and)
boolean = booleanNode->arg2;
BinaryBoolNode* binaryNode = boolean->as<BinaryBoolNode>();
if (binaryNode && binaryNode->blrOp == blr_and)
boolean = binaryNode->arg2;
// Deoptimize the injected boolean of a quantified predicate
// when it's necessary. ALL predicate does not require an index scan.
// This fixes bug SF #543106.
boolean->nod_flags |= nod_deoptimize;
boolean->flags |= FLAG_DEOPTIMIZE;
}
}
// fall into
@ -1628,7 +1739,7 @@ ExprNode* RseBoolNode::pass1(thread_db* tdbb, CompilerScratch* csb)
return BoolExprNode::pass1(tdbb, csb);
}
ExprNode* RseBoolNode::pass2(thread_db* tdbb, CompilerScratch* csb)
void RseBoolNode::pass2Boolean1(thread_db* tdbb, CompilerScratch* csb)
{
fb_assert(rse->nod_type == nod_class_recsrcnode_jrd);
RseNode* rseNode = reinterpret_cast<RseNode*>(rse->nod_arg[0]);
@ -1636,16 +1747,21 @@ ExprNode* RseBoolNode::pass2(thread_db* tdbb, CompilerScratch* csb)
if (!(rseNode->flags & RseNode::FLAG_VARIANT))
{
node->nod_flags |= nod_invariant;
csb->csb_invariants.push(node);
flags |= FLAG_INVARIANT;
csb->csb_invariants.push(&impureOffset);
}
rseNode->pass2Rse(tdbb, csb);
}
BoolExprNode::pass2(tdbb, csb);
void RseBoolNode::pass2Boolean2(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);
if (node->nod_flags & nod_invariant)
csb->csb_impure += sizeof(impure_value);
if (flags & FLAG_INVARIANT)
impureOffset = CMP_impure(csb, sizeof(impure_value));
rsb = CMP_post_rse(tdbb, csb, rseNode);
@ -1655,15 +1771,13 @@ ExprNode* RseBoolNode::pass2(thread_db* tdbb, CompilerScratch* csb)
if (blrOp == blr_ansi_any || blrOp == blr_ansi_all)
{
const bool ansiAny = (blrOp == blr_ansi_any);
const bool ansiNot = (node->nod_flags & nod_ansi_not);
const bool ansiAny = blrOp == blr_ansi_any;
const bool ansiNot = flags & FLAG_ANSI_NOT;
FilteredStream* const filter = static_cast<FilteredStream*>(rsb.getObject());
filter->setAnyBoolean(rseNode->rse_boolean, ansiAny, ansiNot);
}
csb->csb_fors.add(rsb);
return this;
}
bool RseBoolNode::execute(thread_db* tdbb, jrd_req* request) const
@ -1671,9 +1785,9 @@ bool RseBoolNode::execute(thread_db* tdbb, jrd_req* request) const
USHORT* invariant_flags;
impure_value* impure;
if (node->nod_flags & nod_invariant)
if (flags & FLAG_INVARIANT)
{
impure = request->getImpure<impure_value>(node->nod_impure);
impure = request->getImpure<impure_value>(impureOffset);
invariant_flags = &impure->vlu_flags;
if (*invariant_flags & VLU_computed)
@ -1702,7 +1816,7 @@ bool RseBoolNode::execute(thread_db* tdbb, jrd_req* request) const
// If this is an invariant node, save the return value.
if (node->nod_flags & nod_invariant)
if (flags & FLAG_INVARIANT)
{
*invariant_flags |= VLU_computed;
@ -1738,7 +1852,7 @@ BoolExprNode* RseBoolNode::convertNeqAllToNotAny(thread_db* tdbb, CompilerScratc
if (!outerRse || outerRse->type != RseNode::TYPE || outerRse->rse_relations.getCount() != 1 ||
!outerRse->rse_boolean ||
!(outerRseNeq = ExprNode::as<ComparativeBoolNode>(outerRse->rse_boolean.getObject())) ||
!(outerRseNeq = outerRse->rse_boolean->as<ComparativeBoolNode>()) ||
outerRseNeq->blrOp != blr_neq)
{
return NULL;
@ -1755,25 +1869,16 @@ BoolExprNode* RseBoolNode::convertNeqAllToNotAny(thread_db* tdbb, CompilerScratc
BinaryBoolNode* orNode = FB_NEW(csb->csb_pool) BinaryBoolNode(csb->csb_pool, blr_or);
newNode->arg = PAR_make_node(tdbb, 1);
newNode->arg->nod_type = nod_class_exprnode_jrd;
newNode->arg->nod_count = 0;
newNode->arg->nod_arg[0] = reinterpret_cast<jrd_nod*>(orNode);
newNode->arg = orNode;
BinaryBoolNode* andNode = FB_NEW(csb->csb_pool) BinaryBoolNode(csb->csb_pool, blr_and);
orNode->arg1 = PAR_make_node(tdbb, 1);
orNode->arg1->nod_type = nod_class_exprnode_jrd;
orNode->arg1->nod_count = 0;
orNode->arg1->nod_arg[0] = reinterpret_cast<jrd_nod*>(andNode);
orNode->arg1 = andNode;
MissingBoolNode* missNode = FB_NEW(csb->csb_pool) MissingBoolNode(csb->csb_pool);
missNode->arg = outerRseNeq->arg1;
andNode->arg1 = PAR_make_node(tdbb, 1);
andNode->arg1->nod_type = nod_class_exprnode_jrd;
andNode->arg1->nod_count = 0;
andNode->arg1->nod_arg[0] = reinterpret_cast<jrd_nod*>(missNode);
andNode->arg1 = missNode;
RseBoolNode* rseBoolNode = FB_NEW(csb->csb_pool) RseBoolNode(csb->csb_pool, blr_any);
rseBoolNode->rse = PAR_make_node(tdbb, 1);
@ -1781,10 +1886,7 @@ BoolExprNode* RseBoolNode::convertNeqAllToNotAny(thread_db* tdbb, CompilerScratc
rseBoolNode->rse->nod_count = 0;
rseBoolNode->rse->nod_arg[0] = (jrd_nod*) innerRse;
andNode->arg2 = PAR_make_node(tdbb, 1);
andNode->arg2->nod_type = nod_class_exprnode_jrd;
andNode->arg2->nod_count = 0;
andNode->arg2->nod_arg[0] = reinterpret_cast<jrd_nod*>(rseBoolNode);
andNode->arg2 = rseBoolNode;
RseNode* newInnerRse = innerRse->clone();
@ -1794,27 +1896,16 @@ BoolExprNode* RseBoolNode::convertNeqAllToNotAny(thread_db* tdbb, CompilerScratc
rseBoolNode->rse->nod_count = 0;
rseBoolNode->rse->nod_arg[0] = (jrd_nod*) newInnerRse;
orNode->arg2 = PAR_make_node(tdbb, 1);
orNode->arg2->nod_type = nod_class_exprnode_jrd;
orNode->arg2->nod_count = 0;
orNode->arg2->nod_arg[0] = reinterpret_cast<jrd_nod*>(rseBoolNode);
orNode->arg2 = rseBoolNode;
orNode = FB_NEW(csb->csb_pool) BinaryBoolNode(csb->csb_pool, blr_or);
jrd_nod* boolean = PAR_make_node(tdbb, 1);
boolean->nod_type = nod_class_exprnode_jrd;
boolean->nod_count = 0;
boolean->nod_arg[0] = reinterpret_cast<jrd_nod*>(orNode);
BinaryBoolNode* boolean = FB_NEW(csb->csb_pool) BinaryBoolNode(csb->csb_pool, blr_or);
missNode = FB_NEW(csb->csb_pool) MissingBoolNode(csb->csb_pool);
missNode->arg = outerRseNeq->arg2;
orNode->arg1 = PAR_make_node(tdbb, 1);
orNode->arg1->nod_type = nod_class_exprnode_jrd;
orNode->arg1->nod_count = 0;
orNode->arg1->nod_arg[0] = reinterpret_cast<jrd_nod*>(missNode);
boolean->arg1 = missNode;
orNode->arg2 = outerRse->rse_boolean;
boolean->arg2 = outerRse->rse_boolean;
outerRseNeq->blrOp = blr_eql;
// If there was a boolean on the stream, append (AND) the new one
@ -1822,13 +1913,9 @@ BoolExprNode* RseBoolNode::convertNeqAllToNotAny(thread_db* tdbb, CompilerScratc
{
andNode = FB_NEW(csb->csb_pool) BinaryBoolNode(csb->csb_pool, blr_and);
jrd_nod* temp = PAR_make_node(tdbb, 1);
temp->nod_type = nod_class_exprnode_jrd;
temp->nod_count = 0;
temp->nod_arg[0] = reinterpret_cast<jrd_nod*>(andNode);
andNode->arg1 = newInnerRse->rse_boolean;
andNode->arg2 = boolean;
boolean = temp;
boolean = andNode;
}
newInnerRse->rse_boolean = boolean;

View File

@ -37,7 +37,7 @@ class BinaryBoolNode : public TypedNode<BoolExprNode, ExprNode::TYPE_BINARY_BOOL
public:
BinaryBoolNode(MemoryPool& pool, UCHAR aBlrOp, dsql_nod* aArg1 = NULL, dsql_nod* aArg2 = NULL);
static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR blrOp);
static BoolExprNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR blrOp);
virtual void print(Firebird::string& text, Firebird::Array<dsql_nod*>& nodes) const;
virtual BoolExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch);
@ -45,6 +45,8 @@ public:
virtual BoolExprNode* copy(thread_db* tdbb, NodeCopier& copier);
virtual bool dsqlMatch(const ExprNode* other, bool ignoreMapCast) const;
virtual bool expressionEqual(thread_db* tdbb, CompilerScratch* csb, /*const*/ ExprNode* other,
USHORT stream) /*const*/;
virtual bool execute(thread_db* tdbb, jrd_req* request) const;
private:
@ -55,8 +57,8 @@ public:
UCHAR blrOp;
dsql_nod* dsqlArg1;
dsql_nod* dsqlArg2;
NestConst<jrd_nod> arg1;
NestConst<jrd_nod> arg2;
NestConst<BoolExprNode> arg1;
NestConst<BoolExprNode> arg2;
};
@ -73,7 +75,7 @@ public:
ComparativeBoolNode(MemoryPool& pool, UCHAR aBlrOp, dsql_nod* aArg1 = NULL,
dsql_nod* aArg2 = NULL, dsql_nod* aArg3 = NULL);
static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR blrOp);
static BoolExprNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR blrOp);
virtual void print(Firebird::string& text, Firebird::Array<dsql_nod*>& nodes) const;
virtual BoolExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch);
@ -86,8 +88,11 @@ public:
virtual BoolExprNode* copy(thread_db* tdbb, NodeCopier& copier);
virtual bool dsqlMatch(const ExprNode* other, bool ignoreMapCast) const;
virtual ExprNode* pass1(thread_db* tdbb, CompilerScratch* csb);
virtual ExprNode* pass2(thread_db* tdbb, CompilerScratch* csb);
virtual bool expressionEqual(thread_db* tdbb, CompilerScratch* csb, /*const*/ ExprNode* other,
USHORT stream) /*const*/;
virtual BoolExprNode* pass1(thread_db* tdbb, CompilerScratch* csb);
virtual void pass2Boolean1(thread_db* tdbb, CompilerScratch* csb);
virtual void pass2Boolean2(thread_db* tdbb, CompilerScratch* csb);
virtual bool execute(thread_db* tdbb, jrd_req* request) const;
private:
@ -117,7 +122,7 @@ class MissingBoolNode : public TypedNode<BoolExprNode, ExprNode::TYPE_MISSING_BO
public:
MissingBoolNode(MemoryPool& pool, dsql_nod* aArg = NULL);
static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR blrOp);
static BoolExprNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR blrOp);
virtual void print(Firebird::string& text, Firebird::Array<dsql_nod*>& nodes) const;
virtual BoolExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch);
@ -129,8 +134,8 @@ public:
}
virtual BoolExprNode* copy(thread_db* tdbb, NodeCopier& copier);
virtual ExprNode* pass1(thread_db* tdbb, CompilerScratch* csb);
virtual ExprNode* pass2(thread_db* tdbb, CompilerScratch* csb);
virtual BoolExprNode* pass1(thread_db* tdbb, CompilerScratch* csb);
virtual void pass2Boolean2(thread_db* tdbb, CompilerScratch* csb);
virtual bool execute(thread_db* tdbb, jrd_req* request) const;
public:
@ -144,7 +149,7 @@ class NotBoolNode : public TypedNode<BoolExprNode, ExprNode::TYPE_NOT_BOOL>
public:
NotBoolNode(MemoryPool& pool, dsql_nod* aArg = NULL);
static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR blrOp);
static BoolExprNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR blrOp);
virtual void print(Firebird::string& text, Firebird::Array<dsql_nod*>& nodes) const;
virtual BoolExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch);
@ -156,7 +161,7 @@ public:
}
virtual BoolExprNode* copy(thread_db* tdbb, NodeCopier& copier);
virtual ExprNode* pass1(thread_db* tdbb, CompilerScratch* csb);
virtual BoolExprNode* pass1(thread_db* tdbb, CompilerScratch* csb);
virtual bool execute(thread_db* tdbb, jrd_req* request) const;
private:
@ -164,7 +169,7 @@ private:
public:
dsql_nod* dsqlArg;
NestConst<jrd_nod> arg;
NestConst<BoolExprNode> arg;
};
@ -173,7 +178,7 @@ class RseBoolNode : public TypedNode<BoolExprNode, ExprNode::TYPE_RSE_BOOL>
public:
RseBoolNode(MemoryPool& pool, UCHAR aBlrOp, dsql_nod* aDsqlRse = NULL);
static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR blrOp);
static BoolExprNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR blrOp);
virtual void print(Firebird::string& text, Firebird::Array<dsql_nod*>& nodes) const;
virtual BoolExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch);
@ -192,8 +197,11 @@ public:
virtual BoolExprNode* copy(thread_db* tdbb, NodeCopier& copier);
virtual bool dsqlMatch(const ExprNode* other, bool ignoreMapCast) const;
virtual ExprNode* pass1(thread_db* tdbb, CompilerScratch* csb);
virtual ExprNode* pass2(thread_db* tdbb, CompilerScratch* csb);
virtual bool expressionEqual(thread_db* tdbb, CompilerScratch* csb, /*const*/ ExprNode* other,
USHORT stream) /*const*/;
virtual BoolExprNode* pass1(thread_db* tdbb, CompilerScratch* csb);
virtual void pass2Boolean1(thread_db* tdbb, CompilerScratch* csb);
virtual void pass2Boolean2(thread_db* tdbb, CompilerScratch* csb);
virtual bool execute(thread_db* tdbb, jrd_req* request) const;
private:

View File

@ -31,6 +31,7 @@
#include "../jrd/Function.h"
#include "../jrd/SysFunction.h"
#include "../jrd/recsrc/RecordSource.h"
#include "../jrd/Optimizer.h"
#include "../jrd/blb_proto.h"
#include "../jrd/cmp_proto.h"
#include "../jrd/cvt_proto.h"
@ -129,6 +130,7 @@ bool ExprNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const
return false;
const dsql_nod* const* const* j = other->dsqlChildNodes.begin();
for (const dsql_nod* const* const* i = dsqlChildNodes.begin(); i != dsqlChildNodes.end(); ++i, ++j)
{
if (!PASS1_node_match(**i, **j, ignoreMapCast))
@ -138,17 +140,106 @@ bool ExprNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const
return true;
}
bool ExprNode::expressionEqual(thread_db* tdbb, CompilerScratch* csb, /*const*/ ExprNode* other,
USHORT stream) /*const*/
{
if (other->type != type)
return false;
size_t count = jrdChildNodes.getCount();
if (other->jrdChildNodes.getCount() != count)
return false;
JrdNode* j = other->jrdChildNodes.begin();
for (JrdNode* i = jrdChildNodes.begin(); i != jrdChildNodes.end(); ++i, ++j)
{
if (*i && *j)
{
if (i->jrdNode && j->jrdNode)
{
if (!OPT_expression_equal2(tdbb, csb, *i->jrdNode, *j->jrdNode, stream))
return false;
}
else if (i->boolExprNode && j->boolExprNode)
{
if (!(*i->boolExprNode)->expressionEqual(tdbb, csb, *j->boolExprNode, stream))
return false;
}
else
return false;
}
}
return true;
}
bool ExprNode::computable(CompilerScratch* csb, SSHORT stream, bool idxUse,
bool allowOnlyCurrentStream)
{
for (JrdNode* i = jrdChildNodes.begin(); i != jrdChildNodes.end(); ++i)
{
if (*i)
{
if (i->jrdNode)
{
if (!OPT_computable(csb, *i->jrdNode, stream, idxUse, allowOnlyCurrentStream))
return false;
}
else if (i->boolExprNode)
{
if (!(*i->boolExprNode)->computable(csb, stream, idxUse, allowOnlyCurrentStream))
return false;
}
}
}
return true;
}
void ExprNode::findDependentFromStreams(const OptimizerRetrieval* optRet, SortedStreamList* streamList)
{
for (JrdNode* i = jrdChildNodes.begin(); i != jrdChildNodes.end(); ++i)
{
if (*i)
{
if (i->jrdNode)
optRet->findDependentFromStreams(*i->jrdNode, streamList);
else if (i->boolExprNode)
(*i->boolExprNode)->findDependentFromStreams(optRet, streamList);
}
}
}
ExprNode* ExprNode::pass1(thread_db* tdbb, CompilerScratch* csb)
{
for (NestConst<NestConst<jrd_nod> >* i = jrdChildNodes.begin(); i != jrdChildNodes.end(); ++i)
**i = CMP_pass1(tdbb, csb, **i);
for (JrdNode* i = jrdChildNodes.begin(); i != jrdChildNodes.end(); ++i)
{
if (*i)
{
if (i->jrdNode)
*i->jrdNode = CMP_pass1(tdbb, csb, *i->jrdNode);
else if (i->boolExprNode)
*i->boolExprNode = (*i->boolExprNode)->pass1(tdbb, csb);
}
}
return this;
}
ExprNode* ExprNode::pass2(thread_db* tdbb, CompilerScratch* csb)
{
for (NestConst<NestConst<jrd_nod> >* i = jrdChildNodes.begin(); i != jrdChildNodes.end(); ++i)
**i = CMP_pass2(tdbb, csb, **i, node);
for (JrdNode* i = jrdChildNodes.begin(); i != jrdChildNodes.end(); ++i)
{
if (*i)
{
if (i->jrdNode)
*i->jrdNode = CMP_pass2(tdbb, csb, *i->jrdNode, node);
else if (i->boolExprNode)
*i->boolExprNode = (*i->boolExprNode)->pass2(tdbb, csb);
}
}
return this;
}
@ -156,8 +247,8 @@ bool ExprNode::jrdVisit(JrdNodeVisitor& visitor)
{
bool ret = false;
for (NestConst<NestConst<jrd_nod> >* i = jrdChildNodes.begin(); i != jrdChildNodes.end(); ++i)
ret |= visitor.visit(**i);
for (JrdNode* i = jrdChildNodes.begin(); i != jrdChildNodes.end(); ++i)
ret |= visitor.visit(*i);
return ret;
}
@ -1287,6 +1378,35 @@ bool ArithmeticNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const
return dialect1 == o->dialect1 && blrOp == o->blrOp;
}
bool ArithmeticNode::expressionEqual(thread_db* tdbb, CompilerScratch* csb, /*const*/ ExprNode* other,
USHORT stream)
{
ArithmeticNode* otherNode = other->as<ArithmeticNode>();
if (!otherNode || blrOp != otherNode->blrOp || dialect1 != otherNode->dialect1)
return false;
if (OPT_expression_equal2(tdbb, csb, arg1, otherNode->arg1, stream) &&
OPT_expression_equal2(tdbb, csb, arg2, otherNode->arg2, stream))
{
return true;
}
if (blrOp == blr_add || blrOp == blr_multiply)
{
// A + B is equivalent to B + A, ditto for A * B and B * A.
// Note: If one expression is A + B + C, but the other is B + C + A we won't
// necessarily match them.
if (OPT_expression_equal2(tdbb, csb, arg1, otherNode->arg2, stream) &&
OPT_expression_equal2(tdbb, csb, arg2, otherNode->arg1, stream))
{
return true;
}
}
return false;
}
ExprNode* ArithmeticNode::pass2(thread_db* tdbb, CompilerScratch* csb)
{
ExprNode::pass2(tdbb, csb);
@ -3784,7 +3904,7 @@ ExprNode* SubstringSimilarNode::pass1(thread_db* tdbb, CompilerScratch* csb)
ExprNode* SubstringSimilarNode::pass2(thread_db* tdbb, CompilerScratch* csb)
{
if (node->nod_flags & nod_invariant)
csb->csb_invariants.push(node);
csb->csb_invariants.push(&node->nod_impure);
ExprNode::pass2(tdbb, csb);
@ -4016,6 +4136,18 @@ bool SysFuncCallNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const
return name == otherNode->name;
}
bool SysFuncCallNode::expressionEqual(thread_db* tdbb, CompilerScratch* csb, /*const*/ ExprNode* other,
USHORT stream)
{
if (!ExprNode::expressionEqual(tdbb, csb, other, stream))
return false;
SysFuncCallNode* otherNode = other->as<SysFuncCallNode>();
fb_assert(otherNode);
return function && function == otherNode->function;
}
ExprNode* SysFuncCallNode::pass2(thread_db* tdbb, CompilerScratch* csb)
{
ExprNode::pass2(tdbb, csb);
@ -4234,6 +4366,18 @@ bool UdfCallNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const
return name == otherNode->name;
}
bool UdfCallNode::expressionEqual(thread_db* tdbb, CompilerScratch* csb, /*const*/ ExprNode* other,
USHORT stream)
{
if (!ExprNode::expressionEqual(tdbb, csb, other, stream))
return false;
UdfCallNode* otherNode = other->as<UdfCallNode>();
fb_assert(otherNode);
return function && function == otherNode->function;
}
ExprNode* UdfCallNode::pass1(thread_db* tdbb, CompilerScratch* csb)
{
ExprNode::pass1(tdbb, csb);
@ -4319,6 +4463,118 @@ ValueExprNode* UdfCallNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
//--------------------
static RegisterNode<ValueIfNode> regValueIfNode(blr_value_if);
ValueIfNode::ValueIfNode(MemoryPool& pool, dsql_nod* aCondition, dsql_nod* aTrueValue,
dsql_nod* aFalseValue)
: TypedNode<ValueExprNode, ExprNode::TYPE_VALUE_IF>(pool),
dsqlCondition(aCondition),
dsqlTrueValue(aTrueValue),
dsqlFalseValue(aFalseValue),
condition(NULL),
trueValue(NULL),
falseValue(NULL)
{
addChildNode(dsqlCondition, condition);
addChildNode(dsqlTrueValue, trueValue);
addChildNode(dsqlFalseValue, falseValue);
}
DmlNode* ValueIfNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR /*blrOp*/)
{
ValueIfNode* node = FB_NEW(pool) ValueIfNode(pool);
node->condition = PAR_parse_boolean(tdbb, csb);
node->trueValue = PAR_parse_node(tdbb, csb, VALUE);
node->falseValue = PAR_parse_node(tdbb, csb, VALUE);
return node;
}
void ValueIfNode::print(string& text, Array<dsql_nod*>& nodes) const
{
text = "ValueIfNode";
ExprNode::print(text, nodes);
}
ValueExprNode* ValueIfNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
{
ValueIfNode* node = FB_NEW(getPool()) ValueIfNode(getPool(),
PASS1_node(dsqlScratch, dsqlCondition),
PASS1_node(dsqlScratch, dsqlTrueValue),
PASS1_node(dsqlScratch, dsqlFalseValue));
PASS1_set_parameter_type(dsqlScratch, node->dsqlTrueValue, node->dsqlFalseValue, false);
PASS1_set_parameter_type(dsqlScratch, node->dsqlFalseValue, node->dsqlTrueValue, false);
return node;
}
void ValueIfNode::setParameterName(dsql_par* parameter) const
{
parameter->par_name = parameter->par_alias = "CASE";
}
bool ValueIfNode::setParameterType(DsqlCompilerScratch* dsqlScratch,
dsql_nod* node, bool forceVarChar) const
{
return PASS1_set_parameter_type(dsqlScratch, dsqlTrueValue, node, forceVarChar) |
PASS1_set_parameter_type(dsqlScratch, dsqlFalseValue, node, forceVarChar);
}
void ValueIfNode::genBlr(DsqlCompilerScratch* dsqlScratch)
{
dsqlScratch->appendUChar(blr_value_if);
GEN_expr(dsqlScratch, dsqlCondition);
GEN_expr(dsqlScratch, dsqlTrueValue);
GEN_expr(dsqlScratch, dsqlFalseValue);
}
void ValueIfNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc, dsql_nod* /*nullReplacement*/)
{
Array<const dsc*> args;
MAKE_desc(dsqlScratch, &dsqlTrueValue->nod_desc, dsqlTrueValue, NULL);
args.add(&dsqlTrueValue->nod_desc);
MAKE_desc(dsqlScratch, &dsqlFalseValue->nod_desc, dsqlFalseValue, NULL);
args.add(&dsqlFalseValue->nod_desc);
DSqlDataTypeUtil(dsqlScratch).makeFromList(desc, "CASE", args.getCount(), args.begin());
}
void ValueIfNode::getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc)
{
CMP_get_desc(tdbb, csb, (trueValue->nod_type != nod_null ? trueValue : falseValue), desc);
}
ValueExprNode* ValueIfNode::copy(thread_db* tdbb, NodeCopier& copier)
{
ValueIfNode* node = FB_NEW(*tdbb->getDefaultPool()) ValueIfNode(*tdbb->getDefaultPool());
node->condition = condition->copy(tdbb, copier);
node->trueValue = copier.copy(tdbb, trueValue);
node->falseValue = copier.copy(tdbb, falseValue);
return node;
}
ExprNode* ValueIfNode::pass2(thread_db* tdbb, CompilerScratch* csb)
{
ExprNode::pass2(tdbb, csb);
dsc desc;
getDesc(tdbb, csb, &desc);
node->nod_impure = CMP_impure(csb, sizeof(impure_value));
return this;
}
dsc* ValueIfNode::execute(thread_db* tdbb, jrd_req* request) const
{
return EVL_expr(tdbb, (condition->execute(tdbb, request) ? trueValue : falseValue));
}
//--------------------
// Firebird provides transparent conversion from string to date in
// contexts where it makes sense. This macro checks a descriptor to
// see if it is something that *could* represent a date value

View File

@ -51,6 +51,8 @@ public:
virtual void getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc);
virtual ValueExprNode* copy(thread_db* tdbb, NodeCopier& copier);
virtual bool dsqlMatch(const ExprNode* other, bool ignoreMapCast) const;
virtual bool expressionEqual(thread_db* tdbb, CompilerScratch* csb, /*const*/ ExprNode* other,
USHORT stream) /*const*/;
virtual ExprNode* pass2(thread_db* tdbb, CompilerScratch* csb);
virtual dsc* execute(thread_db* tdbb, jrd_req* request) const;
@ -388,6 +390,8 @@ public:
virtual void getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc);
virtual ValueExprNode* copy(thread_db* tdbb, NodeCopier& copier);
virtual bool dsqlMatch(const ExprNode* other, bool ignoreMapCast) const;
virtual bool expressionEqual(thread_db* tdbb, CompilerScratch* csb, /*const*/ ExprNode* other,
USHORT stream) /*const*/;
virtual ExprNode* pass2(thread_db* tdbb, CompilerScratch* csb);
virtual dsc* execute(thread_db* tdbb, jrd_req* request) const;
@ -417,6 +421,8 @@ public:
virtual void getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc);
virtual ValueExprNode* copy(thread_db* tdbb, NodeCopier& copier);
virtual bool dsqlMatch(const ExprNode* other, bool ignoreMapCast) const;
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;
@ -432,6 +438,42 @@ private:
};
class ValueIfNode : public TypedNode<ValueExprNode, ExprNode::TYPE_VALUE_IF>
{
public:
ValueIfNode(MemoryPool& pool, dsql_nod* aCondition = NULL, dsql_nod* aTrueValue = NULL,
dsql_nod* aFalseValue = 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 bool setParameterType(DsqlCompilerScratch* dsqlScratch,
dsql_nod* node, bool forceVarChar) const;
virtual void genBlr(DsqlCompilerScratch* dsqlScratch);
virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc, dsql_nod* nullReplacement);
virtual bool jrdPossibleUnknownFinder(PossibleUnknownFinder& /*visitor*/)
{
return true;
}
virtual void getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc);
virtual ValueExprNode* copy(thread_db* tdbb, NodeCopier& copier);
virtual ExprNode* pass2(thread_db* tdbb, CompilerScratch* csb);
virtual dsc* execute(thread_db* tdbb, jrd_req* request) const;
public:
dsql_nod* dsqlCondition;
dsql_nod* dsqlTrueValue;
dsql_nod* dsqlFalseValue;
NestConst<BoolExprNode> condition;
NestConst<jrd_nod> trueValue;
NestConst<jrd_nod> falseValue;
};
} // namespace
#endif // DSQL_EXPR_NODES_H

View File

@ -38,11 +38,38 @@ class Cursor;
class dsql_nod;
class ExprNode;
class jrd_nod;
class OptimizerRetrieval;
class RseNode;
class SlidingWindow;
class TypeClause;
// Must be less then MAX_SSHORT. Not used for static arrays.
const int MAX_CONJUNCTS = 32000;
// Note that MAX_STREAMS currently MUST be <= MAX_UCHAR.
// Here we should really have a compile-time fb_assert, since this hard-coded
// limit is NOT negotiable so long as we use an array of UCHAR, where index 0
// tells how many streams are in the array (and the streams themselves are
// identified by a UCHAR).
const int MAX_STREAMS = 255;
// This is number of ULONG's needed to store bit-mapped flags for all streams
// OPT_STREAM_BITS = (MAX_STREAMS + 1) / sizeof(ULONG)
// This value cannot be increased simple way. Decrease is possible, but it is also
// hardcoded in several places such as TEST_DEP_ARRAYS macro
const int OPT_STREAM_BITS = 8;
// Number of streams, conjuncts, indices that will be statically allocated
// in various arrays. Larger numbers will have to be allocated dynamically
const int OPT_STATIC_ITEMS = 16;
typedef Firebird::HalfStaticArray<UCHAR, OPT_STATIC_ITEMS> StreamsArray;
typedef Firebird::SortedArray<int> SortedStreamList;
typedef UCHAR stream_array_t[MAX_STREAMS + 1];
template <typename T>
class RegisterNode
{
@ -53,6 +80,16 @@ public:
}
};
template <typename T>
class RegisterBoolNode
{
public:
explicit RegisterBoolNode(UCHAR blr)
{
PAR_register(blr, T::parse);
}
};
class Node : public Firebird::PermanentStorage
{
@ -235,7 +272,8 @@ public:
TYPE_RSE_BOOL,
TYPE_SUBSTRING_SIMILAR,
TYPE_SYSFUNC_CALL,
TYPE_UDF_CALL
TYPE_UDF_CALL,
TYPE_VALUE_IF
};
explicit ExprNode(Type aType, MemoryPool& pool)
@ -333,9 +371,9 @@ public:
{
visitor.nodeFound = node;
for (NestConst<NestConst<jrd_nod> >* i = jrdChildNodes.begin(); i != jrdChildNodes.end(); ++i)
for (JrdNode* i = jrdChildNodes.begin(); i != jrdChildNodes.end(); ++i)
{
if (!visitor.visit(**i))
if (!visitor.visit(*i))
return false;
}
@ -351,6 +389,12 @@ public:
return this;
}
virtual bool expressionEqual(thread_db* tdbb, CompilerScratch* csb, /*const*/ ExprNode* other,
USHORT stream) /*const*/;
virtual bool computable(CompilerScratch* csb, SSHORT stream, bool idxUse,
bool allowOnlyCurrentStream);
virtual void findDependentFromStreams(const OptimizerRetrieval* optRet,
SortedStreamList* streamList);
virtual ExprNode* pass1(thread_db* tdbb, CompilerScratch* csb);
virtual ExprNode* pass2(thread_db* tdbb, CompilerScratch* csb);
virtual ExprNode* copy(thread_db* tdbb, NodeCopier& copier) = 0;
@ -360,10 +404,10 @@ protected:
virtual bool dsqlVisit(NonConstDsqlNodeVisitor& visitor);
virtual bool jrdVisit(JrdNodeVisitor& visitor);
void addChildNode(dsql_nod*& dsqlNode, NestConst<jrd_nod>& jrdNode)
void addChildNode(dsql_nod*& dsqlNode, const JrdNode& jrdNode)
{
dsqlChildNodes.add(&dsqlNode);
jrdChildNodes.add(&jrdNode);
jrdChildNodes.add(jrdNode);
}
void addChildNode(dsql_nod*& dsqlNode)
@ -375,14 +419,20 @@ public:
const Type type;
const char* dsqlCompatDialectVerb;
Firebird::Array<dsql_nod**> dsqlChildNodes;
Firebird::Array<NestConst<NestConst<jrd_nod> > > jrdChildNodes;
Firebird::Array<JrdNode> jrdChildNodes;
};
class BoolExprNode : public ExprNode
{
public:
static const unsigned FLAG_DEOPTIMIZE = 0x1; // Boolean which requires deoptimization.
static const unsigned FLAG_ANSI_NOT = 0x2; // ANY/ALL predicate is prefixed with a NOT one.
static const unsigned FLAG_INVARIANT = 0x4; // Node is recognized as being invariant.
BoolExprNode(Type aType, MemoryPool& pool)
: ExprNode(aType, pool)
: ExprNode(aType, pool),
impureOffset(0),
flags(0)
{
}
@ -392,8 +442,31 @@ public:
return this;
}
virtual bool computable(CompilerScratch* csb, SSHORT stream, bool idxUse,
bool allowOnlyCurrentStream);
virtual BoolExprNode* pass1(thread_db* tdbb, CompilerScratch* csb)
{
ExprNode::pass1(tdbb, csb);
return this;
}
virtual BoolExprNode* pass2(thread_db* tdbb, CompilerScratch* csb);
virtual void pass2Boolean1(thread_db* tdbb, CompilerScratch* csb)
{
}
virtual void pass2Boolean2(thread_db* tdbb, CompilerScratch* csb)
{
}
virtual BoolExprNode* copy(thread_db* tdbb, NodeCopier& copier) = 0;
virtual bool execute(thread_db* tdbb, jrd_req* request) const = 0;
public:
ULONG impureOffset;
unsigned flags;
};
class ValueExprNode : public ExprNode

View File

@ -109,7 +109,7 @@ DmlNode* IfNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb,
{
IfNode* node = FB_NEW(pool) IfNode(pool);
node->condition = PAR_parse_node(tdbb, csb, TYPE_BOOL);
node->condition = PAR_parse_boolean(tdbb, csb);
node->trueAction = PAR_parse_node(tdbb, csb, STATEMENT);
if (csb->csb_blr_reader.peekByte() == (UCHAR) blr_end)
csb->csb_blr_reader.getByte(); // skip blr_end
@ -154,7 +154,7 @@ void IfNode::genBlr(DsqlCompilerScratch* dsqlScratch)
IfNode* IfNode::pass1(thread_db* tdbb, CompilerScratch* csb)
{
condition = CMP_pass1(tdbb, csb, condition);
condition = condition->pass1(tdbb, csb);
trueAction = CMP_pass1(tdbb, csb, trueAction);
falseAction = CMP_pass1(tdbb, csb, falseAction);
return this;
@ -163,7 +163,7 @@ IfNode* IfNode::pass1(thread_db* tdbb, CompilerScratch* csb)
IfNode* IfNode::pass2(thread_db* tdbb, CompilerScratch* csb)
{
condition = CMP_pass2(tdbb, csb, condition, node);
condition = condition->pass2(tdbb, csb);
trueAction = CMP_pass2(tdbb, csb, trueAction, node);
falseAction = CMP_pass2(tdbb, csb, falseAction, node);
return this;
@ -174,7 +174,7 @@ const jrd_nod* IfNode::execute(thread_db* tdbb, jrd_req* request) const
{
if (request->req_operation == jrd_req::req_evaluate)
{
if (EVL_boolean(tdbb, condition))
if (condition->execute(tdbb, request))
{
request->req_operation = jrd_req::req_evaluate;
return trueAction;

View File

@ -62,7 +62,7 @@ public:
dsql_nod* dsqlCondition;
dsql_nod* dsqlTrueAction;
dsql_nod* dsqlFalseAction;
NestConst<jrd_nod> condition;
NestConst<BoolExprNode> condition;
NestConst<jrd_nod> trueAction;
NestConst<jrd_nod> falseAction;
};

View File

@ -26,6 +26,7 @@
#include "../dsql/node.h"
#include "../common/classes/array.h"
#include "../common/classes/auto.h"
#include "../common/classes/NestConst.h"
namespace Jrd {
@ -283,6 +284,49 @@ public:
};
// Stores a reference to jrd_nod or BoolExprNode.
class JrdNode
{
public:
JrdNode(jrd_nod*& aJrdNode)
: jrdNode(&aJrdNode),
boolExprNode(NULL)
{
}
JrdNode(NestConst<jrd_nod>& aJrdNode)
: jrdNode(aJrdNode.getAddress()),
boolExprNode(NULL)
{
}
JrdNode(NestConst<BoolExprNode>& aBoolExprNode)
: jrdNode(NULL),
boolExprNode(aBoolExprNode.getAddress())
{
}
JrdNode()
: jrdNode(NULL),
boolExprNode(NULL)
{
}
bool operator !() const
{
return !((jrdNode && *jrdNode) || (boolExprNode && *boolExprNode));
}
operator bool() const
{
return (jrdNode && *jrdNode) || (boolExprNode && *boolExprNode);
}
jrd_nod** jrdNode;
BoolExprNode** boolExprNode;
};
class JrdNodeVisitor
{
public:
@ -295,9 +339,9 @@ public:
}
public:
bool visitChildren(jrd_nod* node);
bool visitChildren(const JrdNode& node);
virtual bool visit(jrd_nod* node) = 0;
virtual bool visit(const JrdNode& node) = 0;
private:
bool call(ExprNode* exprNode)
@ -318,13 +362,13 @@ public:
PossibleUnknownFinder();
public:
static bool find(jrd_nod* node)
static bool find(const JrdNode& node)
{
return PossibleUnknownFinder().visit(node);
}
protected:
virtual bool visit(jrd_nod* node);
virtual bool visit(const JrdNode& node);
};
// Search if somewhere in the expression the given stream is used.
@ -335,13 +379,13 @@ public:
StreamFinder(CompilerScratch* aCsb, UCHAR aStream);
public:
static bool find(CompilerScratch* csb, UCHAR stream, jrd_nod* node)
static bool find(CompilerScratch* csb, UCHAR stream, const JrdNode& node)
{
return StreamFinder(csb, stream).visit(node);
}
protected:
virtual bool visit(jrd_nod* node);
virtual bool visit(const JrdNode& node);
private:
CompilerScratch* const csb;
@ -355,13 +399,13 @@ public:
StreamsCollector(Firebird::SortedArray<int>& aStreams);
public:
static bool collect(jrd_nod* node, Firebird::SortedArray<int>& streams)
static bool collect(const JrdNode& node, Firebird::SortedArray<int>& streams)
{
return StreamsCollector(streams).visit(node);
}
protected:
virtual bool visit(jrd_nod* node);
virtual bool visit(const JrdNode& node);
private:
Firebird::SortedArray<int>& streams;
@ -371,22 +415,22 @@ private:
class UnmappedNodeGetter : public JrdNodeVisitor
{
public:
UnmappedNodeGetter(const MapNode* aMap, UCHAR aShellStream);
UnmappedNodeGetter(/*const*/ MapNode* aMap, UCHAR aShellStream);
static jrd_nod* get(const MapNode* map, UCHAR shellStream, jrd_nod* node)
static JrdNode get(/*const*/ MapNode* map, UCHAR shellStream, const JrdNode& node)
{
UnmappedNodeGetter obj(map, shellStream);
return obj.visit(node) && !obj.invalid ? obj.nodeFound : NULL;
return obj.visit(node) && !obj.invalid ? obj.nodeFound : JrdNode();
}
virtual bool visit(jrd_nod* node);
virtual bool visit(const JrdNode& node);
public:
const MapNode* map;
/*const*/ MapNode* map;
const UCHAR shellStream;
bool rootNode;
bool invalid;
jrd_nod* nodeFound;
JrdNode nodeFound;
};

View File

@ -74,10 +74,11 @@ DmlNode* WinFuncNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch*
if (count != 0)
{
NestConst<NestConst<jrd_nod> >* arg = node->jrdChildNodes.begin();
JrdNode* arg = node->jrdChildNodes.begin();
do
{
**arg++ = PAR_parse_node(tdbb, csb, VALUE);
*arg->jrdNode = PAR_parse_node(tdbb, csb, VALUE);
++arg;
} while (--count);
}

View File

@ -747,7 +747,7 @@ void MAKE_desc_from_list(DsqlCompilerScratch* dsqlScratch, dsc* desc, dsql_nod*
dsql_nod* null_replacement,
const TEXT* expression_name)
{
Firebird::Array<const dsc*> args;
Array<const dsc*> args;
fb_assert(node->nod_type == nod_list);

View File

@ -5775,7 +5775,7 @@ case_abbreviation
$3);
}
| IIF '(' search_condition ',' value ',' value ')'
{ $$ = make_node (nod_searched_case, 2, make_node (nod_list, 2, $3, $5), $7); }
{ $$ = makeClassNode(FB_NEW(getPool()) ValueIfNode(getPool(), $3, $5, $7)); }
| COALESCE '(' value ',' value_list ')'
{ $$ = make_node (nod_coalesce, 2, $3, $5); }
| DECODE '(' value ',' decode_pairs ')'

View File

@ -334,7 +334,7 @@ Function* Function::loadMetadata(thread_db* tdbb, USHORT id, bool noscan, USHORT
try
{
parameter->prm_default_value =
MET_parse_blob(tdbb, NULL, &default_value, NULL, NULL, false);
MET_parse_blob(tdbb, NULL, &default_value, NULL, NULL, false, false);
}
catch (const Exception&)
{
@ -594,7 +594,7 @@ void Function::parseBlr(thread_db* tdbb, bid* blob_id, CompilerScratch* csb)
statement = NULL;
}
MET_parse_blob(tdbb, NULL, blob_id, &csb, &statement, false);
MET_parse_blob(tdbb, NULL, blob_id, &csb, &statement, false, false);
statement->function = this;
setStatement(statement);
}

View File

@ -138,8 +138,7 @@ JrdStatement::JrdStatement(thread_db* tdbb, MemoryPool* p, CompilerScratch* csb)
// make a vector of all invariant-type nodes, so that we will
// be able to easily reinitialize them when we restart the request
for (Array<jrd_nod*>::iterator i = csb->csb_invariants.begin(); i != csb->csb_invariants.end(); ++i)
invariants.add(*i);
invariants.join(csb->csb_invariants);
rpbsSetup.grow(csb->csb_n_stream);

View File

@ -77,7 +77,7 @@ public:
const jrd_nod* topNode; // top of execution tree
Firebird::Array<const RecordSource*> fors; // record sources
Firebird::Array<const jrd_nod*> execStmts; // exec_into nodes
Firebird::Array<const jrd_nod*> invariants; // invariant nodes
Firebird::Array<ULONG*> invariants; // pointer to nodes invariant offsets
Firebird::RefStrPtr sqlText; // SQL text (encoded in the metadata charset)
Firebird::Array<UCHAR> blr; // BLR for non-SQL query
MapFieldInfo mapFieldInfo; // Map field name to field info

View File

@ -91,9 +91,6 @@ bool OPT_computable(CompilerScratch* csb, jrd_nod* node, SSHORT stream,
DEV_BLKCHK(csb, type_csb);
DEV_BLKCHK(node, type_nod);
if (node->nod_flags & nod_deoptimize)
return false;
// Recurse thru interesting sub-nodes
switch (node->nod_type)
@ -105,18 +102,7 @@ bool OPT_computable(CompilerScratch* csb, jrd_nod* node, SSHORT stream,
case nod_class_exprnode_jrd:
{
ExprNode* exprNode = reinterpret_cast<ExprNode*>(node->nod_arg[0]);
for (NestConst<NestConst<jrd_nod> >* i = exprNode->jrdChildNodes.begin();
i != exprNode->jrdChildNodes.end(); ++i)
{
if (**i)
{
if (!OPT_computable(csb, **i, stream, idx_use, allowOnlyCurrentStream))
return false;
}
}
break;
return exprNode->computable(csb, stream, idx_use, allowOnlyCurrentStream);
}
default:
@ -308,182 +294,8 @@ bool OPT_expression_equal2(thread_db* tdbb, CompilerScratch* csb,
{
ExprNode* exprNode1 = reinterpret_cast<ExprNode*>(node1->nod_arg[0]);
ExprNode* exprNode2 = reinterpret_cast<ExprNode*>(node2->nod_arg[0]);
Array<NestConst<NestConst<jrd_nod> > >& children1 = exprNode1->jrdChildNodes;
Array<NestConst<NestConst<jrd_nod> > >& children2 = exprNode2->jrdChildNodes;
if (exprNode1->type != exprNode2->type || children1.getCount() != children2.getCount())
return false;
switch (exprNode1->type)
{
case ExprNode::TYPE_SYSFUNC_CALL:
case ExprNode::TYPE_UDF_CALL:
switch (exprNode1->type)
{
case ExprNode::TYPE_SYSFUNC_CALL:
if (!exprNode1->as<SysFuncCallNode>()->function ||
exprNode1->as<SysFuncCallNode>()->function != exprNode2->as<SysFuncCallNode>()->function)
{
return false;
}
break;
case ExprNode::TYPE_UDF_CALL:
if (!exprNode1->as<UdfCallNode>()->function ||
exprNode1->as<UdfCallNode>()->function != exprNode2->as<UdfCallNode>()->function)
{
return false;
}
break;
}
// fall into
case ExprNode::TYPE_CONCATENATE:
case ExprNode::TYPE_CURRENT_DATE:
case ExprNode::TYPE_CURRENT_TIME:
case ExprNode::TYPE_CURRENT_TIMESTAMP:
case ExprNode::TYPE_CURRENT_ROLE:
case ExprNode::TYPE_CURRENT_USER:
case ExprNode::TYPE_INTERNAL_INFO:
case ExprNode::TYPE_NEGATE:
case ExprNode::TYPE_SUBSTRING_SIMILAR:
for (NestConst<NestConst<jrd_nod> >* i = children1.begin(), *j = children2.begin();
i != children1.end(); ++i, ++j)
{
if (!OPT_expression_equal2(tdbb, csb, **i, **j, stream))
return false;
}
return true;
case ExprNode::TYPE_ARITHMETIC:
{
ArithmeticNode* arithmeticNode1 = static_cast<ArithmeticNode*>(exprNode1);
ArithmeticNode* arithmeticNode2 = static_cast<ArithmeticNode*>(exprNode2);
if (arithmeticNode1->blrOp != arithmeticNode2->blrOp ||
arithmeticNode1->dialect1 != arithmeticNode2->dialect1)
{
return false;
}
if (OPT_expression_equal2(tdbb, csb, arithmeticNode1->arg1, arithmeticNode2->arg1, stream) &&
OPT_expression_equal2(tdbb, csb, arithmeticNode1->arg2, arithmeticNode2->arg2, stream))
{
return true;
}
if (arithmeticNode1->blrOp == blr_add || arithmeticNode1->blrOp == blr_multiply)
{
// A+B is equivalent to B+A, ditto A*B and B*A
// Note: If one expression is A+B+C, but the other is B+C+A we won't
// necessarily match them.
if (OPT_expression_equal2(tdbb, csb,
arithmeticNode1->arg1, arithmeticNode2->arg2, stream) &&
OPT_expression_equal2(tdbb, csb,
arithmeticNode1->arg2, arithmeticNode2->arg1, stream))
{
return true;
}
}
return false;
}
case ExprNode::TYPE_BINARY_BOOL:
{
BinaryBoolNode* booleanNode1 = static_cast<BinaryBoolNode*>(exprNode1);
BinaryBoolNode* booleanNode2 = static_cast<BinaryBoolNode*>(exprNode2);
if (booleanNode1->blrOp != booleanNode2->blrOp)
return false;
if (OPT_expression_equal2(tdbb, csb, booleanNode1->arg1, booleanNode2->arg1, stream) &&
OPT_expression_equal2(tdbb, csb, booleanNode1->arg2, booleanNode2->arg2, stream))
{
return true;
}
// A AND B is equivalent to B AND A. So as OR.
if (OPT_expression_equal2(tdbb, csb,
booleanNode1->arg1, booleanNode2->arg2, stream) &&
OPT_expression_equal2(tdbb, csb,
booleanNode1->arg2, booleanNode2->arg1, stream))
{
return true;
}
return false;
}
case ExprNode::TYPE_COMPARATIVE_BOOL:
{
ComparativeBoolNode* cmpNode1 = static_cast<ComparativeBoolNode*>(exprNode1);
ComparativeBoolNode* cmpNode2 = static_cast<ComparativeBoolNode*>(exprNode2);
if (cmpNode1->blrOp != cmpNode2->blrOp)
return false;
NestConst<NestConst<jrd_nod> >* i = cmpNode1->jrdChildNodes.begin();
NestConst<NestConst<jrd_nod> >* j = cmpNode2->jrdChildNodes.begin();
bool matching = true;
for (; matching && i != cmpNode1->jrdChildNodes.end(); ++i, ++j)
{
if (**i && **j)
matching = OPT_expression_equal2(tdbb, csb, **i, **j, stream);
else
matching = !**i && !**j;
}
if (matching)
return true;
// TODO match A > B to B <= A, etc
if (cmpNode1->blrOp == blr_eql || cmpNode1->blrOp == blr_equiv ||
cmpNode1->blrOp == blr_neq)
{
// A = B is equivalent to B = A.
if (OPT_expression_equal2(tdbb, csb, cmpNode1->arg1, cmpNode2->arg2, stream) &&
OPT_expression_equal2(tdbb, csb, cmpNode1->arg2, cmpNode2->arg1, stream))
{
return true;
}
}
return false;
}
case ExprNode::TYPE_MISSING_BOOL:
{
MissingBoolNode* missingNode1 = static_cast<MissingBoolNode*>(exprNode1);
MissingBoolNode* missingNode2 = static_cast<MissingBoolNode*>(exprNode2);
return OPT_expression_equal2(tdbb, csb, missingNode1->arg, missingNode2->arg, stream);
}
case ExprNode::TYPE_NOT_BOOL:
{
NotBoolNode* notNode1 = static_cast<NotBoolNode*>(exprNode1);
NotBoolNode* notNode2 = static_cast<NotBoolNode*>(exprNode2);
return OPT_expression_equal2(tdbb, csb, notNode1->arg, notNode2->arg, stream);
}
case ExprNode::TYPE_RSE_BOOL:
{
RseBoolNode* rseNode1 = static_cast<RseBoolNode*>(exprNode1);
RseBoolNode* rseNode2 = static_cast<RseBoolNode*>(exprNode2);
if (rseNode1->blrOp != rseNode2->blrOp)
return false;
return OPT_expression_equal2(tdbb, csb, rseNode1->rse, rseNode2->rse, stream);
}
}
break;
return exprNode1->expressionEqual(tdbb, csb, exprNode2, stream);
}
case nod_rec_version:
@ -495,34 +307,25 @@ bool OPT_expression_equal2(thread_db* tdbb, CompilerScratch* csb,
break;
case nod_field:
{
const USHORT fld_stream = (USHORT)(IPTR) node2->nod_arg[e_fld_stream];
if ((node1->nod_arg[e_fld_id] == node2->nod_arg[e_fld_id]) && fld_stream == stream)
{
return true;
}
}
break;
{
const USHORT fld_stream = (USHORT)(IPTR) node2->nod_arg[e_fld_stream];
return (node1->nod_arg[e_fld_id] == node2->nod_arg[e_fld_id]) && fld_stream == stream;
}
case nod_literal:
{
dsc desc1, desc2;
{
dsc desc1, desc2;
CMP_get_desc(tdbb, csb, node1, &desc1);
CMP_get_desc(tdbb, csb, node2, &desc2);
CMP_get_desc(tdbb, csb, node1, &desc1);
CMP_get_desc(tdbb, csb, node2, &desc2);
if (DSC_EQUIV(&desc1, &desc2, true) &&
!memcmp(desc1.dsc_address, desc2.dsc_address, desc1.dsc_length))
{
return true;
}
}
break;
return DSC_EQUIV(&desc1, &desc2, true) &&
!memcmp(desc1.dsc_address, desc2.dsc_address, desc1.dsc_length);
}
case nod_null:
return true;
case nod_value_if:
case nod_substr:
case nod_trim:
{
@ -540,76 +343,52 @@ bool OPT_expression_equal2(thread_db* tdbb, CompilerScratch* csb,
case nod_gen_id:
case nod_gen_id2:
if (node1->nod_arg[e_gen_id] == node2->nod_arg[e_gen_id])
{
return true;
}
break;
return node1->nod_arg[e_gen_id] == node2->nod_arg[e_gen_id];
case nod_upcase:
case nod_lowcase:
if (OPT_expression_equal2(tdbb, csb, node1->nod_arg[0], node2->nod_arg[0], stream))
{
return true;
}
break;
return OPT_expression_equal2(tdbb, csb, node1->nod_arg[0], node2->nod_arg[0], stream);
case nod_cast:
{
dsc desc1, desc2;
{
dsc desc1, desc2;
CMP_get_desc(tdbb, csb, node1, &desc1);
CMP_get_desc(tdbb, csb, node2, &desc2);
CMP_get_desc(tdbb, csb, node1, &desc1);
CMP_get_desc(tdbb, csb, node2, &desc2);
if (DSC_EQUIV(&desc1, &desc2, true) &&
OPT_expression_equal2(tdbb, csb, node1->nod_arg[e_cast_source],
node2->nod_arg[e_cast_source], stream))
{
return true;
}
}
break;
return DSC_EQUIV(&desc1, &desc2, true) &&
OPT_expression_equal2(tdbb, csb, node1->nod_arg[e_cast_source],
node2->nod_arg[e_cast_source], stream);
}
case nod_extract:
if (node1->nod_arg[e_extract_part] == node2->nod_arg[e_extract_part] &&
return node1->nod_arg[e_extract_part] == node2->nod_arg[e_extract_part] &&
OPT_expression_equal2(tdbb, csb, node1->nod_arg[e_extract_value],
node2->nod_arg[e_extract_value], stream))
{
return true;
}
break;
node2->nod_arg[e_extract_value], stream);
case nod_strlen:
if (node1->nod_arg[e_strlen_type] == node2->nod_arg[e_strlen_type] &&
return node1->nod_arg[e_strlen_type] == node2->nod_arg[e_strlen_type] &&
OPT_expression_equal2(tdbb, csb, node1->nod_arg[e_strlen_value],
node2->nod_arg[e_strlen_value], stream))
{
return true;
}
break;
node2->nod_arg[e_strlen_value], stream);
case nod_list:
{
jrd_nod* const* ptr1 = node1->nod_arg;
jrd_nod* const* ptr2 = node2->nod_arg;
if (node1->nod_count != node2->nod_count)
return false;
ULONG count = node1->nod_count;
while (count--)
{
jrd_nod* const* ptr1 = node1->nod_arg;
jrd_nod* const* ptr2 = node2->nod_arg;
if (node1->nod_count != node2->nod_count)
{
if (!OPT_expression_equal2(tdbb, csb, *ptr1++, *ptr2++, stream))
return false;
}
}
ULONG count = node1->nod_count;
while (count--)
{
if (!OPT_expression_equal2(tdbb, csb, *ptr1++, *ptr2++, stream))
{
return false;
}
}
return true;
}
return true;
}
// AB: New nodes has to be added
@ -654,32 +433,6 @@ double OPT_getRelationCardinality(thread_db* tdbb, jrd_rel* relation, const Form
}
jrd_nod* OPT_make_binary_node(nod_t type, jrd_nod* arg1, jrd_nod* arg2, bool flag)
{
/**************************************
*
* m a k e _ b i n a r y _ n o d e
*
**************************************
*
* Functional description
* Make a binary node.
*
**************************************/
thread_db* tdbb = JRD_get_thread_data();
DEV_BLKCHK(arg1, type_nod);
DEV_BLKCHK(arg2, type_nod);
jrd_nod* node = PAR_make_node(tdbb, 2);
node->nod_type = type;
node->nod_arg[0] = arg1;
node->nod_arg[1] = arg2;
if (flag) {
node->nod_flags |= nod_comparison;
}
return node;
}
string OPT_make_alias(thread_db* tdbb, const CompilerScratch* csb,
const CompilerScratch::csb_repeat* base_tail)
{
@ -1031,13 +784,7 @@ void OptimizerRetrieval::findDependentFromStreams(jrd_nod* node, SortedStreamLis
if (node->nod_type == nod_class_exprnode_jrd)
{
ExprNode* exprNode = reinterpret_cast<ExprNode*>(node->nod_arg[0]);
for (NestConst<NestConst<jrd_nod> >* i = exprNode->jrdChildNodes.begin();
i != exprNode->jrdChildNodes.end(); ++i)
{
if (**i)
findDependentFromStreams(**i, streamList);
}
exprNode->findDependentFromStreams(this, streamList);
}
else if (node->nod_type == nod_class_recsrcnode_jrd)
{
@ -1173,13 +920,15 @@ InversionCandidate* OptimizerRetrieval::generateInversion(IndexTableScan** rsb)
// Check for any DB_KEY comparisons
for (OptimizerBlk::opt_conjunct* tail = opt_begin; tail < opt_end; tail++)
{
if (tail->opt_conjunct_flags & opt_conjunct_matched) {
if (tail->opt_conjunct_flags & opt_conjunct_matched)
continue;
}
jrd_nod* const node = tail->opt_conjunct_node;
BoolExprNode* const node = tail->opt_conjunct_node;
if (!(tail->opt_conjunct_flags & opt_conjunct_used) && node)
{
invCandidate = matchDbKey(node);
if (invCandidate)
{
invCandidate->boolean = node;
@ -1194,8 +943,8 @@ InversionCandidate* OptimizerRetrieval::generateInversion(IndexTableScan** rsb)
if (tail->opt_conjunct_flags & opt_conjunct_matched)
continue;
jrd_nod* const node = tail->opt_conjunct_node;
BinaryBoolNode* booleanNode = ExprNode::as<BinaryBoolNode>(node);
BoolExprNode* const node = tail->opt_conjunct_node;
BinaryBoolNode* booleanNode = node->as<BinaryBoolNode>();
if (!(tail->opt_conjunct_flags & opt_conjunct_used) && node &&
(!booleanNode || booleanNode->blrOp != blr_or))
@ -1206,9 +955,8 @@ InversionCandidate* OptimizerRetrieval::generateInversion(IndexTableScan** rsb)
getInversionCandidates(&inversions, &indexScratches, 1);
if (sort && rsb) {
if (sort && rsb)
*rsb = generateNavigation();
}
// Second, handle "OR" comparisons
for (OptimizerBlk::opt_conjunct* tail = opt_begin; tail < opt_end; tail++)
@ -1216,13 +964,14 @@ InversionCandidate* OptimizerRetrieval::generateInversion(IndexTableScan** rsb)
if (tail->opt_conjunct_flags & opt_conjunct_matched)
continue;
jrd_nod* const node = tail->opt_conjunct_node;
BinaryBoolNode* booleanNode = ExprNode::as<BinaryBoolNode>(node);
BoolExprNode* const node = tail->opt_conjunct_node;
BinaryBoolNode* booleanNode = node->as<BinaryBoolNode>();
if (!(tail->opt_conjunct_flags & opt_conjunct_used) && node &&
(booleanNode && booleanNode->blrOp == blr_or))
{
invCandidate = matchOnIndexes(&indexScratches, node, 1);
if (invCandidate)
{
invCandidate->boolean = node;
@ -1241,9 +990,7 @@ InversionCandidate* OptimizerRetrieval::generateInversion(IndexTableScan** rsb)
// Clean up inversion list
InversionCandidate** inversion = inversions.begin();
for (size_t i = 0; i < inversions.getCount(); i++)
{
delete inversion[i];
}
}
if (!invCandidate)
@ -1270,13 +1017,13 @@ InversionCandidate* OptimizerRetrieval::generateInversion(IndexTableScan** rsb)
for (const OptimizerBlk::opt_conjunct* tail = optimizer->opt_conjuncts.begin();
tail < optimizer->opt_conjuncts.end(); tail++)
{
jrd_nod* const node = tail->opt_conjunct_node;
BoolExprNode* const node = tail->opt_conjunct_node;
if (!(tail->opt_conjunct_flags & opt_conjunct_used) &&
OPT_computable(csb, node, stream, false, true) &&
node->computable(csb, stream, false, true) &&
!invCandidate->matches.exist(node))
{
const ComparativeBoolNode* cmpNode = ExprNode::as<ComparativeBoolNode>(node);
const ComparativeBoolNode* cmpNode = node->as<ComparativeBoolNode>();
const double factor = (cmpNode && cmpNode->blrOp == blr_eql) ?
REDUCE_SELECTIVITY_FACTOR_EQUALITY : REDUCE_SELECTIVITY_FACTOR_INEQUALITY;
@ -1286,25 +1033,24 @@ InversionCandidate* OptimizerRetrieval::generateInversion(IndexTableScan** rsb)
// Add the streams where this stream is depending on.
for (size_t i = 0; i < invCandidate->matches.getCount(); i++)
{
findDependentFromStreams(invCandidate->matches[i], &invCandidate->dependentFromStreams);
}
invCandidate->matches[i]->findDependentFromStreams(this, &invCandidate->dependentFromStreams);
if (setConjunctionsMatched)
{
SortedArray<jrd_nod*> matches;
SortedArray<BoolExprNode*> matches;
// AB: Putting a unsorted array in a sorted array directly by join isn't
// very safe at the moment, but in our case Array holds a sorted list.
// However SortedArray class should be updated to handle join right!
matches.join(invCandidate->matches);
for (OptimizerBlk::opt_conjunct* tail = opt_begin; tail < opt_end; tail++)
{
if (!(tail->opt_conjunct_flags & opt_conjunct_used))
{
if (matches.exist(tail->opt_conjunct_node))
{
tail->opt_conjunct_flags |= opt_conjunct_matched;
}
}
}
}
@ -1510,8 +1256,9 @@ void OptimizerRetrieval::getInversionCandidates(InversionCandidateList* inversio
const double cardinality = csb->csb_rpt[stream].csb_cardinality;
// Walk through indexes to calculate selectivity / candidate
Array<jrd_nod*> matches;
Array<BoolExprNode*> matches;
size_t i = 0;
for (i = 0; i < fromIndexScratches->getCount(); i++)
{
IndexScratch& scratch = (*fromIndexScratches)[i];
@ -1520,17 +1267,21 @@ void OptimizerRetrieval::getInversionCandidates(InversionCandidateList* inversio
scratch.lowerCount = 0;
scratch.upperCount = 0;
scratch.nonFullMatchedSegments = MAX_INDEX_SEGMENTS + 1;
if (scratch.candidate)
{
matches.clear();
scratch.selectivity = MAXIMUM_SELECTIVITY;
bool unique = false;
for (int j = 0; j < scratch.idx->idx_count; j++)
{
IndexScratchSegment* segment = scratch.segments[j];
if (segment->scope == scope) {
if (segment->scope == scope)
scratch.scopeCandidate = true;
}
// Check if this is the last usable segment
if (((segment->scanType == segmentScanEqual) ||
(segment->scanType == segmentScanEquivalent) ||
@ -1578,6 +1329,7 @@ void OptimizerRetrieval::getInversionCandidates(InversionCandidateList* inversio
// estimate the selectivity
double selectivity = scratch.selectivity;
double factor = 1;
switch (segment->scanType)
{
case segmentScanBetween:
@ -1635,6 +1387,7 @@ void OptimizerRetrieval::getInversionCandidates(InversionCandidateList* inversio
// For a non-unique one, assume 1/10 of the maximum selectivity, so that
// at least some indexes could be chosen by the optimizer.
double selectivity = scratch.selectivity;
if (selectivity <= 0)
{
if (unique && cardinality)
@ -1659,11 +1412,13 @@ void OptimizerRetrieval::getInversionCandidates(InversionCandidateList* inversio
invCandidate->indexes = 1;
invCandidate->scratch = &scratch;
invCandidate->matches.join(matches);
for (size_t k = 0; k < invCandidate->matches.getCount(); k++)
{
findDependentFromStreams(invCandidate->matches[k],
&invCandidate->dependentFromStreams);
invCandidate->matches[k]->findDependentFromStreams(this,
&invCandidate->dependentFromStreams);
}
invCandidate->dependencies = (int) invCandidate->dependentFromStreams.getCount();
inversions->add(invCandidate);
}
@ -1688,9 +1443,7 @@ jrd_nod* OptimizerRetrieval::findDbKey(jrd_nod* dbkey, USHORT stream, SLONG* pos
if (dbkey->nod_type == nod_dbkey)
{
if ((USHORT)(IPTR) dbkey->nod_arg[0] == stream)
{
return dbkey;
}
*position = *position + 1;
return NULL;
@ -1701,16 +1454,14 @@ jrd_nod* OptimizerRetrieval::findDbKey(jrd_nod* dbkey, USHORT stream, SLONG* pos
if (concatNode)
{
jrd_nod* dbkey_temp = findDbKey(concatNode->arg1, stream, position);
if (dbkey_temp)
{
return dbkey_temp;
}
dbkey_temp = findDbKey(concatNode->arg2, stream, position);
if (dbkey_temp)
{
return dbkey_temp;
}
}
return NULL;
@ -1833,11 +1584,11 @@ InversionNode* OptimizerRetrieval::makeIndexScanNode(IndexScratch* indexScratch)
for (IndexScratchSegment** tail = indexScratch->segments.begin();
tail != indexScratch->segments.end() && ((*tail)->lowerValue || (*tail)->upperValue); ++tail)
{
ComparativeBoolNode* cmpNode = ExprNode::as<ComparativeBoolNode>((*tail)->matches[0]);
ComparativeBoolNode* cmpNode = (*tail)->matches[0]->as<ComparativeBoolNode>();
fb_assert(cmpNode);
dsc dsc0;
CMP_get_desc(tdbb, csb,
(cmpNode ? cmpNode->arg1.getObject() : (*tail)->matches[0]->nod_arg[0]), &dsc0);
CMP_get_desc(tdbb, csb, cmpNode->arg1.getObject(), &dsc0);
// ASF: "dsc0.dsc_ttype() > ttype_last_internal" is to avoid recursion
// when looking for charsets/collations
@ -1975,11 +1726,10 @@ InversionCandidate* OptimizerRetrieval::makeInversion(InversionCandidateList* in
}
// The matches returned in this inversion are always sorted.
SortedArray<jrd_nod*> matches;
SortedArray<BoolExprNode*> matches;
for (i = 0; i < inversions->getCount(); i++)
{
// Initialize vars before walking through candidates
InversionCandidate* bestCandidate = NULL;
bool restartLoop = false;
@ -2009,16 +1759,16 @@ InversionCandidate* OptimizerRetrieval::makeInversion(InversionCandidateList* in
invCandidate->matchedSegments = currentInv->matchedSegments;
invCandidate->dependencies = currentInv->dependencies;
matches.clear();
for (size_t j = 0; j < currentInv->matches.getCount(); j++)
{
if (!matches.exist(currentInv->matches[j])) {
if (!matches.exist(currentInv->matches[j]))
matches.add(currentInv->matches[j]);
}
}
invCandidate->matches.join(matches);
if (acceptAll) {
if (acceptAll)
continue;
}
return invCandidate;
}
@ -2287,7 +2037,8 @@ InversionCandidate* OptimizerRetrieval::makeInversion(InversionCandidateList* in
return invCandidate;
}
bool OptimizerRetrieval::matchBoolean(IndexScratch* indexScratch, jrd_nod* boolean, USHORT scope) const
bool OptimizerRetrieval::matchBoolean(IndexScratch* indexScratch, BoolExprNode* boolean,
USHORT scope) const
{
/**************************************
*
@ -2298,10 +2049,10 @@ bool OptimizerRetrieval::matchBoolean(IndexScratch* indexScratch, jrd_nod* boole
* Functional description
*
**************************************/
ComparativeBoolNode* cmpNode = ExprNode::as<ComparativeBoolNode>(boolean);
MissingBoolNode* missingNode = ExprNode::as<MissingBoolNode>(boolean);
NotBoolNode* notNode = ExprNode::as<NotBoolNode>(boolean);
RseBoolNode* rseNode = ExprNode::as<RseBoolNode>(boolean);
ComparativeBoolNode* cmpNode = boolean->as<ComparativeBoolNode>();
MissingBoolNode* missingNode = boolean->as<MissingBoolNode>();
NotBoolNode* notNode = boolean->as<NotBoolNode>();
RseBoolNode* rseNode = boolean->as<RseBoolNode>();
bool forward = true;
jrd_nod* value = NULL;
jrd_nod* match;
@ -2314,7 +2065,7 @@ bool OptimizerRetrieval::matchBoolean(IndexScratch* indexScratch, jrd_nod* boole
else if (missingNode)
match = missingNode->arg;
else if (notNode)
match = notNode->arg;
return false;
else if (rseNode)
match = rseNode->rse;
else
@ -2580,7 +2331,7 @@ bool OptimizerRetrieval::matchBoolean(IndexScratch* indexScratch, jrd_nod* boole
return count >= 1;
}
InversionCandidate* OptimizerRetrieval::matchDbKey(jrd_nod* boolean) const
InversionCandidate* OptimizerRetrieval::matchDbKey(BoolExprNode* boolean) const
{
/**************************************
*
@ -2594,7 +2345,7 @@ InversionCandidate* OptimizerRetrieval::matchDbKey(jrd_nod* boolean) const
**************************************/
// If this isn't an equality, it isn't even interesting
ComparativeBoolNode* cmpNode = ExprNode::as<ComparativeBoolNode>(boolean);
ComparativeBoolNode* cmpNode = boolean->as<ComparativeBoolNode>();
if (!cmpNode || cmpNode->blrOp != blr_eql)
return NULL;
@ -2654,7 +2405,7 @@ InversionCandidate* OptimizerRetrieval::matchDbKey(jrd_nod* boolean) const
}
InversionCandidate* OptimizerRetrieval::matchOnIndexes(
IndexScratchList* inputIndexScratches, jrd_nod* boolean, USHORT scope) const
IndexScratchList* inputIndexScratches, BoolExprNode* boolean, USHORT scope) const
{
/**************************************
*
@ -2668,12 +2419,10 @@ InversionCandidate* OptimizerRetrieval::matchOnIndexes(
* inversion candidate could be returned.
*
**************************************/
DEV_BLKCHK(boolean, type_nod);
BinaryBoolNode* booleanNode = ExprNode::as<BinaryBoolNode>(boolean);
BinaryBoolNode* binaryNode = boolean->as<BinaryBoolNode>();
// Handle the "OR" case up front
if (booleanNode && booleanNode->blrOp == blr_or)
if (binaryNode && binaryNode->blrOp == blr_or)
{
InversionCandidateList inversions;
inversions.shrink(0);
@ -2696,13 +2445,12 @@ InversionCandidate* OptimizerRetrieval::matchOnIndexes(
scope++;
InversionCandidate* invCandidate1 =
matchOnIndexes(&indexOrScratches, booleanNode->arg1, scope);
matchOnIndexes(&indexOrScratches, binaryNode->arg1, scope);
if (invCandidate1)
inversions.add(invCandidate1);
BinaryBoolNode* childBoolNode = ExprNode::as<BinaryBoolNode>(
booleanNode->arg1.getObject());
BinaryBoolNode* childBoolNode = binaryNode->arg1->as<BinaryBoolNode>();
// Get usable inversions based on indexOrScratches and scope
if (!childBoolNode || childBoolNode->blrOp != blr_or)
@ -2729,12 +2477,12 @@ InversionCandidate* OptimizerRetrieval::matchOnIndexes(
inversions.clear();
InversionCandidate* invCandidate2 = matchOnIndexes(
&indexOrScratches, booleanNode->arg2, scope);
&indexOrScratches, binaryNode->arg2, scope);
if (invCandidate2)
inversions.add(invCandidate2);
childBoolNode = ExprNode::as<BinaryBoolNode>(booleanNode->arg2.getObject());
childBoolNode = binaryNode->arg2->as<BinaryBoolNode>();
// Make inversion based on indexOrScratches and scope
if (!childBoolNode || childBoolNode->blrOp != blr_or)
@ -2759,7 +2507,7 @@ InversionCandidate* OptimizerRetrieval::matchOnIndexes(
// Add matches conjunctions that exists in both left and right inversion
if ((invCandidate1->matches.getCount()) && (invCandidate2->matches.getCount()))
{
SortedArray<jrd_nod*> matches;
SortedArray<BoolExprNode*> matches;
for (size_t j = 0; j < invCandidate1->matches.getCount(); j++)
matches.add(invCandidate1->matches[j]);
@ -2777,7 +2525,7 @@ InversionCandidate* OptimizerRetrieval::matchOnIndexes(
return NULL;
}
if (booleanNode && booleanNode->blrOp == blr_and)
if (binaryNode && binaryNode->blrOp == blr_and)
{
// Recursivly call this procedure for every boolean
// and finally get candidate inversions.
@ -2786,12 +2534,12 @@ InversionCandidate* OptimizerRetrieval::matchOnIndexes(
inversions.shrink(0);
InversionCandidate* invCandidate = matchOnIndexes(
inputIndexScratches, booleanNode->arg1, scope);
inputIndexScratches, binaryNode->arg1, scope);
if (invCandidate)
inversions.add(invCandidate);
invCandidate = matchOnIndexes(inputIndexScratches, booleanNode->arg2, scope);
invCandidate = matchOnIndexes(inputIndexScratches, binaryNode->arg2, scope);
if (invCandidate)
inversions.add(invCandidate);

View File

@ -81,7 +81,6 @@ bool OPT_expression_equal(thread_db*, CompilerScratch*, const index_desc*, jrd_n
bool OPT_expression_equal2(thread_db*, CompilerScratch*, jrd_nod*, jrd_nod*, USHORT);
double OPT_getRelationCardinality(thread_db*, jrd_rel*, const Format*);
Firebird::string OPT_make_alias(thread_db*, const CompilerScratch*, const CompilerScratch::csb_repeat*);
jrd_nod* OPT_make_binary_node(nod_t, jrd_nod*, jrd_nod*, bool);
enum segmentScanType {
segmentScanNone,
@ -108,7 +107,7 @@ public:
int scope; // highest scope level
segmentScanType scanType; // scan type
Firebird::Array<jrd_nod*> matches;
Firebird::Array<BoolExprNode*> matches;
};
class IndexScratch
@ -142,13 +141,13 @@ public:
USHORT matchedSegments;
int indexes;
int dependencies;
jrd_nod* boolean;
BoolExprNode* boolean;
InversionNode* inversion;
IndexScratch* scratch;
bool used;
bool unique;
Firebird::Array<jrd_nod*> matches;
Firebird::Array<BoolExprNode*> matches;
SortedStreamList dependentFromStreams;
};
@ -178,10 +177,10 @@ protected:
InversionNode* makeIndexNode(const index_desc* idx) const;
InversionNode* makeIndexScanNode(IndexScratch* indexScratch) const;
InversionCandidate* makeInversion(InversionCandidateList* inversions) const;
bool matchBoolean(IndexScratch* indexScratch, jrd_nod* boolean, USHORT scope) const;
InversionCandidate* matchDbKey(jrd_nod* boolean) const;
bool matchBoolean(IndexScratch* indexScratch, BoolExprNode* boolean, USHORT scope) const;
InversionCandidate* matchDbKey(BoolExprNode* boolean) const;
InversionCandidate* matchOnIndexes(IndexScratchList* indexScratches,
jrd_nod* boolean, USHORT scope) const;
BoolExprNode* boolean, USHORT scope) const;
jrd_nod* findDbKey(jrd_nod*, USHORT, SLONG*) const;
#ifdef OPT_DEBUG_RETRIEVAL

View File

@ -42,10 +42,10 @@ using namespace Jrd;
static MapNode* parseMap(thread_db* tdbb, CompilerScratch* csb, USHORT stream);
static SSHORT strcmpSpace(const char* p, const char* q);
static void processSource(thread_db* tdbb, CompilerScratch* csb, RseNode* rse,
RecordSourceNode* source, jrd_nod** boolean, RecordSourceNodeStack& stack);
RecordSourceNode* source, BoolExprNode** boolean, RecordSourceNodeStack& stack);
static void processMap(thread_db* tdbb, CompilerScratch* csb, MapNode* map, Format** inputFormat);
static void genDeliverUnmapped(thread_db* tdbb, NodeStack* deliverStack, MapNode* map,
NodeStack* parentStack, UCHAR shellStream);
static void genDeliverUnmapped(thread_db* tdbb, BoolExprNodeStack* deliverStack, MapNode* map,
BoolExprNodeStack* parentStack, UCHAR shellStream);
static void markIndices(CompilerScratch::csb_repeat* csbTail, SSHORT relationId);
static void sortIndicesBySelectivity(CompilerScratch::csb_repeat* csbTail);
@ -303,7 +303,7 @@ void RelationSourceNode::ignoreDbKey(thread_db* tdbb, CompilerScratch* csb, cons
}
void RelationSourceNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, RseNode* rse,
jrd_nod** boolean, RecordSourceNodeStack& stack)
BoolExprNode** boolean, RecordSourceNodeStack& stack)
{
stack.push(this); // Assume that the source will be used. Push it on the final stream stack.
@ -415,8 +415,10 @@ void RelationSourceNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, RseN
if (viewRse->rse_boolean)
{
jrd_nod* node = CMP_pass1(tdbb, csb, NodeCopier::copy(tdbb,
csb, viewRse->rse_boolean, map));
NodeCopier copier(csb, map);
BoolExprNode* node = viewRse->rse_boolean->copy(tdbb, copier);
node = node->pass1(tdbb, csb);
if (*boolean)
{
@ -428,12 +430,7 @@ void RelationSourceNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, RseN
andNode->arg1 = node;
andNode->arg2 = *boolean;
jrd_nod* additional = PAR_make_node(tdbb, 1);
additional->nod_type = nod_class_exprnode_jrd;
additional->nod_count = 0;
additional->nod_arg[0] = reinterpret_cast<jrd_nod*>(andNode);
*boolean = additional;
*boolean = andNode;
}
else
*boolean = node;
@ -628,7 +625,7 @@ void ProcedureSourceNode::pass1(thread_db* tdbb, CompilerScratch* csb, jrd_rel*
}
void ProcedureSourceNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, RseNode* rse,
jrd_nod** boolean, RecordSourceNodeStack& stack)
BoolExprNode** boolean, RecordSourceNodeStack& stack)
{
stack.push(this); // Assume that the source will be used. Push it on the final stream stack.
@ -801,7 +798,7 @@ void AggregateSourceNode::pass1(thread_db* tdbb, CompilerScratch* csb, jrd_rel*
}
void AggregateSourceNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, RseNode* rse,
jrd_nod** boolean, RecordSourceNodeStack& stack)
BoolExprNode** boolean, RecordSourceNodeStack& stack)
{
stack.push(this); // Assume that the source will be used. Push it on the final stream stack.
@ -853,7 +850,7 @@ RecordSource* AggregateSourceNode::compile(thread_db* tdbb, OptimizerBlk* opt, b
opt->beds[++opt->beds[0]] = (UCHAR) stream;
NodeStack::const_iterator stackEnd;
BoolExprNodeStack::const_iterator stackEnd;
if (opt->parentStack)
stackEnd = opt->conjunctStack.merge(*opt->parentStack);
@ -871,7 +868,7 @@ RecordSource* AggregateSourceNode::compile(thread_db* tdbb, OptimizerBlk* opt, b
// Generate an RecordSource (Record Source Block) for each aggregate operation.
// Generate an AggregateSort (Aggregate SortedStream Block) for each DISTINCT aggregate.
RecordSource* AggregateSourceNode::generate(thread_db* tdbb, OptimizerBlk* opt,
NodeStack* parentStack, UCHAR shellStream)
BoolExprNodeStack* parentStack, UCHAR shellStream)
{
SET_TDBB(tdbb);
@ -882,7 +879,7 @@ RecordSource* AggregateSourceNode::generate(thread_db* tdbb, OptimizerBlk* opt,
// Zip thru stack of booleans looking for fields that belong to shellStream.
// Those fields are mappings. Mappings that hold a plain field may be used
// to distribute. Handle the simple cases only.
NodeStack deliverStack;
BoolExprNodeStack deliverStack;
genDeliverUnmapped(tdbb, &deliverStack, map, parentStack, shellStream);
// try to optimize MAX and MIN to use an index; for now, optimize
@ -1037,7 +1034,7 @@ void UnionSourceNode::ignoreDbKey(thread_db* tdbb, CompilerScratch* csb, const j
}
void UnionSourceNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, RseNode* rse,
jrd_nod** boolean, RecordSourceNodeStack& stack)
BoolExprNode** boolean, RecordSourceNodeStack& stack)
{
stack.push(this); // Assume that the source will be used. Push it on the final stream stack.
@ -1110,7 +1107,7 @@ RecordSource* UnionSourceNode::compile(thread_db* tdbb, OptimizerBlk* opt, bool
const SSHORT i = (SSHORT) opt->keyStreams[0];
computeDbKeyStreams(opt->keyStreams);
NodeStack::const_iterator stackEnd;
BoolExprNodeStack::const_iterator stackEnd;
if (opt->parentStack)
stackEnd = opt->conjunctStack.merge(*opt->parentStack);
@ -1128,7 +1125,7 @@ RecordSource* UnionSourceNode::compile(thread_db* tdbb, OptimizerBlk* opt, bool
// Generate a union complex.
RecordSource* UnionSourceNode::generate(thread_db* tdbb, OptimizerBlk* opt, UCHAR* streams,
USHORT nstreams, NodeStack* parentStack, UCHAR shellStream)
USHORT nstreams, BoolExprNodeStack* parentStack, UCHAR shellStream)
{
SET_TDBB(tdbb);
@ -1148,7 +1145,7 @@ RecordSource* UnionSourceNode::generate(thread_db* tdbb, OptimizerBlk* opt, UCHA
// AB: Try to distribute booleans from the top rse for an UNION to
// the WHERE clause of every single rse.
// hvlad: don't do it for recursive unions else they will work wrong !
NodeStack deliverStack;
BoolExprNodeStack deliverStack;
if (!recursive)
genDeliverUnmapped(tdbb, &deliverStack, map, parentStack, shellStream);
@ -1320,7 +1317,7 @@ void WindowSourceNode::pass1(thread_db* tdbb, CompilerScratch* csb, jrd_rel* vie
}
void WindowSourceNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, RseNode* rse,
jrd_nod** boolean, RecordSourceNodeStack& stack)
BoolExprNode** boolean, RecordSourceNodeStack& stack)
{
stack.push(this); // Assume that the source will be used. Push it on the final stream stack.
@ -1399,7 +1396,7 @@ RecordSource* WindowSourceNode::compile(thread_db* tdbb, OptimizerBlk* opt, bool
opt->beds[++opt->beds[0]] = (UCHAR) partition->stream;
}
NodeStack deliverStack;
BoolExprNodeStack deliverStack;
RecordSource* rsb = FB_NEW(*tdbb->getDefaultPool()) WindowedStream(opt->opt_csb, partitions,
OPT_compile(tdbb, opt->opt_csb, rse, &deliverStack));
@ -1455,9 +1452,13 @@ RseNode* RseNode::copy(thread_db* tdbb, NodeCopier& copier)
newSource->rse_jointype = rse_jointype;
newSource->rse_first = copier.copy(tdbb, rse_first);
newSource->rse_skip = copier.copy(tdbb, rse_skip);
newSource->rse_boolean = copier.copy(tdbb, rse_boolean);
if (rse_boolean)
newSource->rse_boolean = rse_boolean->copy(tdbb, copier);
if (rse_sorted)
newSource->rse_sorted = rse_sorted->copy(tdbb, copier);
if (rse_projection)
newSource->rse_projection = rse_projection->copy(tdbb, copier);
@ -1502,7 +1503,7 @@ void RseNode::pass1(thread_db* tdbb, CompilerScratch* csb, jrd_rel* view)
csb->csb_current_nodes.push(this);
RecordSourceNodeStack stack;
jrd_nod* boolean = NULL;
BoolExprNode* boolean = NULL;
SortNode* sort = rse_sorted;
SortNode* project = rse_projection;
jrd_nod* first = rse_first;
@ -1538,20 +1539,15 @@ void RseNode::pass1(thread_db* tdbb, CompilerScratch* csb, jrd_rel* view)
{
BinaryBoolNode* andNode = FB_NEW(csb->csb_pool) BinaryBoolNode(csb->csb_pool, blr_and);
andNode->arg1 = boolean;
andNode->arg2 = CMP_pass1(tdbb, csb, rse_boolean);
andNode->arg2 = rse_boolean->pass1(tdbb, csb);
jrd_nod* additional = PAR_make_node(tdbb, 1);
additional->nod_type = nod_class_exprnode_jrd;
additional->nod_count = 0;
additional->nod_arg[0] = reinterpret_cast<jrd_nod*>(andNode);
rse_boolean = additional;
rse_boolean = andNode;
}
else
rse_boolean = boolean;
}
else
rse_boolean = CMP_pass1(tdbb, csb, rse_boolean);
else if (rse_boolean)
rse_boolean = rse_boolean->pass1(tdbb, csb);
if (sort)
{
@ -1573,7 +1569,7 @@ void RseNode::pass1(thread_db* tdbb, CompilerScratch* csb, jrd_rel* view)
}
void RseNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, RseNode* rse,
jrd_nod** boolean, RecordSourceNodeStack& stack)
BoolExprNode** boolean, RecordSourceNodeStack& stack)
{
// in the case of a RseNode, it is possible that a new RseNode will be generated,
// so wait to process the source before we push it on the stack (bug 8039)
@ -1594,7 +1590,7 @@ void RseNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, RseNode* rse,
if (rse_boolean)
{
jrd_nod* node = CMP_pass1(tdbb, csb, rse_boolean);
BoolExprNode* node = rse_boolean->pass1(tdbb, csb);
if (*boolean)
{
@ -1603,12 +1599,7 @@ void RseNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, RseNode* rse,
andNode->arg1 = node;
andNode->arg2 = *boolean;
jrd_nod* additional = PAR_make_node(tdbb, 1);
additional->nod_type = nod_class_exprnode_jrd;
additional->nod_count = 0;
additional->nod_arg[0] = reinterpret_cast<jrd_nod*>(andNode);
*boolean = additional;
*boolean = andNode;
}
else
*boolean = node;
@ -1642,7 +1633,7 @@ void RseNode::pass2Rse(thread_db* tdbb, CompilerScratch* csb)
(*ptr)->pass2Rse(tdbb, csb);
if (rse_boolean)
CMP_pass2(tdbb, csb, rse_boolean, NULL);
rse_boolean->pass2(tdbb, csb);
if (rse_sorted)
rse_sorted->pass2(tdbb, csb);
@ -1706,9 +1697,9 @@ RecordSource* RseNode::compile(thread_db* tdbb, OptimizerBlk* opt, bool innerSub
opt->opt_csb->csb_rpt[*i].csb_flags |= csb_active;
}
//const NodeStack::iterator stackSavepoint(opt->conjunctStack);
NodeStack::const_iterator stackEnd;
NodeStack deliverStack;
//const BoolExprNodeStack::iterator stackSavepoint(opt->conjunctStack);
BoolExprNodeStack::const_iterator stackEnd;
BoolExprNodeStack deliverStack;
if (opt->rse->rse_jointype != blr_inner)
{
@ -1716,15 +1707,16 @@ RecordSource* RseNode::compile(thread_db* tdbb, OptimizerBlk* opt, bool innerSub
// In fact these are all nodes except when a IS NULL comparision is done.
// Note! Don't forget that this can be burried inside a expression
// such as "CASE WHEN (FieldX IS NULL) THEN 0 ELSE 1 END = 0"
NodeStack::iterator stackItem;
BoolExprNodeStack::iterator stackItem;
if (opt->parentStack)
stackItem = *opt->parentStack;
for (; stackItem.hasData(); ++stackItem)
{
jrd_nod* deliverNode = stackItem.object();
BoolExprNode* deliverNode = stackItem.object();
PossibleUnknownFinder finder;
if (!PossibleUnknownFinder::find(deliverNode))
if (!deliverNode->jrdPossibleUnknownFinder(finder))
deliverStack.push(deliverNode);
}
@ -2039,7 +2031,7 @@ bool RseNode::computable(CompilerScratch* csb, SSHORT stream, bool idx_use,
bool result = true;
// Check sub-stream
if ((rse_boolean && !OPT_computable(csb, rse_boolean, stream, idx_use, allowOnlyCurrentStream)) ||
if ((rse_boolean && !rse_boolean->computable(csb, stream, idx_use, allowOnlyCurrentStream)) ||
(rse_sorted && !rse_sorted->computable(csb, stream, idx_use, allowOnlyCurrentStream)) ||
(rse_projection && !rse_projection->computable(csb, stream, idx_use, allowOnlyCurrentStream)))
{
@ -2082,7 +2074,7 @@ void RseNode::findDependentFromStreams(const OptimizerRetrieval* optRet,
optRet->findDependentFromStreams(rse_skip, streamList);
if (rse_boolean)
optRet->findDependentFromStreams(rse_boolean, streamList);
rse_boolean->findDependentFromStreams(optRet, streamList);
if (rse_sorted)
rse_sorted->findDependentFromStreams(optRet, streamList);
@ -2143,7 +2135,7 @@ static SSHORT strcmpSpace(const char* p, const char* q)
// Process a single record source stream from a RseNode.
// Obviously, if the source is a view, there is more work to do.
static void processSource(thread_db* tdbb, CompilerScratch* csb, RseNode* rse,
RecordSourceNode* source, jrd_nod** boolean, RecordSourceNodeStack& stack)
RecordSourceNode* source, BoolExprNode** boolean, RecordSourceNodeStack& stack)
{
SET_TDBB(tdbb);
@ -2267,19 +2259,19 @@ static void processMap(thread_db* tdbb, CompilerScratch* csb, MapNode* map, Form
// Make new boolean nodes from nodes that contain a field from the given shellStream.
// Those fields are references (mappings) to other nodes and are used by aggregates and union rse's.
static void genDeliverUnmapped(thread_db* tdbb, NodeStack* deliverStack, MapNode* map,
NodeStack* parentStack, UCHAR shellStream)
static void genDeliverUnmapped(thread_db* tdbb, BoolExprNodeStack* deliverStack, MapNode* map,
BoolExprNodeStack* parentStack, UCHAR shellStream)
{
SET_TDBB(tdbb);
for (NodeStack::iterator stack1(*parentStack); stack1.hasData(); ++stack1)
for (BoolExprNodeStack::iterator stack1(*parentStack); stack1.hasData(); ++stack1)
{
jrd_nod* boolean = stack1.object();
BoolExprNode* boolean = stack1.object();
// Reduce to simple comparisons
ComparativeBoolNode* cmpNode = ExprNode::as<ComparativeBoolNode>(boolean);
MissingBoolNode* missingNode = ExprNode::as<MissingBoolNode>(boolean);
ComparativeBoolNode* cmpNode = boolean->as<ComparativeBoolNode>();
MissingBoolNode* missingNode = boolean->as<MissingBoolNode>();
HalfStaticArray<jrd_nod*, 2> children;
if (cmpNode &&
@ -2313,60 +2305,47 @@ static void genDeliverUnmapped(thread_db* tdbb, NodeStack* deliverStack, MapNode
continue;
// Create new node and assign the correct existing arguments
jrd_nod* deliverNode = PAR_make_node(tdbb, 1);
deliverNode->nod_count = 0;
deliverNode->nod_type = boolean->nod_type;
deliverNode->nod_flags = boolean->nod_flags;
deliverNode->nod_impure = boolean->nod_impure;
BoolExprNode* newNode = NULL;
BoolExprNode* deliverNode = NULL;
HalfStaticArray<jrd_nod**, 2> newChildren;
if (cmpNode)
{
ComparativeBoolNode* newCmpNode = FB_NEW(*tdbb->getDefaultPool()) ComparativeBoolNode(
*tdbb->getDefaultPool(), cmpNode->blrOp);
newCmpNode->setNode(deliverNode);
newChildren.add(newCmpNode->arg1.getAddress());
newChildren.add(newCmpNode->arg2.getAddress());
newNode = newCmpNode;
deliverNode = newCmpNode;
}
else if (missingNode)
{
MissingBoolNode* newMissingNode = FB_NEW(*tdbb->getDefaultPool()) MissingBoolNode(
*tdbb->getDefaultPool());
newMissingNode->setNode(deliverNode);
newChildren.add(newMissingNode->arg.getAddress());
newNode = newMissingNode;
}
else
{
fb_assert(false);
deliverNode = newMissingNode;
}
deliverNode->nod_arg[0] = reinterpret_cast<jrd_nod*>(newNode);
deliverNode->flags = boolean->flags;
deliverNode->impureOffset = boolean->impureOffset;
bool wrongNode = false;
for (indexArg = 0; (indexArg < children.getCount()) && !wrongNode; ++indexArg)
{
jrd_nod* node = UnmappedNodeGetter::get(map, shellStream, children[indexArg]);
JrdNode node = UnmappedNodeGetter::get(map, shellStream, children[indexArg]);
wrongNode = (node == NULL);
wrongNode = (!node.jrdNode || !*node.jrdNode);
if (!wrongNode)
*newChildren[indexArg] = node;
*newChildren[indexArg] = *node.jrdNode;
}
if (wrongNode)
{
delete newNode;
delete deliverNode;
}
else
deliverStack->push(deliverNode);
}

View File

@ -35,6 +35,7 @@ namespace Jrd {
class IndexRetrieval;
class OptimizerRetrieval;
class ProcedureScan;
class BoolExprNode;
class RelationSourceNode;
class RseNode;
@ -233,7 +234,7 @@ public:
virtual void ignoreDbKey(thread_db* tdbb, CompilerScratch* csb, const jrd_rel* view) const = 0;
virtual void pass1(thread_db* tdbb, CompilerScratch* csb, jrd_rel* view) = 0;
virtual void pass1Source(thread_db* tdbb, CompilerScratch* csb, RseNode* rse,
jrd_nod** boolean, RecordSourceNodeStack& stack) = 0;
BoolExprNode** boolean, RecordSourceNodeStack& stack) = 0;
virtual void pass2(thread_db* tdbb, CompilerScratch* csb) = 0;
virtual void pass2Rse(thread_db* tdbb, CompilerScratch* csb) = 0;
virtual bool containsStream(USHORT checkStream) const = 0;
@ -277,7 +278,7 @@ public:
}
virtual void pass1Source(thread_db* tdbb, CompilerScratch* csb, RseNode* rse,
jrd_nod** boolean, RecordSourceNodeStack& stack);
BoolExprNode** boolean, RecordSourceNodeStack& stack);
virtual void pass2(thread_db* tdbb, CompilerScratch* csb)
{
@ -341,7 +342,7 @@ public:
virtual void pass1(thread_db* tdbb, CompilerScratch* csb, jrd_rel* view);
virtual void pass1Source(thread_db* tdbb, CompilerScratch* csb, RseNode* rse,
jrd_nod** boolean, RecordSourceNodeStack& stack);
BoolExprNode** boolean, RecordSourceNodeStack& stack);
virtual void pass2(thread_db* tdbb, CompilerScratch* csb);
virtual void pass2Rse(thread_db* tdbb, CompilerScratch* csb);
@ -390,7 +391,7 @@ public:
virtual void ignoreDbKey(thread_db* tdbb, CompilerScratch* csb, const jrd_rel* view) const;
virtual void pass1(thread_db* tdbb, CompilerScratch* csb, jrd_rel* view);
virtual void pass1Source(thread_db* tdbb, CompilerScratch* csb, RseNode* rse,
jrd_nod** boolean, RecordSourceNodeStack& stack);
BoolExprNode** boolean, RecordSourceNodeStack& stack);
virtual void pass2(thread_db* tdbb, CompilerScratch* csb);
virtual void pass2Rse(thread_db* tdbb, CompilerScratch* csb);
virtual bool containsStream(USHORT checkStream) const;
@ -406,7 +407,7 @@ public:
virtual RecordSource* compile(thread_db* tdbb, OptimizerBlk* opt, bool innerSubStream);
private:
RecordSource* generate(thread_db* tdbb, OptimizerBlk* opt, NodeStack* parentStack,
RecordSource* generate(thread_db* tdbb, OptimizerBlk* opt, BoolExprNodeStack* parentStack,
UCHAR shellStream);
public:
@ -439,7 +440,7 @@ public:
}
virtual void pass1Source(thread_db* tdbb, CompilerScratch* csb, RseNode* rse,
jrd_nod** boolean, RecordSourceNodeStack& stack);
BoolExprNode** boolean, RecordSourceNodeStack& stack);
virtual void pass2(thread_db* tdbb, CompilerScratch* csb);
virtual void pass2Rse(thread_db* tdbb, CompilerScratch* csb);
virtual bool containsStream(USHORT checkStream) const;
@ -452,7 +453,7 @@ public:
private:
RecordSource* generate(thread_db* tdbb, OptimizerBlk* opt, UCHAR* streams, USHORT nstreams,
NodeStack* parentStack, UCHAR shellStream);
BoolExprNodeStack* parentStack, UCHAR shellStream);
private:
Firebird::Array<NestConst<RseNode> > clauses; // RseNode's for union
@ -502,7 +503,7 @@ public:
virtual void ignoreDbKey(thread_db* tdbb, CompilerScratch* csb, const jrd_rel* view) const;
virtual void pass1(thread_db* tdbb, CompilerScratch* csb, jrd_rel* view);
virtual void pass1Source(thread_db* tdbb, CompilerScratch* csb, RseNode* rse,
jrd_nod** boolean, RecordSourceNodeStack& stack);
BoolExprNode** boolean, RecordSourceNodeStack& stack);
virtual void pass2(thread_db* tdbb, CompilerScratch* csb);
virtual void pass2Rse(thread_db* tdbb, CompilerScratch* csb);
virtual bool containsStream(USHORT checkStream) const;
@ -572,7 +573,7 @@ public:
virtual void ignoreDbKey(thread_db* tdbb, CompilerScratch* csb, const jrd_rel* view) const;
virtual void pass1(thread_db* tdbb, CompilerScratch* csb, jrd_rel* view);
virtual void pass1Source(thread_db* tdbb, CompilerScratch* csb, RseNode* rse,
jrd_nod** boolean, RecordSourceNodeStack& stack);
BoolExprNode** boolean, RecordSourceNodeStack& stack);
virtual void pass2(thread_db* tdbb, CompilerScratch* csb)
{
@ -596,7 +597,7 @@ public:
USHORT rse_jointype; // inner, left, full
NestConst<jrd_nod> rse_first;
NestConst<jrd_nod> rse_skip;
NestConst<jrd_nod> rse_boolean;
NestConst<BoolExprNode> rse_boolean;
NestConst<SortNode> rse_sorted;
NestConst<SortNode> rse_projection;
NestConst<SortNode> rse_aggregate; // singleton aggregate for optimizing to index

View File

@ -29,6 +29,7 @@
namespace Jrd
{
class BoolExprNode;
class RseNode;
// view context block to cache view aliases
@ -330,8 +331,10 @@ inline RelationPages* jrd_rel::getPages(thread_db* tdbb, SLONG tran, bool allocP
class jrd_fld : public pool_alloc<type_fld>
{
public:
jrd_nod* fld_validation; // validation clause, if any
jrd_nod* fld_not_null; // if field cannot be NULL
BoolExprNode* fld_validation; // validation clause, if any
jrd_nod* fld_validation_stmt; // validation clause, if any - nod_stmt_expr fragment
BoolExprNode* fld_not_null; // if field cannot be NULL
jrd_nod* fld_not_null_stmt; // if field cannot be NULL - nod_stmt_expr fragment
jrd_nod* fld_missing_value; // missing value, if any
jrd_nod* fld_computation; // computation for virtual field
jrd_nod* fld_source; // source for view fields

View File

@ -199,27 +199,18 @@ jrd_nod* CMP_clone_node(thread_db* tdbb, CompilerScratch* csb, jrd_nod* node)
}
// Clone a value node for the optimizer.
// Make a copy of the node (if necessary) and assign impure space.
jrd_nod* CMP_clone_node_opt(thread_db* tdbb, CompilerScratch* csb, jrd_nod* node)
{
/**************************************
*
* C M P _ c l o n e _ n o d e _ o p t
*
**************************************
*
* Functional description
* Clone a value node for the optimizer. Make a copy of the node
* (if necessary) and assign impure space.
*
**************************************/
SET_TDBB(tdbb);
DEV_BLKCHK(csb, type_csb);
DEV_BLKCHK(node, type_nod);
if (node->nod_type == nod_argument) {
if (node->nod_type == nod_argument)
return node;
}
jrd_nod* clone = NodeCopier::copy(tdbb, csb, node, NULL);
CMP_pass2(tdbb, csb, clone, 0);
@ -227,6 +218,20 @@ jrd_nod* CMP_clone_node_opt(thread_db* tdbb, CompilerScratch* csb, jrd_nod* node
return clone;
}
BoolExprNode* CMP_clone_node_opt(thread_db* tdbb, CompilerScratch* csb, BoolExprNode* node)
{
SET_TDBB(tdbb);
DEV_BLKCHK(csb, type_csb);
NodeCopier copier(csb, NULL);
BoolExprNode* clone = node->copy(tdbb, copier);
clone->pass2(tdbb, csb);
return clone;
}
jrd_req* CMP_compile2(thread_db* tdbb, const UCHAR* blr, ULONG blr_length, bool internal_flag,
USHORT dbginfo_length, const UCHAR* dbginfo)
@ -787,13 +792,6 @@ void CMP_get_desc(thread_db* tdbb, CompilerScratch* csb, jrd_nod* node, DSC* des
return;
}
case nod_value_if:
CMP_get_desc(tdbb, csb,
node->nod_arg[1]->nod_type != nod_null ?
node->nod_arg[1] : node->nod_arg[2],
desc);
return;
case nod_domain_validation:
*desc = *(DSC*) (node->nod_arg + e_domval_desc);
return;
@ -1752,16 +1750,38 @@ static jrd_nod* make_validation(thread_db* tdbb, CompilerScratch* csb, USHORT st
vec<jrd_fld*>::iterator ptr1 = vector->begin();
for (const vec<jrd_fld*>::const_iterator end = vector->end(); ptr1 < end; ++ptr1, ++field_id)
{
jrd_nod* validation;
BoolExprNode* validation;
jrd_nod* validationStmt;
if (*ptr1 && (validation = (*ptr1)->fld_validation))
{
AutoSetRestore<USHORT> autoRemapVariable(&csb->csb_remap_variable,
(csb->csb_variables ? csb->csb_variables->count() : 0) + 1);
RemapFieldNodeCopier copier(csb, map, field_id);
if ((validationStmt = (*ptr1)->fld_validation_stmt))
validationStmt = copier.copy(tdbb, validationStmt);
validation = validation->copy(tdbb, copier);
jrd_nod* boolNod = PAR_make_node(tdbb, 1);
boolNod->nod_type = nod_class_exprnode_jrd;
boolNod->nod_count = 0;
boolNod->nod_arg[0] = reinterpret_cast<jrd_nod*>(validation);
if (validationStmt)
{
jrd_nod* exprStmtNod = PAR_make_node(tdbb, e_stmt_expr_length);
exprStmtNod->nod_type = nod_stmt_expr;
exprStmtNod->nod_arg[e_stmt_expr_stmt] = validationStmt;
exprStmtNod->nod_arg[e_stmt_expr_expr] = boolNod;
boolNod = exprStmtNod;
}
jrd_nod* node = PAR_make_node(tdbb, e_val_length);
node->nod_type = nod_validate;
node->nod_arg[e_val_boolean] =
RemapFieldNodeCopier(csb, map, field_id).copy(tdbb, validation);
node->nod_arg[e_val_boolean] = boolNod;
node->nod_arg[e_val_value] = PAR_gen_field(tdbb, stream, field_id);
stack.push(node);
}
@ -1771,10 +1791,30 @@ static jrd_nod* make_validation(thread_db* tdbb, CompilerScratch* csb, USHORT st
AutoSetRestore<USHORT> autoRemapVariable(&csb->csb_remap_variable,
(csb->csb_variables ? csb->csb_variables->count() : 0) + 1);
RemapFieldNodeCopier copier(csb, map, field_id);
if ((validationStmt = (*ptr1)->fld_not_null_stmt))
validationStmt = copier.copy(tdbb, validationStmt);
validation = validation->copy(tdbb, copier);
jrd_nod* boolNod = PAR_make_node(tdbb, 1);
boolNod->nod_type = nod_class_exprnode_jrd;
boolNod->nod_count = 0;
boolNod->nod_arg[0] = reinterpret_cast<jrd_nod*>(validation);
if (validationStmt)
{
jrd_nod* exprStmtNod = PAR_make_node(tdbb, e_stmt_expr_length);
exprStmtNod->nod_type = nod_stmt_expr;
exprStmtNod->nod_arg[e_stmt_expr_stmt] = validationStmt;
exprStmtNod->nod_arg[e_stmt_expr_expr] = boolNod;
boolNod = exprStmtNod;
}
jrd_nod* node = PAR_make_node(tdbb, e_val_length);
node->nod_type = nod_validate;
node->nod_arg[e_val_boolean] =
RemapFieldNodeCopier(csb, map, field_id).copy(tdbb, validation);
node->nod_arg[e_val_boolean] = boolNod;
node->nod_arg[e_val_value] = PAR_gen_field(tdbb, stream, field_id);
stack.push(node);
}
@ -1805,6 +1845,8 @@ static void mark_variant(CompilerScratch* csb, USHORT stream)
break;
node->rseNode->flags |= RseNode::FLAG_VARIANT;
}
else if (node->boolExprNode)
node->boolExprNode->flags &= ~BoolExprNode::FLAG_INVARIANT;
else
{
fb_assert(node->legacyNode->nod_type != nod_class_recsrcnode_jrd);
@ -2252,34 +2294,32 @@ jrd_nod* CMP_pass1(thread_db* tdbb, CompilerScratch* csb, jrd_nod* node)
csb->dump(" %d", (USHORT)(IPTR) i.object()->nod_arg[0]);
#endif
jrd_nod* new_node = PAR_make_node(tdbb, 3);
new_node->nod_type = nod_value_if;
new_node->nod_count = 3;
ValueIfNode* valueIfNode = FB_NEW(csb->csb_pool) ValueIfNode(
csb->csb_pool);
jrd_nod* new_node = PAR_make_node(tdbb, 1);
new_node->nod_type = nod_class_exprnode_jrd;
new_node->nod_count = 0;
new_node->nod_arg[0] = reinterpret_cast<jrd_nod*>(valueIfNode);
MissingBoolNode* missingNode = FB_NEW(csb->csb_pool) MissingBoolNode(
csb->csb_pool);
missingNode->arg = i.object();
NotBoolNode* notNode = FB_NEW(csb->csb_pool) NotBoolNode(csb->csb_pool);
notNode->arg = PAR_make_node(tdbb, 1);
notNode->arg->nod_type = nod_class_exprnode_jrd;
notNode->arg->nod_count = 0;
notNode->arg->nod_arg[0] = reinterpret_cast<jrd_nod*>(missingNode);
notNode->arg = missingNode;
// build an IF (RDB$DB_KEY IS NOT NULL)
new_node->nod_arg[0] = PAR_make_node(tdbb, 1);
new_node->nod_arg[0]->nod_type = nod_class_exprnode_jrd;
new_node->nod_arg[0]->nod_count = 0;
new_node->nod_arg[0]->nod_arg[0] = reinterpret_cast<jrd_nod*>(notNode);
valueIfNode->condition = notNode;
new_node->nod_arg[1] = i.object(); // THEN
valueIfNode->trueValue = i.object(); // THEN
const SSHORT count = lit_delta +
(0 + sizeof(jrd_nod*) - 1) / sizeof(jrd_nod*);
new_node->nod_arg[2] = PAR_make_node(tdbb, count); // ELSE
new_node->nod_arg[2]->nod_type = nod_literal;
new_node->nod_arg[2]->nod_count = 0;
Literal* literal = (Literal*) new_node->nod_arg[2];
valueIfNode->falseValue = PAR_make_node(tdbb, count); // ELSE
valueIfNode->falseValue->nod_type = nod_literal;
valueIfNode->falseValue->nod_count = 0;
Literal* literal = (Literal*) valueIfNode->falseValue.getObject();
literal->lit_desc.dsc_dtype = dtype_text;
literal->lit_desc.dsc_ttype() = CS_BINARY;
literal->lit_desc.dsc_scale = 0;
@ -2305,19 +2345,14 @@ jrd_nod* CMP_pass1(thread_db* tdbb, CompilerScratch* csb, jrd_nod* node)
// ASF: If the view is in null state (with outer joins) we need to transform
// the view RDB$KEY to NULL. (CORE-1245)
jrd_nod* new_node = PAR_make_node(tdbb, 3);
new_node->nod_type = nod_value_if;
new_node->nod_count = 3;
ValueIfNode* valueIfNode = FB_NEW(csb->csb_pool) ValueIfNode(
csb->csb_pool);
ComparativeBoolNode* eqlNode = FB_NEW(csb->csb_pool) ComparativeBoolNode(
csb->csb_pool, blr_eql);
// build an IF (RDB$DB_KEY = '')
new_node->nod_arg[0] = PAR_make_node(tdbb, 1);
new_node->nod_arg[0]->nod_type = nod_class_exprnode_jrd;
new_node->nod_arg[0]->nod_count = 0;
new_node->nod_arg[0]->nod_flags = nod_comparison;
new_node->nod_arg[0]->nod_arg[0] = reinterpret_cast<jrd_nod*>(eqlNode);
valueIfNode->condition = eqlNode;
eqlNode->arg1 = NodeCopier::copy(tdbb, csb, node, NULL);
const SSHORT count = lit_delta + (0 + sizeof(jrd_nod*) - 1) / sizeof(jrd_nod*);
@ -2331,11 +2366,14 @@ jrd_nod* CMP_pass1(thread_db* tdbb, CompilerScratch* csb, jrd_nod* node)
literal->lit_desc.dsc_length = 0;
literal->lit_desc.dsc_address = reinterpret_cast<UCHAR*>(literal->lit_data);
new_node->nod_arg[1] = PAR_make_node(tdbb, 0); // THEN: NULL
new_node->nod_arg[1]->nod_type = nod_null;
new_node->nod_arg[2] = node; // ELSE: RDB$DB_KEY
valueIfNode->trueValue = PAR_make_node(tdbb, 0); // THEN: NULL
valueIfNode->trueValue->nod_type = nod_null;
valueIfNode->falseValue = node; // ELSE: RDB$DB_KEY
node = new_node;
node = PAR_make_node(tdbb, 1);
node->nod_type = nod_class_exprnode_jrd;
node->nod_count = 0;
node->nod_arg[0] = reinterpret_cast<jrd_nod*>(valueIfNode);
}
#ifdef CMP_DEBUG
@ -3056,7 +3094,7 @@ jrd_nod* CMP_pass2(thread_db* tdbb, CompilerScratch* csb, jrd_nod* const node, j
if (!(rse_node->flags & RseNode::FLAG_VARIANT))
{
node->nod_flags |= nod_invariant;
csb->csb_invariants.push(node);
csb->csb_invariants.push(&node->nod_impure);
}
rsb_ptr = (RecordSource**) &node->nod_arg[e_stat_rsb];
@ -3140,8 +3178,6 @@ jrd_nod* CMP_pass2(thread_db* tdbb, CompilerScratch* csb, jrd_nod* const node, j
// Handle any residual work
node->nod_impure = CMP_impure(csb, 0);
switch (node->nod_type)
{
case nod_class_recsrcnode_jrd:
@ -3161,24 +3197,24 @@ jrd_nod* CMP_pass2(thread_db* tdbb, CompilerScratch* csb, jrd_nod* const node, j
case nod_from:
case nod_count:
node->nod_count = 0;
csb->csb_impure += sizeof(impure_value_ex);
node->nod_impure = CMP_impure(csb, sizeof(impure_value_ex));
break;
case nod_block:
csb->csb_impure += sizeof(SLONG);
node->nod_impure = CMP_impure(csb, sizeof(SLONG));
break;
case nod_dcl_variable:
{
const dsc* desc = (DSC*) (node->nod_arg + e_dcl_desc);
csb->csb_impure += sizeof(impure_value) + desc->dsc_length;
node->nod_impure = CMP_impure(csb, sizeof(impure_value) + desc->dsc_length);
}
break;
case nod_total:
{
node->nod_count = 0;
csb->csb_impure += sizeof(impure_value_ex);
node->nod_impure = CMP_impure(csb, sizeof(impure_value_ex));
dsc descriptor_a;
CMP_get_desc(tdbb, csb, node, &descriptor_a);
}
@ -3188,9 +3224,9 @@ jrd_nod* CMP_pass2(thread_db* tdbb, CompilerScratch* csb, jrd_nod* const node, j
{
const Format* format = (Format*) node->nod_arg[e_msg_format];
fb_assert(format);
csb->csb_impure += FB_ALIGN(format->fmt_length, 2);
node->nod_arg[e_msg_impure_flags] = (jrd_nod*)(IPTR) CMP_impure(csb, 0);
csb->csb_impure += sizeof(USHORT) * format->fmt_count;
node->nod_impure = CMP_impure(csb, FB_ALIGN(format->fmt_length, 2));
node->nod_arg[e_msg_impure_flags] = (jrd_nod*)(IPTR)
CMP_impure(csb, sizeof(USHORT) * format->fmt_count);
}
break;
@ -3206,7 +3242,7 @@ jrd_nod* CMP_pass2(thread_db* tdbb, CompilerScratch* csb, jrd_nod* const node, j
SBM_SET(tdbb->getDefaultPool(), &csb->csb_rpt[stream].csb_fields, id);
}
}
csb->csb_impure += sizeof(impure_state);
node->nod_impure = CMP_impure(csb, sizeof(impure_state));
}
break;
@ -3228,7 +3264,7 @@ jrd_nod* CMP_pass2(thread_db* tdbb, CompilerScratch* csb, jrd_nod* const node, j
// FALL INTO
case nod_store:
csb->csb_impure += sizeof(impure_state);
node->nod_impure = CMP_impure(csb, sizeof(impure_state));
break;
case nod_erase:
@ -3244,14 +3280,14 @@ jrd_nod* CMP_pass2(thread_db* tdbb, CompilerScratch* csb, jrd_nod* const node, j
SBM_SET(tdbb->getDefaultPool(), &csb->csb_rpt[stream].csb_fields, id);
if (csb->csb_rpt[stream].csb_relation || csb->csb_rpt[stream].csb_procedure)
node->nod_arg[e_fld_format] = (jrd_nod*) CMP_format(tdbb, csb, stream);
csb->csb_impure += sizeof(impure_value_ex);
node->nod_impure = CMP_impure(csb, sizeof(impure_value_ex));
break;
}
case nod_argument:
case nod_variable:
csb->csb_impure += (node->nod_flags & nod_value) ?
sizeof(impure_value_ex) : sizeof(dsc);
node->nod_impure = CMP_impure(csb, (node->nod_flags & nod_value) ?
sizeof(impure_value_ex) : sizeof(dsc));
break;
case nod_literal:
@ -3274,17 +3310,17 @@ jrd_nod* CMP_pass2(thread_db* tdbb, CompilerScratch* csb, jrd_nod* const node, j
{
dsc descriptor_a;
CMP_get_desc(tdbb, csb, node, &descriptor_a);
csb->csb_impure += sizeof(impure_value);
node->nod_impure = CMP_impure(csb, sizeof(impure_value));
}
break;
case nod_exec_into:
csb->csb_impure += sizeof(ExecuteStatement);
node->nod_impure = CMP_impure(csb, sizeof(ExecuteStatement));
csb->csb_exec_sta.push(node);
break;
case nod_exec_stmt:
csb->csb_impure += sizeof(void**);
node->nod_impure = CMP_impure(csb, sizeof(void**));
break;
case nod_class_exprnode_jrd:
@ -3303,16 +3339,16 @@ jrd_nod* CMP_pass2(thread_db* tdbb, CompilerScratch* csb, jrd_nod* const node, j
{
if (csb->csb_current_nodes.hasData())
{
LegacyNodeOrRseNode& top_rse_node = csb->csb_current_nodes[0];
fb_assert(top_rse_node.rseNode);
LegacyNodeOrRseNode& topRseNode = csb->csb_current_nodes[0];
fb_assert(topRseNode.rseNode);
if (!top_rse_node.rseNode->rse_invariants)
if (!topRseNode.rseNode->rse_invariants)
{
top_rse_node.rseNode->rse_invariants =
topRseNode.rseNode->rse_invariants =
FB_NEW(*tdbb->getDefaultPool()) VarInvariantArray(*tdbb->getDefaultPool());
}
top_rse_node.rseNode->rse_invariants->add(node->nod_impure);
topRseNode.rseNode->rse_invariants->add(node->nod_impure);
}
}

View File

@ -30,6 +30,7 @@
UCHAR* CMP_alloc_map(Jrd::thread_db*, Jrd::CompilerScratch*, USHORT);
Jrd::jrd_nod* CMP_clone_node_opt(Jrd::thread_db*, Jrd::CompilerScratch*, Jrd::jrd_nod*);
Jrd::BoolExprNode* CMP_clone_node_opt(Jrd::thread_db*, Jrd::CompilerScratch*, Jrd::BoolExprNode*);
Jrd::jrd_nod* CMP_clone_node(Jrd::thread_db*, Jrd::CompilerScratch*, Jrd::jrd_nod*);
Jrd::jrd_req* CMP_compile2(Jrd::thread_db*, const UCHAR* blr, ULONG blr_length, bool internal_flag,
USHORT = 0, const UCHAR* = NULL);

View File

@ -5245,7 +5245,7 @@ static bool make_version(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_
try
{
jrd_nod* defaultNode = MET_parse_blob(tdbb, relation, defaultValue,
NULL, &defaultStatement, false);
NULL, &defaultStatement, false, false);
jrd_req* const defaultRequest = defaultStatement->findRequest(tdbb);

View File

@ -320,9 +320,6 @@ bool EVL_boolean(thread_db* tdbb, const jrd_nod* node)
DEV_BLKCHK(node, type_nod);
// Handle and pre-processing possible for various nodes. This includes
// evaluating argument and checking NULL flags
jrd_req* request = tdbb->getRequest();
switch (node->nod_type)
@ -578,10 +575,6 @@ dsc* EVL_expr(thread_db* tdbb, const jrd_nod* node)
}
return request->req_domain_validation;
case nod_value_if:
return EVL_expr(tdbb, (EVL_boolean(tdbb, node->nod_arg[0])) ?
node->nod_arg[1] : node->nod_arg[2]);
case nod_trim:
return trim(tdbb, node, impure);

View File

@ -980,11 +980,11 @@ void EXE_start(thread_db* tdbb, jrd_req* request, jrd_tra* transaction)
request->req_timestamp.validate();
// Set all invariants to not computed.
const jrd_nod* const* ptr, * const* end;
const ULONG* const* ptr, * const* end;
for (ptr = statement->invariants.begin(), end = statement->invariants.end();
ptr < end; ++ptr)
{
impure_value* impure = request->getImpure<impure_value>((*ptr)->nod_impure);
impure_value* impure = request->getImpure<impure_value>(**ptr);
impure->vlu_flags = 0;
}
@ -3660,6 +3660,7 @@ static void validate(thread_db* tdbb, const jrd_nod* list)
for (const jrd_nod* const* const end = ptr1 + list->nod_count; ptr1 < end; ptr1++)
{
jrd_req* request = tdbb->getRequest();
if (!EVL_boolean(tdbb, (*ptr1)->nod_arg[e_val_boolean]) && !(request->req_flags & req_null))
{
// Validation error -- report result

View File

@ -125,16 +125,13 @@ public:
***/
};
const int nod_comparison = 1;
const int nod_id = 1; // marks a field node as a blr_fid guy
const int nod_quad = 2; // compute in quad (default is long)
const int nod_double = 4;
const int nod_date = 8;
const int nod_value = 16; // full value area required in impure space
const int nod_deoptimize = 32; // boolean which requires deoptimization
const int nod_agg_dbkey = 64; // dbkey of an aggregate
const int nod_invariant = 128; // node is recognized as being invariant
const int nod_ansi_not = 256; // ANY/ALL predicate is prefixed with a NOT one
const int nod_agg_dbkey = 32; // dbkey of an aggregate
const int nod_invariant = 64; // node is recognized as being invariant
// Types of nulls placement for each column in sort order
const int rse_nulls_default = 0;
@ -631,17 +628,27 @@ struct LegacyNodeOrRseNode
{
LegacyNodeOrRseNode(jrd_nod* aLegacyNode)
: legacyNode(aLegacyNode),
boolExprNode(NULL),
rseNode(NULL)
{
}
LegacyNodeOrRseNode(BoolExprNode* aBoolExprNode)
: legacyNode(NULL),
boolExprNode(aBoolExprNode),
rseNode(NULL)
{
}
LegacyNodeOrRseNode(RseNode* aRseNode)
: legacyNode(NULL),
boolExprNode(NULL),
rseNode(aRseNode)
{
}
jrd_nod* legacyNode;
BoolExprNode* boolExprNode;
RseNode* rseNode;
};
@ -746,7 +753,7 @@ public:
Firebird::Array<Dependency> csb_dependencies; // objects that this statement depends upon
Firebird::Array<const RecordSource*> csb_fors; // record sources
Firebird::Array<jrd_nod*> csb_exec_sta; // Array of exec_into nodes
Firebird::Array<jrd_nod*> csb_invariants; // stack of invariant nodes
Firebird::Array<ULONG*> csb_invariants; // stack of pointer to nodes invariant offsets
Firebird::Array<LegacyNodeOrRseNode> csb_current_nodes; // RseNode's and other invariant
// candidates within whose scope we are
USHORT csb_n_stream; // Next available stream

View File

@ -28,10 +28,12 @@
namespace Jrd {
class Record;
class jrd_nod;
class BoolExprNode;
class RecordSourceNode;
typedef Firebird::Stack<Record*> RecordStack;
typedef Firebird::Stack<jrd_nod*> NodeStack;
typedef Firebird::Stack<BoolExprNode*> BoolExprNodeStack;
typedef Firebird::Stack<RecordSourceNode*> RecordSourceNodeStack;
typedef Firebird::Stack<SLONG> PageStack;
typedef Firebird::Stack<UCHAR*> UCharStack;

View File

@ -1443,7 +1443,7 @@ jrd_nod* MET_get_dependencies(thread_db* tdbb,
else
{
node = MET_parse_blob(tdbb, relation, blob_id, &csb, statementPtr,
(type == obj_trigger && relation != NULL));
(type == obj_trigger && relation != NULL), type == obj_validation);
}
if (type == obj_computed)
@ -2615,7 +2615,8 @@ jrd_nod* MET_parse_blob(thread_db* tdbb,
bid* blob_id,
CompilerScratch** csb_ptr,
JrdStatement** statementPtr,
const bool trigger)
const bool trigger,
bool validationExpr)
{
/**************************************
*
@ -2641,7 +2642,16 @@ jrd_nod* MET_parse_blob(thread_db* tdbb,
UCHAR* temp = tmp.getBuffer(length);
length = BLB_get_data(tdbb, blob, temp, length);
jrd_nod* node = PAR_blr(tdbb, relation, temp, length, NULL, csb_ptr, statementPtr, trigger, 0);
jrd_nod* node = NULL;
if (validationExpr)
{
// The set of MET parse functions needs a rework.
// For now, our caller chain is not interested in the returned node.
PAR_validation_blr(tdbb, relation, temp, length, NULL, csb_ptr, 0, NULL, NULL);
}
else
node = PAR_blr(tdbb, relation, temp, length, NULL, csb_ptr, statementPtr, trigger, 0);
return node;
}
@ -2993,8 +3003,8 @@ jrd_prc* MET_procedure(thread_db* tdbb, int id, bool noscan, USHORT flags)
try
{
parameter->prm_default_value =
MET_parse_blob(tdbb, NULL, &pa_default_value, NULL, NULL, false);
parameter->prm_default_value = MET_parse_blob(tdbb, NULL,
&pa_default_value, NULL, NULL, false, false);
}
catch (const Exception&)
{
@ -3580,7 +3590,7 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation)
NULL, &csb, depName, obj_view, 0, depTrans);
}
else
rseNode = MET_parse_blob(tdbb, relation, &REL.RDB$VIEW_BLR, &csb, NULL, false);
rseNode = MET_parse_blob(tdbb, relation, &REL.RDB$VIEW_BLR, &csb, NULL, false, false);
if (rseNode)
{
@ -3748,14 +3758,14 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation)
// Because a VIEW can't have a validation section i ignored the whole call.
if (!csb)
{
field->fld_validation = PAR_blr(tdbb, relation, p, length, csb,
NULL, NULL, false, csb_validation);
PAR_validation_blr(tdbb, relation, p, length, csb, NULL, csb_validation,
&field->fld_validation, &field->fld_validation_stmt);
}
break;
case RSR_field_not_null:
field->fld_not_null = PAR_blr(tdbb, relation, p, length, csb, NULL,
NULL, false, csb_validation);
PAR_validation_blr(tdbb, relation, p, length, csb, NULL, csb_validation,
&field->fld_not_null, &field->fld_not_null_stmt);
break;
case RSR_security_class:

View File

@ -99,7 +99,7 @@ Jrd::jrd_prc* MET_lookup_procedure_id(Jrd::thread_db*, SSHORT, bool, bool, USHOR
Jrd::jrd_rel* MET_lookup_relation(Jrd::thread_db*, const Firebird::MetaName&);
Jrd::jrd_rel* MET_lookup_relation_id(Jrd::thread_db*, SLONG, bool);
Jrd::jrd_nod* MET_parse_blob(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::bid*, Jrd::CompilerScratch**,
Jrd::JrdStatement**, bool);
Jrd::JrdStatement**, bool, bool);
void MET_parse_sys_trigger(Jrd::thread_db*, Jrd::jrd_rel*);
void MET_post_existence(Jrd::thread_db*, Jrd::jrd_rel*);
void MET_prepare(Jrd::thread_db*, Jrd::jrd_tra*, USHORT, const UCHAR*);

View File

@ -58,7 +58,6 @@ NODE(nod_asn_list, asn_list, "")
NODE(nod_substr, substr, "")
NODE(nod_total, total, "SUM")
NODE(nod_trim, trim, "")
NODE(nod_value_if, value_if, "")
NODE(nod_validate, validate, "")
NODE(nod_exec_proc, exec_proc, "")

File diff suppressed because it is too large Load Diff

View File

@ -44,7 +44,7 @@ namespace Jrd {
bool OPT_access_path(const Jrd::jrd_req*, UCHAR*, SLONG, ULONG*);
Jrd::RecordSource* OPT_compile(Jrd::thread_db*, Jrd::CompilerScratch*,
Jrd::RseNode*, Jrd::NodeStack*);
Jrd::RseNode*, Jrd::BoolExprNodeStack* const);
void OPT_gen_aggregate_distincts(Jrd::thread_db*, Jrd::CompilerScratch*, Jrd::MapNode*);
Jrd::SortedStream* OPT_gen_sort(Jrd::thread_db*, Jrd::CompilerScratch*, const UCHAR*,
const UCHAR*, Jrd::RecordSource*, Jrd::SortNode*, bool);

View File

@ -83,7 +83,8 @@ static const TEXT elements[][14] =
#include "gen/codetext.h"
static NodeParseFunc blr_parsers[256] = {NULL};
static NodeParseFunc blr_parsers[256] = {NULL}; // TODO: separate statements and value expressions
static BoolExprNodeParseFunc boolParsers[256] = {NULL};
static SSHORT find_proc_field(const jrd_prc*, const Firebird::MetaName&);
@ -98,21 +99,12 @@ static jrd_nod* par_modify(thread_db*, CompilerScratch*, SSHORT);
static PlanNode* par_plan(thread_db*, CompilerScratch*);
// Parse blr, returning a compiler scratch block with the results.
// Caller must do pool handling.
jrd_nod* PAR_blr(thread_db* tdbb, jrd_rel* relation, const UCHAR* blr, ULONG blr_length,
CompilerScratch* view_csb, CompilerScratch** csb_ptr, JrdStatement** statementPtr,
const bool trigger, USHORT flags)
{
/**************************************
*
* P A R _ b l r
*
**************************************
*
* Functional description
* Parse blr, returning a compiler scratch block with the results.
* Caller must do pool handling.
*
**************************************/
SET_TDBB(tdbb);
#ifdef CMP_DEBUG
@ -207,6 +199,100 @@ jrd_nod* PAR_blr(thread_db* tdbb, jrd_rel* relation, const UCHAR* blr, ULONG blr
}
// PAR_blr equivalent for validation expressions.
// Validation expressions are boolean expressions, but may be prefixed with a blr_stmt_expr.
void PAR_validation_blr(thread_db* tdbb, jrd_rel* relation, const UCHAR* blr, ULONG blr_length,
CompilerScratch* view_csb, CompilerScratch** csb_ptr, USHORT flags,
BoolExprNode** resultExpr, jrd_nod** resultStmt)
{
SET_TDBB(tdbb);
#ifdef CMP_DEBUG
cmp_trace("BLR code given for JRD parsing:");
// CVC: Couldn't find isc_trace_printer, so changed it to gds__trace_printer.
fb_print_blr(blr, blr_length, gds__trace_printer, 0, 0);
#endif
CompilerScratch* csb;
if (!(csb_ptr && (csb = *csb_ptr)))
{
size_t count = 5;
if (view_csb)
count += view_csb->csb_rpt.getCapacity();
csb = CompilerScratch::newCsb(*tdbb->getDefaultPool(), count);
csb->csb_g_flags |= flags;
}
// If there is a request ptr, this is a trigger. Set up contexts 0 and 1 for
// the target relation
if (relation)
{
CompilerScratch::csb_repeat* t1 = CMP_csb_element(csb, 0);
t1->csb_stream = csb->nextStream();
t1->csb_relation = relation;
t1->csb_flags = csb_used | csb_active;
}
csb->csb_blr_reader = BlrReader(blr, blr_length);
if (view_csb)
{
CompilerScratch::rpt_itr ptr = view_csb->csb_rpt.begin();
// AB: csb_n_stream replaced by view_csb->csb_rpt.getCount(), because there could
// be more then just csb_n_stream-numbers that hold data.
// Certainly csb_stream (see PAR_context where the context is retrieved)
const CompilerScratch::rpt_const_itr end = view_csb->csb_rpt.end();
for (SSHORT stream = 0; ptr != end; ++ptr, ++stream)
{
CompilerScratch::csb_repeat* t2 = CMP_csb_element(csb, stream);
t2->csb_relation = ptr->csb_relation;
t2->csb_procedure = ptr->csb_procedure;
t2->csb_stream = ptr->csb_stream;
t2->csb_flags = ptr->csb_flags & csb_used;
}
csb->csb_n_stream = view_csb->csb_n_stream;
}
const SSHORT version = csb->csb_blr_reader.getByte();
switch (version)
{
case blr_version4:
csb->csb_g_flags |= csb_blr_version4;
break;
case blr_version5:
break; // nothing to do
default:
PAR_error(csb, Arg::Gds(isc_metadata_corrupt) <<
Arg::Gds(isc_wroblrver) << Arg::Num(blr_version4) << Arg::Num(version));
}
jrd_nod* stmt = NULL;
if (csb->csb_blr_reader.peekByte() == blr_stmt_expr)
{
csb->csb_blr_reader.getByte();
stmt = PAR_parse_node(tdbb, csb, STATEMENT);
}
BoolExprNode* expr = PAR_parse_boolean(tdbb, csb);
if (csb->csb_blr_reader.getByte() != (UCHAR) blr_eoc)
PAR_syntax_error(csb, "end_of_command");
if (csb_ptr)
*csb_ptr = csb;
else
delete csb;
if (resultExpr)
*resultExpr = expr;
if (resultStmt)
*resultStmt = stmt;
}
USHORT PAR_desc(thread_db* tdbb, CompilerScratch* csb, DSC* desc, ItemInfo* itemInfo)
{
/**************************************
@ -742,6 +828,13 @@ void PAR_register(UCHAR blr, NodeParseFunc parseFunc)
blr_parsers[blr] = parseFunc;
}
// Registers a parse function for a boolean BLR code.
void PAR_register(UCHAR blr, BoolExprNodeParseFunc parseFunc)
{
fb_assert(!boolParsers[blr] || boolParsers[blr] == parseFunc);
boolParsers[blr] = parseFunc;
}
void PAR_error(CompilerScratch* csb, const Arg::StatusVector& v, bool isSyntaxError)
{
@ -1135,10 +1228,7 @@ static jrd_nod* par_fetch(thread_db* tdbb, CompilerScratch* csb, jrd_nod* node)
ComparativeBoolNode* booleanNode = FB_NEW(csb->csb_pool) ComparativeBoolNode(
csb->csb_pool, blr_eql);
rse->rse_boolean = PAR_make_node(tdbb, 1);
rse->rse_boolean->nod_type = nod_class_exprnode_jrd;
rse->rse_boolean->nod_flags = nod_comparison;
rse->rse_boolean->nod_arg[0] = reinterpret_cast<jrd_nod*>(booleanNode);
rse->rse_boolean = booleanNode;
booleanNode->arg2 = PAR_parse_node(tdbb, csb, VALUE);
@ -1951,7 +2041,7 @@ jrd_nod* PAR_rse(thread_db* tdbb, CompilerScratch* csb, SSHORT rse_op)
switch (op)
{
case blr_boolean:
rse->rse_boolean = PAR_parse_node(tdbb, csb, TYPE_BOOL);
rse->rse_boolean = PAR_parse_boolean(tdbb, csb);
break;
case blr_first:
@ -2119,18 +2209,28 @@ SortNode* PAR_sort_internal(thread_db* tdbb, CompilerScratch* csb, UCHAR blrOp,
}
// Parse a boolean node.
BoolExprNode* PAR_parse_boolean(thread_db* tdbb, CompilerScratch* csb)
{
SET_TDBB(tdbb);
const USHORT blrOffset = csb->csb_blr_reader.getOffset();
const SSHORT blrOp = csb->csb_blr_reader.getByte();
if (blrOp < 0 || blrOp >= FB_NELEM(type_table) || !boolParsers[blrOp])
{
// NS: This error string is correct, please do not mangle it again and again.
// The whole error message is "BLR syntax error: expected %s at offset %d, encountered %d"
PAR_syntax_error(csb, "valid BLR code");
}
return boolParsers[blrOp](tdbb, *tdbb->getDefaultPool(), csb, blrOp);
}
// Parse a BLR expression.
jrd_nod* PAR_parse_node(thread_db* tdbb, CompilerScratch* csb, USHORT expected)
{
/**************************************
*
* P A R _ p a r s e _ n o d e
*
**************************************
*
* Functional description
* Parse a BLR expression.
*
**************************************/
SET_TDBB(tdbb);
const USHORT blr_offset = csb->csb_blr_reader.getOffset();
@ -2170,7 +2270,6 @@ jrd_nod* PAR_parse_node(thread_db* tdbb, CompilerScratch* csb, USHORT expected)
switch (blr_operator)
{
case blr_value_if:
case blr_substring:
*arg++ = PAR_parse_node(tdbb, csb, sub_type);
*arg++ = PAR_parse_node(tdbb, csb, sub_type);

View File

@ -32,6 +32,7 @@ namespace Jrd {
class JrdStatement;
class thread_db;
struct ItemInfo;
class BoolExprNode;
class DmlNode;
class SortNode;
}
@ -51,8 +52,10 @@ struct dsc;
Jrd::jrd_nod* PAR_args(Jrd::thread_db*, Jrd::CompilerScratch*, USHORT, UCHAR, USHORT);
Jrd::jrd_nod* PAR_args(Jrd::thread_db*, Jrd::CompilerScratch*, USHORT);
Jrd::jrd_nod* PAR_blr(Jrd::thread_db*, Jrd::jrd_rel*, const UCHAR*, ULONG blr_length,
Jrd::CompilerScratch*, Jrd::CompilerScratch**, Jrd::JrdStatement**, const bool,
USHORT);
Jrd::CompilerScratch*, Jrd::CompilerScratch**, Jrd::JrdStatement**, const bool, USHORT);
void PAR_validation_blr(Jrd::thread_db*, Jrd::jrd_rel*, const UCHAR* blr,
ULONG blr_length, Jrd::CompilerScratch*, Jrd::CompilerScratch**, USHORT,
Jrd::BoolExprNode**, Jrd::jrd_nod**);
SSHORT PAR_context(Jrd::CompilerScratch*, SSHORT*);
void PAR_dependency(Jrd::thread_db*, Jrd::CompilerScratch*, SSHORT, SSHORT,
const Firebird::MetaName&);
@ -78,8 +81,13 @@ SLONG PAR_symbol_to_gdscode(const Firebird::string&);
typedef Jrd::DmlNode* (*NodeParseFunc)(Jrd::thread_db* tdbb, MemoryPool& pool,
Jrd::CompilerScratch* csb, UCHAR blrOp);
typedef Jrd::BoolExprNode* (*BoolExprNodeParseFunc)(Jrd::thread_db* tdbb, MemoryPool& pool,
Jrd::CompilerScratch* csb, UCHAR blrOp);
Jrd::BoolExprNode* PAR_parse_boolean(Jrd::thread_db* tdbb, Jrd::CompilerScratch* csb);
Jrd::jrd_nod* PAR_parse_node(Jrd::thread_db* tdbb, Jrd::CompilerScratch* csb, USHORT expected);
void PAR_register(UCHAR blr, NodeParseFunc parseFunc);
void PAR_register(UCHAR blr, BoolExprNodeParseFunc parseFunc);
void PAR_syntax_error(Jrd::CompilerScratch* csb, const TEXT* string);
void PAR_warning(const Firebird::Arg::StatusVector& v);

View File

@ -248,7 +248,7 @@ void PCMET_lookup_index(thread_db* tdbb, jrd_rel* relation, index_desc* idx)
{ // scope
Jrd::ContextPoolHolder context(tdbb, dbb->createPool());
idx->idx_expression = MET_parse_blob(tdbb, relation, &IDX.RDB$EXPRESSION_BLR, &csb,
&idx->idx_expression_statement, false);
&idx->idx_expression_statement, false, false);
} // end scope
}
END_FOR

View File

@ -36,7 +36,7 @@ using namespace Jrd;
// Data access: predicate driven filter
// ------------------------------------
FilteredStream::FilteredStream(CompilerScratch* csb, RecordSource* next, jrd_nod* boolean)
FilteredStream::FilteredStream(CompilerScratch* csb, RecordSource* next, BoolExprNode* boolean)
: m_next(next), m_boolean(boolean), m_anyBoolean(NULL),
m_ansiAny(false), m_ansiAll(false), m_ansiNot(false)
{
@ -166,16 +166,16 @@ bool FilteredStream::evaluateBoolean(thread_db* tdbb) const
// on the right.
// ANY/ALL select node pointer
const jrd_nod* select_node;
const BoolExprNode* select_node;
// ANY/ALL column node pointer
const jrd_nod* column_node = m_anyBoolean;
const BoolExprNode* column_node = m_anyBoolean;
if (column_node && (m_ansiAny || m_ansiAll))
{
// see if there's a select node to work with
const BinaryBoolNode* booleanNode = ExprNode::as<BinaryBoolNode>(column_node);
const BinaryBoolNode* booleanNode = column_node->as<BinaryBoolNode>();
if (booleanNode && booleanNode->blrOp == blr_and)
{
@ -202,7 +202,7 @@ bool FilteredStream::evaluateBoolean(thread_db* tdbb) const
while (m_next->getRecord(tdbb))
{
if (EVL_boolean(tdbb, m_boolean))
if (m_boolean->execute(tdbb, request))
{
// found a TRUE value
@ -225,7 +225,7 @@ bool FilteredStream::evaluateBoolean(thread_db* tdbb) const
request->req_flags &= ~req_null;
// select for ANY/ALL processing
const bool select_value = EVL_boolean(tdbb, select_node);
const bool select_value = select_node->execute(tdbb, request);
// see if any record in select stream
@ -234,7 +234,7 @@ bool FilteredStream::evaluateBoolean(thread_db* tdbb) const
// see if any nulls
request->req_flags &= ~req_null;
EVL_boolean(tdbb, column_node);
column_node->execute(tdbb, request);
// see if any record is null
@ -258,7 +258,7 @@ bool FilteredStream::evaluateBoolean(thread_db* tdbb) const
bool result = false;
while (m_next->getRecord(tdbb))
{
if (EVL_boolean(tdbb, m_boolean))
if (m_boolean->execute(tdbb, request))
{
result = true;
break;
@ -283,7 +283,7 @@ bool FilteredStream::evaluateBoolean(thread_db* tdbb) const
// look for a FALSE (and not null either)
if (!EVL_boolean(tdbb, m_boolean) && !(request->req_flags & req_null))
if (!m_boolean->execute(tdbb, request) && !(request->req_flags & req_null))
{
// make sure it wasn't FALSE because there's no select stream record
@ -292,7 +292,7 @@ bool FilteredStream::evaluateBoolean(thread_db* tdbb) const
request->req_flags &= ~req_null;
// select for ANY/ALL processing
const bool select_value = EVL_boolean(tdbb, select_node);
const bool select_value = select_node->execute(tdbb, request);
if (select_value)
{
any_false = true;
@ -326,7 +326,7 @@ bool FilteredStream::evaluateBoolean(thread_db* tdbb) const
// look for a FALSE or null
if (!EVL_boolean(tdbb, m_boolean))
if (!m_boolean->execute(tdbb, request))
{
// make sure it wasn't FALSE because there's no select stream record
@ -335,7 +335,7 @@ bool FilteredStream::evaluateBoolean(thread_db* tdbb) const
request->req_flags &= ~req_null;
// select for ANY/ALL processing
const bool select_value = EVL_boolean(tdbb, select_node);
const bool select_value = select_node->execute(tdbb, request);
if (select_value)
{
any_false = true;
@ -359,7 +359,7 @@ bool FilteredStream::evaluateBoolean(thread_db* tdbb) const
bool result = false;
while (m_next->getRecord(tdbb))
{
if (EVL_boolean(tdbb, m_boolean))
if (m_boolean->execute(tdbb, request))
{
result = true;
break;

View File

@ -50,7 +50,7 @@ NestedLoopJoin::NestedLoopJoin(CompilerScratch* csb, size_t count, RecordSource*
}
NestedLoopJoin::NestedLoopJoin(CompilerScratch* csb, RecordSource* outer, RecordSource* inner,
jrd_nod* boolean, bool semiJoin, bool antiJoin)
BoolExprNode* boolean, bool semiJoin, bool antiJoin)
: m_outerJoin(true), m_semiJoin(semiJoin), m_antiJoin(antiJoin), m_args(csb->csb_pool),
m_boolean(boolean)
{
@ -121,7 +121,7 @@ bool NestedLoopJoin::getRecord(thread_db* tdbb) const
return false;
}
if (m_boolean && !EVL_boolean(tdbb, m_boolean))
if (m_boolean && !m_boolean->execute(tdbb, request))
{
// The boolean pertaining to the left sub-stream is false
// so just join sub-stream to a null valued right sub-stream

View File

@ -38,6 +38,7 @@ namespace Jrd
class jrd_nod;
class jrd_prc;
class AggNode;
class BoolExprNode;
class Sort;
class CompilerScratch;
class RecordBuffer;
@ -422,7 +423,7 @@ namespace Jrd
class FilteredStream : public RecordSource
{
public:
FilteredStream(CompilerScratch* csb, RecordSource* next, jrd_nod* boolean);
FilteredStream(CompilerScratch* csb, RecordSource* next, BoolExprNode* boolean);
void open(thread_db* tdbb) const;
void close(thread_db* tdbb) const;
@ -441,7 +442,7 @@ namespace Jrd
void saveRecords(thread_db* tdbb) const;
void restoreRecords(thread_db* tdbb) const;
void setAnyBoolean(jrd_nod* anyBoolean, bool ansiAny, bool ansiNot)
void setAnyBoolean(BoolExprNode* anyBoolean, bool ansiAny, bool ansiNot)
{
fb_assert(!m_anyBoolean);
m_anyBoolean = anyBoolean;
@ -455,8 +456,8 @@ namespace Jrd
bool evaluateBoolean(thread_db* tdbb) const;
NestConst<RecordSource> m_next;
NestConst<jrd_nod> const m_boolean;
NestConst<jrd_nod> m_anyBoolean;
NestConst<BoolExprNode> const m_boolean;
NestConst<BoolExprNode> m_anyBoolean;
bool m_ansiAny;
bool m_ansiAll;
bool m_ansiNot;
@ -732,7 +733,7 @@ namespace Jrd
public:
NestedLoopJoin(CompilerScratch* csb, size_t count, RecordSource* const* args);
NestedLoopJoin(CompilerScratch* csb, RecordSource* outer, RecordSource* inner,
jrd_nod* boolean, bool semiJoin, bool antiJoin);
BoolExprNode* boolean, bool semiJoin, bool antiJoin);
void open(thread_db* tdbb) const;
void close(thread_db* tdbb) const;
@ -758,7 +759,7 @@ namespace Jrd
const bool m_semiJoin;
const bool m_antiJoin;
Firebird::Array<NestConst<RecordSource> > m_args;
NestConst<jrd_nod> const m_boolean;
NestConst<BoolExprNode> const m_boolean;
};
class FullOuterJoin : public RecordSource

View File

@ -26,19 +26,15 @@
#ifndef JRD_RSE_H
#define JRD_RSE_H
// This is really funny: class rse is not defined here but in exe.h!!!
#include "../include/fb_blk.h"
#include "../common/classes/array.h"
#include "../jrd/constants.h"
#include "../jrd/dsc.h"
#include "../jrd/lls.h"
#include "../jrd/sbm.h"
#include "../jrd/ExtEngineManager.h"
#include "../jrd/RecordBuffer.h"
#include "../dsql/Nodes.h"
struct dsc;
@ -47,34 +43,11 @@ namespace Jrd {
class jrd_nod;
struct sort_key_def;
class CompilerScratch;
class BoolExprNode;
// Array which stores relative pointers to impure areas of invariant nodes
typedef Firebird::SortedArray<ULONG> VarInvariantArray;
// Must be less then MAX_SSHORT. Not used for static arrays.
const int MAX_CONJUNCTS = 32000;
// Note that MAX_STREAMS currently MUST be <= MAX_UCHAR.
// Here we should really have a compile-time fb_assert, since this hard-coded
// limit is NOT negotiable so long as we use an array of UCHAR, where index 0
// tells how many streams are in the array (and the streams themselves are
// identified by a UCHAR).
const int MAX_STREAMS = 255;
// This is number of ULONG's needed to store bit-mapped flags for all streams
// OPT_STREAM_BITS = (MAX_STREAMS + 1) / sizeof(ULONG)
// This value cannot be increased simple way. Decrease is possible, but it is also
// hardcoded in several places such as TEST_DEP_ARRAYS macro
const int OPT_STREAM_BITS = 8;
// Number of streams, conjuncts, indices that will be statically allocated
// in various arrays. Larger numbers will have to be allocated dynamically
const int OPT_STATIC_ITEMS = 16;
typedef Firebird::HalfStaticArray<UCHAR, OPT_STATIC_ITEMS> StreamsArray;
typedef Firebird::SortedArray<int> SortedStreamList;
typedef UCHAR stream_array_t[MAX_STREAMS + 1];
class RseNode;
// General optimizer block
@ -82,7 +55,7 @@ class RseNode;
class OptimizerBlk : public pool_alloc<type_opt>
{
public:
OptimizerBlk(MemoryPool* pool, RseNode* aRse, NodeStack* aParentStack)
OptimizerBlk(MemoryPool* pool, RseNode* aRse, BoolExprNodeStack* aParentStack)
: opt_conjuncts(*pool),
opt_streams(*pool),
rse(aRse),
@ -105,7 +78,7 @@ public:
struct opt_conjunct
{
// Conjunctions and their options
jrd_nod* opt_conjunct_node; // conjunction
BoolExprNode* opt_conjunct_node; // conjunction
UCHAR opt_conjunct_flags;
};
@ -120,9 +93,9 @@ public:
Firebird::HalfStaticArray<opt_stream, OPT_STATIC_ITEMS> opt_streams;
RseNode* const rse;
NodeStack* parentStack;
BoolExprNodeStack* parentStack;
StreamsArray outerStreams, subStreams;
NodeStack conjunctStack;
BoolExprNodeStack conjunctStack;
SLONG conjunctCount;
stream_array_t compileStreams, beds, localStreams, keyStreams;
};

View File

@ -142,7 +142,7 @@ static const VERB verbs[] =
PAIR(nod_substr, blr_substring, 3, 3, VALUE, VALUE),
PAIR(nod_class_exprnode_jrd, blr_subtract, 1, 0, VALUE, VALUE),
PAIR2(nod_total, blr_total, e_stat_length, 2, VALUE, VALUE),
PAIR(nod_value_if, blr_value_if, 3, 3, VALUE, OTHER),
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),
PAIR(nod_class_exprnode_jrd, blr_neq, 1, 0, TYPE_BOOL, VALUE),