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:
parent
9e786f0c8a
commit
9b8171d5c1
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 ')'
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
188
src/jrd/cmp.cpp
188
src/jrd/cmp.cpp
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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*);
|
||||
|
@ -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, "")
|
||||
|
586
src/jrd/opt.cpp
586
src/jrd/opt.cpp
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
|
155
src/jrd/par.cpp
155
src/jrd/par.cpp
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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),
|
||||
|
Loading…
Reference in New Issue
Block a user