mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 18:43:02 +01:00
Refactor nod_rse, nod_relation, nod_procedure, nod_union, nod_aggregate and nod_window.
This commit is contained in:
parent
77fa416d04
commit
48d83b8fef
@ -42,7 +42,7 @@ JRD_ServerFiles= blob_filter.cpp cvt.cpp dpm.epp dyn.epp dyn_def.epp \
|
||||
svc.cpp SysFunction.cpp TempSpace.cpp tpc.cpp tra.cpp validation.cpp \
|
||||
ValueImpl.cpp ValuesImpl.cpp vio.cpp \
|
||||
nodebug.cpp nbak.cpp $(Physical_IO_Module) TextType.cpp \
|
||||
unicode_util.cpp RuntimeStatistics.cpp DebugInterface.cpp \
|
||||
unicode_util.cpp RecordSourceNodes.cpp RuntimeStatistics.cpp DebugInterface.cpp \
|
||||
extds/ExtDS.cpp extds/InternalDS.cpp extds/IscDS.cpp \
|
||||
trace/TraceConfigStorage.cpp trace/TraceLog.cpp \
|
||||
trace/TraceManager.cpp trace/TraceObjects.cpp \
|
||||
|
@ -221,6 +221,7 @@
|
||||
<ClCompile Include="..\..\..\src\jrd\PreparedStatement.cpp" />
|
||||
<ClCompile Include="..\..\..\src\jrd\RandomGenerator.cpp" />
|
||||
<ClCompile Include="..\..\..\src\jrd\RecordBuffer.cpp" />
|
||||
<ClCompile Include="..\..\..\src\jrd\RecordSourceNodes.cpp" />
|
||||
<ClCompile Include="..\..\..\src\jrd\Relation.cpp" />
|
||||
<ClCompile Include="..\..\..\src\jrd\ResultSet.cpp" />
|
||||
<ClCompile Include="..\..\..\src\jrd\rlck.cpp" />
|
||||
@ -427,6 +428,7 @@
|
||||
<ClInclude Include="..\..\..\src\jrd\que.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\RandomGenerator.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\RecordBuffer.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\RecordSourceNodes.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\recsrc\RecordSource.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\Relation.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\relations.h" />
|
||||
|
@ -240,6 +240,9 @@
|
||||
<ClCompile Include="..\..\..\src\jrd\RecordBuffer.cpp">
|
||||
<Filter>JRD files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\src\jrd\RecordSourceNodes.cpp">
|
||||
<Filter>JRD files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\src\jrd\Relation.cpp">
|
||||
<Filter>JRD files</Filter>
|
||||
</ClCompile>
|
||||
@ -854,6 +857,9 @@
|
||||
<ClInclude Include="..\..\..\src\jrd\RecordBuffer.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\jrd\RecordSourceNodes.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\jrd\recsrc\RecordSource.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
|
@ -221,6 +221,7 @@
|
||||
<ClCompile Include="..\..\..\src\jrd\PreparedStatement.cpp" />
|
||||
<ClCompile Include="..\..\..\src\jrd\RandomGenerator.cpp" />
|
||||
<ClCompile Include="..\..\..\src\jrd\RecordBuffer.cpp" />
|
||||
<ClCompile Include="..\..\..\src\jrd\RecordSourceNodes.cpp" />
|
||||
<ClCompile Include="..\..\..\src\jrd\Relation.cpp" />
|
||||
<ClCompile Include="..\..\..\src\jrd\ResultSet.cpp" />
|
||||
<ClCompile Include="..\..\..\src\jrd\rlck.cpp" />
|
||||
@ -427,6 +428,7 @@
|
||||
<ClInclude Include="..\..\..\src\jrd\que.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\RandomGenerator.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\RecordBuffer.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\RecordSourceNodes.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\recsrc\RecordSource.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\Relation.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\relations.h" />
|
||||
|
@ -240,6 +240,9 @@
|
||||
<ClCompile Include="..\..\..\src\jrd\RecordBuffer.cpp">
|
||||
<Filter>JRD files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\src\jrd\RecordSourceNodes.cpp">
|
||||
<Filter>JRD files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\src\jrd\Relation.cpp">
|
||||
<Filter>JRD files</Filter>
|
||||
</ClCompile>
|
||||
@ -854,6 +857,9 @@
|
||||
<ClInclude Include="..\..\..\src\jrd\RecordBuffer.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\jrd\RecordSourceNodes.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\jrd\recsrc\RecordSource.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
|
@ -221,6 +221,7 @@
|
||||
<ClCompile Include="..\..\..\src\jrd\PreparedStatement.cpp" />
|
||||
<ClCompile Include="..\..\..\src\jrd\RandomGenerator.cpp" />
|
||||
<ClCompile Include="..\..\..\src\jrd\RecordBuffer.cpp" />
|
||||
<ClCompile Include="..\..\..\src\jrd\RecordSourceNodes.cpp" />
|
||||
<ClCompile Include="..\..\..\src\jrd\Relation.cpp" />
|
||||
<ClCompile Include="..\..\..\src\jrd\ResultSet.cpp" />
|
||||
<ClCompile Include="..\..\..\src\jrd\rlck.cpp" />
|
||||
@ -427,6 +428,7 @@
|
||||
<ClInclude Include="..\..\..\src\jrd\que.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\RandomGenerator.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\RecordBuffer.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\RecordSourceNodes.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\recsrc\RecordSource.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\Relation.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\relations.h" />
|
||||
|
@ -240,6 +240,9 @@
|
||||
<ClCompile Include="..\..\..\src\jrd\RecordBuffer.cpp">
|
||||
<Filter>JRD files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\src\jrd\RecordSourceNodes.cpp">
|
||||
<Filter>JRD files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\src\jrd\Relation.cpp">
|
||||
<Filter>JRD files</Filter>
|
||||
</ClCompile>
|
||||
@ -857,6 +860,9 @@
|
||||
<ClInclude Include="..\..\..\src\jrd\recsrc\RecordSource.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\jrd\RecordSourceNodes.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\jrd\Relation.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
|
@ -571,6 +571,10 @@
|
||||
RelativePath="..\..\..\src\jrd\RecordBuffer.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\jrd\RecordSourceNodes.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\jrd\Relation.cpp"
|
||||
>
|
||||
@ -1391,6 +1395,10 @@
|
||||
RelativePath="..\..\..\src\jrd\RecordBuffer.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\jrd\RecordSourceNodes.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\jrd\recsrc\RecordSource.h"
|
||||
>
|
||||
|
@ -571,6 +571,10 @@
|
||||
RelativePath="..\..\..\src\jrd\RecordBuffer.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\jrd\RecordSourceNodes.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\jrd\Relation.cpp"
|
||||
>
|
||||
@ -1391,6 +1395,10 @@
|
||||
RelativePath="..\..\..\src\jrd\RecordBuffer.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\jrd\RecordSourceNodes.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\jrd\recsrc\RecordSource.h"
|
||||
>
|
||||
|
@ -571,6 +571,10 @@
|
||||
RelativePath="..\..\..\src\jrd\RecordBuffer.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\jrd\RecordSourceNodes.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\jrd\Relation.cpp"
|
||||
>
|
||||
@ -1391,6 +1395,10 @@
|
||||
RelativePath="..\..\..\src\jrd\RecordBuffer.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\jrd\RecordSourceNodes.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\src\jrd\recsrc\RecordSource.h"
|
||||
>
|
||||
|
@ -709,7 +709,7 @@ ExprNode* SubstringSimilarNode::pass1(thread_db* tdbb, CompilerScratch* csb)
|
||||
|
||||
// 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);
|
||||
csb->csb_current_nodes.push(node.getObject());
|
||||
|
||||
pattern = CMP_pass1(tdbb, csb, pattern);
|
||||
escape = CMP_pass1(tdbb, csb, escape);
|
||||
@ -721,11 +721,11 @@ ExprNode* SubstringSimilarNode::pass1(thread_db* tdbb, CompilerScratch* csb)
|
||||
if ((node->nod_flags & nod_invariant) &&
|
||||
(pattern->nod_type != nod_literal || escape->nod_type != nod_literal))
|
||||
{
|
||||
const jrd_node_base* const* ctx_node, *const *end;
|
||||
const LegacyNodeOrRseNode* ctx_node, *end;
|
||||
for (ctx_node = csb->csb_current_nodes.begin(), end = csb->csb_current_nodes.end();
|
||||
ctx_node < end; ctx_node++)
|
||||
ctx_node != end; ++ctx_node)
|
||||
{
|
||||
if ((*ctx_node)->nod_type == nod_rse)
|
||||
if (ctx_node->rseNode)
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ class Cursor;
|
||||
class dsql_nod;
|
||||
class ExprNode;
|
||||
class jrd_nod;
|
||||
class RecordSelExpr;
|
||||
class RseNode;
|
||||
class SlidingWindow;
|
||||
class TypeClause;
|
||||
|
||||
@ -550,7 +550,7 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
virtual void pass2Cursor(RecordSelExpr*& /*rsePtr*/, Cursor**& /*cursorPtr*/)
|
||||
virtual void pass2Cursor(RseNode*& /*rsePtr*/, Cursor**& /*cursorPtr*/)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "../dsql/node.h"
|
||||
#include "../jrd/blr.h"
|
||||
#include "../jrd/tra.h"
|
||||
#include "../jrd/RecordSourceNodes.h"
|
||||
#include "../jrd/recsrc/Cursor.h"
|
||||
#include "../jrd/cmp_proto.h"
|
||||
#include "../jrd/dfw_proto.h"
|
||||
@ -1291,10 +1292,10 @@ DmlNode* ForNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb,
|
||||
csb->csb_blr_reader.peekByte() == (UCHAR) blr_singular ||
|
||||
csb->csb_blr_reader.peekByte() == (UCHAR) blr_scrollable)
|
||||
{
|
||||
node->rse = PAR_parse_node(tdbb, csb, TYPE_RSE);
|
||||
node->rse = RseNode::getFrom(PAR_parse_node(tdbb, csb, TYPE_RSE));
|
||||
}
|
||||
else
|
||||
node->rse = PAR_rse(tdbb, csb, blrOp);
|
||||
node->rse = RseNode::getFrom(PAR_rse(tdbb, csb, blrOp));
|
||||
|
||||
node->statement = PAR_parse_node(tdbb, csb, STATEMENT);
|
||||
|
||||
@ -1414,7 +1415,7 @@ void ForNode::genBlr()
|
||||
StmtNode* ForNode::pass1(thread_db* tdbb, CompilerScratch* csb)
|
||||
{
|
||||
stall = CMP_pass1(tdbb, csb, stall);
|
||||
rse = CMP_pass1(tdbb, csb, rse);
|
||||
rse->pass1(tdbb, csb, csb->csb_view);
|
||||
statement = CMP_pass1(tdbb, csb, statement);
|
||||
return this;
|
||||
}
|
||||
@ -1422,7 +1423,7 @@ StmtNode* ForNode::pass1(thread_db* tdbb, CompilerScratch* csb)
|
||||
StmtNode* ForNode::pass2(thread_db* tdbb, CompilerScratch* csb)
|
||||
{
|
||||
stall = CMP_pass2(tdbb, csb, stall, node);
|
||||
rse = CMP_pass2(tdbb, csb, rse, node);
|
||||
rse->pass2(tdbb, csb);
|
||||
statement = CMP_pass2(tdbb, csb, statement, node);
|
||||
return this;
|
||||
}
|
||||
|
@ -220,9 +220,9 @@ public:
|
||||
virtual StmtNode* pass1(thread_db* tdbb, CompilerScratch* csb);
|
||||
virtual StmtNode* pass2(thread_db* tdbb, CompilerScratch* csb);
|
||||
|
||||
virtual void pass2Cursor(RecordSelExpr*& rsePtr, Cursor**& cursorPtr)
|
||||
virtual void pass2Cursor(RseNode*& rsePtr, Cursor**& cursorPtr)
|
||||
{
|
||||
rsePtr = reinterpret_cast<RecordSelExpr*>(static_cast<jrd_nod*>(rse));
|
||||
rsePtr = rse;
|
||||
cursorPtr = cursor.getAddress();
|
||||
}
|
||||
|
||||
@ -236,7 +236,7 @@ public:
|
||||
dsql_nod* dsqlLabel;
|
||||
bool dsqlForceSingular;
|
||||
NestConst<jrd_nod> stall;
|
||||
NestConst<jrd_nod> rse;
|
||||
NestConst<RseNode> rse;
|
||||
NestConst<jrd_nod> statement;
|
||||
NestConst<Cursor> cursor;
|
||||
};
|
||||
|
@ -427,7 +427,7 @@ protected:
|
||||
|
||||
virtual USHORT getFieldId(jrd_nod* input);
|
||||
|
||||
protected:
|
||||
public:
|
||||
CompilerScratch* csb;
|
||||
UCHAR* remap;
|
||||
jrd_nod* message;
|
||||
|
@ -65,7 +65,6 @@ namespace Jrd
|
||||
class IndexLock;
|
||||
class ArrayField;
|
||||
struct sort_context;
|
||||
class RecordSelExpr;
|
||||
class vcl;
|
||||
class TextType;
|
||||
class Parameter;
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "../jrd/rse.h"
|
||||
#include "../jrd/ods.h"
|
||||
#include "../jrd/Optimizer.h"
|
||||
#include "../jrd/RecordSourceNodes.h"
|
||||
#include "../jrd/recsrc/RecordSource.h"
|
||||
#include "../dsql/ExprNodes.h"
|
||||
#include "../dsql/StmtNodes.h"
|
||||
@ -89,43 +90,16 @@ 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) {
|
||||
if (node->nod_flags & nod_deoptimize)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Recurse thru interesting sub-nodes
|
||||
|
||||
switch (node->nod_type)
|
||||
{
|
||||
case nod_procedure:
|
||||
{
|
||||
jrd_nod* inputs = node->nod_arg[e_prc_inputs];
|
||||
if (inputs)
|
||||
{
|
||||
fb_assert(inputs->nod_type == nod_asn_list);
|
||||
jrd_nod* const* ptr = inputs->nod_arg;
|
||||
for (const jrd_nod* const* const end = ptr + inputs->nod_count; ptr < end; ptr++)
|
||||
{
|
||||
if (!OPT_computable(csb, *ptr, stream, idx_use, allowOnlyCurrentStream)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case nod_union:
|
||||
{
|
||||
jrd_nod* clauses = node->nod_arg[e_uni_clauses];
|
||||
jrd_nod* const* ptr = clauses->nod_arg;
|
||||
for (const jrd_nod* const* const end = ptr + clauses->nod_count; ptr < end; ptr += 2)
|
||||
{
|
||||
if (!OPT_computable(csb, *ptr, stream, idx_use, allowOnlyCurrentStream)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case nod_class_recsrcnode_jrd:
|
||||
return reinterpret_cast<RecordSourceNode*>(node->nod_arg[0])->computable(
|
||||
csb, stream, idx_use, allowOnlyCurrentStream, NULL);
|
||||
|
||||
case nod_class_exprnode_jrd:
|
||||
{
|
||||
@ -146,17 +120,13 @@ bool OPT_computable(CompilerScratch* csb, jrd_nod* node, SSHORT stream,
|
||||
jrd_nod* const* ptr = node->nod_arg;
|
||||
for (const jrd_nod* const* const end = ptr + node->nod_count; ptr < end; ptr++)
|
||||
{
|
||||
if (!OPT_computable(csb, *ptr, stream, idx_use, allowOnlyCurrentStream)) {
|
||||
if (!OPT_computable(csb, *ptr, stream, idx_use, allowOnlyCurrentStream))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RecordSelExpr* rse;
|
||||
jrd_nod* sub;
|
||||
jrd_nod* value;
|
||||
USHORT n;
|
||||
|
||||
switch (node->nod_type)
|
||||
@ -166,15 +136,12 @@ bool OPT_computable(CompilerScratch* csb, jrd_nod* node, SSHORT stream,
|
||||
if (allowOnlyCurrentStream)
|
||||
{
|
||||
if (n != stream && !(csb->csb_rpt[n].csb_flags & csb_sub_stream))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (n == stream) {
|
||||
if (n == stream)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return csb->csb_rpt[n].csb_flags & csb_active;
|
||||
|
||||
@ -225,115 +192,24 @@ bool OPT_computable(CompilerScratch* csb, jrd_nod* node, SSHORT stream,
|
||||
case nod_total:
|
||||
case nod_count:
|
||||
case nod_from:
|
||||
if ((sub = node->nod_arg[e_stat_default]) &&
|
||||
!OPT_computable(csb, sub, stream, idx_use, allowOnlyCurrentStream))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
rse = (RecordSelExpr*) node->nod_arg[e_stat_rse];
|
||||
value = node->nod_arg[e_stat_value];
|
||||
break;
|
||||
jrd_nod* sub;
|
||||
|
||||
case nod_rse:
|
||||
rse = (RecordSelExpr*) node;
|
||||
value = NULL;
|
||||
break;
|
||||
|
||||
case nod_aggregate:
|
||||
rse = (RecordSelExpr*) node->nod_arg[e_agg_rse];
|
||||
rse->rse_sorted = node->nod_arg[e_agg_group];
|
||||
value = NULL;
|
||||
break;
|
||||
|
||||
case nod_window:
|
||||
rse = (RecordSelExpr*) node->nod_arg[e_win_rse];
|
||||
value = NULL;
|
||||
break;
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
||||
// Node is a record selection expression.
|
||||
bool result = true;
|
||||
|
||||
if ((sub = rse->rse_first) && !OPT_computable(csb, sub, stream, idx_use, allowOnlyCurrentStream)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((sub = rse->rse_skip) && !OPT_computable(csb, sub, stream, idx_use, allowOnlyCurrentStream)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set sub-streams of rse active
|
||||
jrd_nod* const* ptr;
|
||||
const jrd_nod* const* end;
|
||||
|
||||
for (ptr = rse->rse_relation, end = ptr + rse->rse_count; ptr < end; ptr++)
|
||||
{
|
||||
const jrd_nod* const node = *ptr;
|
||||
|
||||
if (node->nod_type == nod_window)
|
||||
{
|
||||
const jrd_nod* windows = node->nod_arg[e_win_windows];
|
||||
|
||||
for (unsigned i = 0; i < windows->nod_count; ++i)
|
||||
if ((sub = node->nod_arg[e_stat_default]) &&
|
||||
!OPT_computable(csb, sub, stream, idx_use, allowOnlyCurrentStream))
|
||||
{
|
||||
n = (USHORT)(IPTR) windows->nod_arg[i]->nod_arg[e_part_stream];
|
||||
csb->csb_rpt[n].csb_flags |= (csb_active | csb_sub_stream);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (node->nod_type != nod_rse)
|
||||
{
|
||||
n = (USHORT)(IPTR) node->nod_arg[STREAM_INDEX(node)];
|
||||
csb->csb_rpt[n].csb_flags |= (csb_active | csb_sub_stream);
|
||||
|
||||
fb_assert(node->nod_arg[e_stat_rse]->nod_type == nod_class_recsrcnode_jrd);
|
||||
RseNode* rse = reinterpret_cast<RseNode*>(node->nod_arg[e_stat_rse]->nod_arg[0]);
|
||||
|
||||
return rse->computable(csb, stream, idx_use, allowOnlyCurrentStream,
|
||||
node->nod_arg[e_stat_value]);
|
||||
}
|
||||
}
|
||||
|
||||
// Check sub-stream
|
||||
if (((sub = rse->rse_boolean) && !OPT_computable(csb, sub, stream, idx_use, allowOnlyCurrentStream)) ||
|
||||
((sub = rse->rse_sorted) && !OPT_computable(csb, sub, stream, idx_use, allowOnlyCurrentStream)) ||
|
||||
((sub = rse->rse_projection) && !OPT_computable(csb, sub, stream, idx_use, allowOnlyCurrentStream)))
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
|
||||
for (ptr = rse->rse_relation, end = ptr + rse->rse_count; ptr < end && result; ptr++)
|
||||
{
|
||||
if (!OPT_computable(csb, (*ptr), stream, idx_use, allowOnlyCurrentStream))
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check value expression, if any
|
||||
if (result && value && !OPT_computable(csb, value, stream, idx_use, allowOnlyCurrentStream)) {
|
||||
result = false;
|
||||
}
|
||||
|
||||
// Reset streams inactive
|
||||
for (ptr = rse->rse_relation, end = ptr + rse->rse_count; ptr < end; ptr++)
|
||||
{
|
||||
const jrd_nod* const node = *ptr;
|
||||
|
||||
if (node->nod_type == nod_window)
|
||||
{
|
||||
const jrd_nod* windows = node->nod_arg[e_win_windows];
|
||||
|
||||
for (unsigned i = 0; i < windows->nod_count; ++i)
|
||||
{
|
||||
n = (USHORT)(IPTR) windows->nod_arg[i]->nod_arg[e_part_stream];
|
||||
csb->csb_rpt[n].csb_flags &= ~(csb_active | csb_sub_stream);
|
||||
}
|
||||
}
|
||||
else if (node->nod_type != nod_rse)
|
||||
{
|
||||
n = (USHORT)(IPTR) (*ptr)->nod_arg[STREAM_INDEX((*ptr))];
|
||||
csb->csb_rpt[n].csb_flags &= ~(csb_active | csb_sub_stream);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -1067,6 +943,7 @@ jrd_nod* OptimizerRetrieval::composeInversion(jrd_nod* node1, jrd_nod* node2,
|
||||
return OPT_make_binary_node(node_type, node1, node2, false);
|
||||
}
|
||||
|
||||
|
||||
void OptimizerRetrieval::findDependentFromStreams(jrd_nod* node, SortedStreamList* streamList) const
|
||||
{
|
||||
/**************************************
|
||||
@ -1081,29 +958,7 @@ void OptimizerRetrieval::findDependentFromStreams(jrd_nod* node, SortedStreamLis
|
||||
|
||||
// Recurse thru interesting sub-nodes
|
||||
|
||||
if (node->nod_type == nod_procedure)
|
||||
{
|
||||
jrd_nod* const inputs = node->nod_arg[e_prc_inputs];
|
||||
if (inputs)
|
||||
{
|
||||
fb_assert(inputs->nod_type == nod_asn_list);
|
||||
jrd_nod* const* ptr = inputs->nod_arg;
|
||||
for (const jrd_nod* const* const end = ptr + inputs->nod_count; ptr < end; ptr++)
|
||||
{
|
||||
findDependentFromStreams(*ptr, streamList);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (node->nod_type == nod_union)
|
||||
{
|
||||
jrd_nod* const clauses = node->nod_arg[e_uni_clauses];
|
||||
jrd_nod* const* ptr = clauses->nod_arg;
|
||||
for (const jrd_nod* const* const end = ptr + clauses->nod_count; ptr < end; ptr += 2)
|
||||
{
|
||||
findDependentFromStreams(*ptr, streamList);
|
||||
}
|
||||
}
|
||||
else if (node->nod_type == nod_class_exprnode_jrd)
|
||||
if (node->nod_type == nod_class_exprnode_jrd)
|
||||
{
|
||||
ExprNode* exprNode = reinterpret_cast<ExprNode*>(node->nod_arg[0]);
|
||||
|
||||
@ -1113,18 +968,18 @@ void OptimizerRetrieval::findDependentFromStreams(jrd_nod* node, SortedStreamLis
|
||||
findDependentFromStreams(**i, streamList);
|
||||
}
|
||||
}
|
||||
else if (node->nod_type == nod_class_recsrcnode_jrd)
|
||||
{
|
||||
reinterpret_cast<RecordSourceNode*>(node->nod_arg[0])->findDependentFromStreams(
|
||||
this, streamList);
|
||||
}
|
||||
else
|
||||
{
|
||||
jrd_nod* const* ptr = node->nod_arg;
|
||||
for (const jrd_nod* const* const end = ptr + node->nod_count; ptr < end; ptr++)
|
||||
{
|
||||
findDependentFromStreams(*ptr, streamList);
|
||||
}
|
||||
}
|
||||
|
||||
RecordSelExpr* rse;
|
||||
jrd_nod* sub;
|
||||
jrd_nod* value;
|
||||
for (const jrd_nod* const* const end = ptr + node->nod_count; ptr < end; ptr++)
|
||||
findDependentFromStreams(*ptr, streamList);
|
||||
}
|
||||
|
||||
switch (node->nod_type)
|
||||
{
|
||||
@ -1136,9 +991,8 @@ void OptimizerRetrieval::findDependentFromStreams(jrd_nod* node, SortedStreamLis
|
||||
(csb->csb_rpt[fieldStream].csb_flags & csb_active) &&
|
||||
!(csb->csb_rpt[fieldStream].csb_flags & csb_trigger))
|
||||
{
|
||||
if (!streamList->exist(fieldStream)) {
|
||||
if (!streamList->exist(fieldStream))
|
||||
streamList->add(fieldStream);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -1180,67 +1034,26 @@ void OptimizerRetrieval::findDependentFromStreams(jrd_nod* node, SortedStreamLis
|
||||
case nod_total:
|
||||
case nod_count:
|
||||
case nod_from:
|
||||
if (sub = node->nod_arg[e_stat_default]) {
|
||||
{
|
||||
jrd_nod* sub;
|
||||
|
||||
if (sub = node->nod_arg[e_stat_default])
|
||||
findDependentFromStreams(sub, streamList);
|
||||
}
|
||||
rse = (RecordSelExpr*) node->nod_arg[e_stat_rse];
|
||||
value = node->nod_arg[e_stat_value];
|
||||
|
||||
fb_assert(node->nod_arg[e_stat_rse]->nod_type == nod_class_recsrcnode_jrd);
|
||||
RseNode* rse = reinterpret_cast<RseNode*>(node->nod_arg[e_stat_rse]->nod_arg[0]);
|
||||
|
||||
rse->findDependentFromStreams(this, streamList);
|
||||
|
||||
jrd_nod* value = node->nod_arg[e_stat_value];
|
||||
|
||||
// Check value expression, if any
|
||||
if (value)
|
||||
findDependentFromStreams(value, streamList);
|
||||
|
||||
break;
|
||||
|
||||
case nod_rse:
|
||||
rse = (RecordSelExpr*) node;
|
||||
value = NULL;
|
||||
break;
|
||||
|
||||
case nod_aggregate:
|
||||
rse = (RecordSelExpr*) node->nod_arg[e_agg_rse];
|
||||
rse->rse_sorted = node->nod_arg[e_agg_group];
|
||||
value = NULL;
|
||||
break;
|
||||
|
||||
case nod_window:
|
||||
rse = (RecordSelExpr*) node->nod_arg[e_win_rse];
|
||||
value = NULL;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Node is a record selection expression.
|
||||
if (sub = rse->rse_first) {
|
||||
findDependentFromStreams(sub, streamList);
|
||||
}
|
||||
|
||||
if (sub = rse->rse_skip) {
|
||||
findDependentFromStreams(sub, streamList);
|
||||
}
|
||||
|
||||
if (sub = rse->rse_boolean) {
|
||||
findDependentFromStreams(sub, streamList);
|
||||
}
|
||||
|
||||
if (sub = rse->rse_sorted) {
|
||||
findDependentFromStreams(sub, streamList);
|
||||
}
|
||||
|
||||
if (sub = rse->rse_projection) {
|
||||
findDependentFromStreams(sub, streamList);
|
||||
}
|
||||
|
||||
jrd_nod* const* ptr;
|
||||
const jrd_nod* const* end;
|
||||
for (ptr = rse->rse_relation, end = ptr + rse->rse_count; ptr < end; ptr++)
|
||||
{
|
||||
findDependentFromStreams(*ptr, streamList);
|
||||
}
|
||||
|
||||
// Check value expression, if any
|
||||
if (value) {
|
||||
findDependentFromStreams(value, streamList);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const string& OptimizerRetrieval::getAlias()
|
||||
|
@ -80,24 +80,6 @@ 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);
|
||||
|
||||
inline int STREAM_INDEX(const jrd_nod* node)
|
||||
{
|
||||
switch (node->nod_type)
|
||||
{
|
||||
case nod_relation:
|
||||
return e_rel_stream;
|
||||
case nod_procedure:
|
||||
return e_prc_stream;
|
||||
case nod_union:
|
||||
return e_uni_stream;
|
||||
case nod_aggregate:
|
||||
return e_agg_stream;
|
||||
default:
|
||||
fb_assert(false);
|
||||
return 0; // silence compiler warning.
|
||||
}
|
||||
}
|
||||
|
||||
enum segmentScanType {
|
||||
segmentScanNone,
|
||||
segmentScanGreater,
|
||||
@ -146,8 +128,6 @@ public:
|
||||
Firebird::Array<IndexScratchSegment*> segments;
|
||||
};
|
||||
|
||||
typedef Firebird::SortedArray<int> SortedStreamList;
|
||||
|
||||
class InversionCandidate
|
||||
{
|
||||
public:
|
||||
@ -182,9 +162,10 @@ public:
|
||||
InversionCandidate* getCost();
|
||||
InversionCandidate* getInversion(IndexTableScan** rsb);
|
||||
|
||||
void findDependentFromStreams(jrd_nod* node, SortedStreamList* streamList) const;
|
||||
|
||||
protected:
|
||||
jrd_nod* composeInversion(jrd_nod* node1, jrd_nod* node2, nod_t node_type) const;
|
||||
void findDependentFromStreams(jrd_nod* node, SortedStreamList* streamList) const;
|
||||
const Firebird::string& getAlias();
|
||||
InversionCandidate* generateInversion(IndexTableScan** rsb);
|
||||
IndexTableScan* generateNavigation();
|
||||
|
2444
src/jrd/RecordSourceNodes.cpp
Normal file
2444
src/jrd/RecordSourceNodes.cpp
Normal file
File diff suppressed because it is too large
Load Diff
463
src/jrd/RecordSourceNodes.h
Normal file
463
src/jrd/RecordSourceNodes.h
Normal file
@ -0,0 +1,463 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Interbase Public
|
||||
* License Version 1.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy
|
||||
* of the License at http://www.Inprise.com/IPL.html
|
||||
*
|
||||
* Software distributed under the License is distributed on an
|
||||
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code was created by Inprise Corporation
|
||||
* and its predecessors. Portions created by Inprise Corporation are
|
||||
* Copyright (C) Inprise Corporation.
|
||||
*
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ______________________________________.
|
||||
* Adriano dos Santos Fernandes
|
||||
*/
|
||||
|
||||
#include "../jrd/common.h"
|
||||
#include "../common/classes/alloc.h"
|
||||
#include "../common/classes/array.h"
|
||||
#include "../common/classes/NestConst.h"
|
||||
#include "../jrd/jrd.h"
|
||||
#include "../jrd/exe.h"
|
||||
#include "../dsql/Visitors.h"
|
||||
|
||||
namespace Jrd {
|
||||
|
||||
class OptimizerRetrieval;
|
||||
class ProcedureScan;
|
||||
class RseNode;
|
||||
|
||||
|
||||
class RecordSourceNode : public Firebird::PermanentStorage
|
||||
{
|
||||
public:
|
||||
enum Type
|
||||
{
|
||||
TYPE_RELATION,
|
||||
TYPE_PROCEDURE,
|
||||
TYPE_AGGREGATE,
|
||||
TYPE_UNION,
|
||||
TYPE_WINDOW,
|
||||
TYPE_RSE
|
||||
};
|
||||
|
||||
RecordSourceNode(Type aType, MemoryPool& pool)
|
||||
: PermanentStorage(pool),
|
||||
type(aType)
|
||||
{
|
||||
}
|
||||
|
||||
virtual USHORT getStream() const
|
||||
{
|
||||
return stream;
|
||||
}
|
||||
|
||||
void setStream(USHORT value)
|
||||
{
|
||||
stream = value;
|
||||
}
|
||||
|
||||
// Identify the streams that make up an RseNode.
|
||||
virtual void getStreams(StreamsArray& list) const
|
||||
{
|
||||
list.add(getStream());
|
||||
}
|
||||
|
||||
virtual RecordSourceNode* copy(thread_db* tdbb, NodeCopier& copier) = 0;
|
||||
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;
|
||||
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;
|
||||
|
||||
// Identify all of the streams for which a dbkey may need to be carried through a sort.
|
||||
virtual void computeDbKeyStreams(UCHAR* streams) const = 0;
|
||||
|
||||
virtual bool computable(CompilerScratch* csb, SSHORT stream, bool idx_use,
|
||||
bool allowOnlyCurrentStream, jrd_nod* value) = 0;
|
||||
virtual void findDependentFromStreams(const OptimizerRetrieval* optRet,
|
||||
SortedStreamList* streamList) = 0;
|
||||
virtual RecordSource* compile(thread_db* tdbb, CompilerScratch* csb, OptimizerBlk* opt,
|
||||
RseNode* rse, NodeStack* parent_stack, stream_array_t& beds, stream_array_t& key_streams,
|
||||
stream_array_t& local_streams, NodeStack& conjunct_stack, stream_array_t& streams,
|
||||
jrd_nod* sort, jrd_nod* aggregate, StreamsArray& outerStreams, SLONG conjunct_count,
|
||||
bool innerSubStream) = 0;
|
||||
|
||||
public:
|
||||
const Type type;
|
||||
|
||||
protected:
|
||||
USHORT stream;
|
||||
};
|
||||
|
||||
class RelationSourceNode : public TypedNode<RecordSourceNode, RecordSourceNode::TYPE_RELATION>
|
||||
{
|
||||
public:
|
||||
explicit RelationSourceNode(MemoryPool& pool)
|
||||
: TypedNode<RecordSourceNode, RecordSourceNode::TYPE_RELATION>(pool),
|
||||
relation(NULL),
|
||||
context(NULL),
|
||||
alias(NULL),
|
||||
view(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
static RelationSourceNode* parse(thread_db* tdbb, CompilerScratch* csb, SSHORT blrOp,
|
||||
bool parseContext);
|
||||
|
||||
virtual RelationSourceNode* copy(thread_db* tdbb, NodeCopier& copier);
|
||||
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);
|
||||
|
||||
virtual void pass2(thread_db* tdbb, CompilerScratch* csb)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void pass2Rse(thread_db* tdbb, CompilerScratch* csb);
|
||||
|
||||
virtual bool containsStream(USHORT checkStream) const
|
||||
{
|
||||
return checkStream == stream;
|
||||
}
|
||||
|
||||
virtual void computeDbKeyStreams(UCHAR* streams) const
|
||||
{
|
||||
fb_assert(streams[0] < MAX_STREAMS && streams[0] < MAX_UCHAR);
|
||||
streams[++streams[0]] = getStream();
|
||||
}
|
||||
|
||||
virtual bool computable(CompilerScratch* csb, SSHORT stream, bool idx_use,
|
||||
bool allowOnlyCurrentStream, jrd_nod* value)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void findDependentFromStreams(const OptimizerRetrieval* optRet,
|
||||
SortedStreamList* streamList)
|
||||
{
|
||||
}
|
||||
|
||||
virtual RecordSource* compile(thread_db* tdbb, CompilerScratch* csb, OptimizerBlk* opt,
|
||||
RseNode* rse, NodeStack* parent_stack, stream_array_t& beds, stream_array_t& key_streams,
|
||||
stream_array_t& local_streams, NodeStack& conjunct_stack, stream_array_t& streams,
|
||||
jrd_nod* sort, jrd_nod* aggregate, StreamsArray& outerStreams, SLONG conjunct_count,
|
||||
bool innerSubStream);
|
||||
|
||||
public:
|
||||
jrd_rel* relation;
|
||||
SSHORT context; // user-specified context number for the relation reference
|
||||
const char* alias; // SQL alias for the relation
|
||||
|
||||
private:
|
||||
jrd_rel* view; // parent view for posting access
|
||||
};
|
||||
|
||||
class ProcedureSourceNode : public TypedNode<RecordSourceNode, RecordSourceNode::TYPE_PROCEDURE>
|
||||
{
|
||||
public:
|
||||
explicit ProcedureSourceNode(MemoryPool& pool)
|
||||
: TypedNode<RecordSourceNode, RecordSourceNode::TYPE_PROCEDURE>(pool),
|
||||
inputs(NULL),
|
||||
in_msg(NULL),
|
||||
procedure(NULL),
|
||||
view(NULL),
|
||||
context(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
static ProcedureSourceNode* parse(thread_db* tdbb, CompilerScratch* csb, SSHORT blrOp);
|
||||
|
||||
virtual ProcedureSourceNode* copy(thread_db* tdbb, NodeCopier& copier);
|
||||
|
||||
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);
|
||||
virtual void pass2(thread_db* tdbb, CompilerScratch* csb);
|
||||
virtual void pass2Rse(thread_db* tdbb, CompilerScratch* csb);
|
||||
|
||||
virtual bool containsStream(USHORT checkStream) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void computeDbKeyStreams(UCHAR* streams) const
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool computable(CompilerScratch* csb, SSHORT stream, bool idx_use,
|
||||
bool allowOnlyCurrentStream, jrd_nod* value);
|
||||
virtual void findDependentFromStreams(const OptimizerRetrieval* optRet,
|
||||
SortedStreamList* streamList);
|
||||
virtual RecordSource* compile(thread_db* tdbb, CompilerScratch* csb, OptimizerBlk* opt,
|
||||
RseNode* rse, NodeStack* parent_stack, stream_array_t& beds, stream_array_t& key_streams,
|
||||
stream_array_t& local_streams, NodeStack& conjunct_stack, stream_array_t& streams,
|
||||
jrd_nod* sort, jrd_nod* aggregate, StreamsArray& outerStreams, SLONG conjunct_count,
|
||||
bool innerSubStream);
|
||||
|
||||
private:
|
||||
ProcedureScan* generate(thread_db* tdbb, OptimizerBlk* opt);
|
||||
|
||||
public:
|
||||
NestConst<jrd_nod> inputs;
|
||||
|
||||
private:
|
||||
NestConst<jrd_nod> in_msg;
|
||||
USHORT procedure;
|
||||
jrd_rel* view;
|
||||
SSHORT context;
|
||||
};
|
||||
|
||||
class AggregateSourceNode : public TypedNode<RecordSourceNode, RecordSourceNode::TYPE_AGGREGATE>
|
||||
{
|
||||
public:
|
||||
explicit AggregateSourceNode(MemoryPool& pool)
|
||||
: TypedNode<RecordSourceNode, RecordSourceNode::TYPE_AGGREGATE>(pool),
|
||||
group(NULL),
|
||||
map(NULL),
|
||||
rse(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
static AggregateSourceNode* parse(thread_db* tdbb, CompilerScratch* csb);
|
||||
|
||||
virtual AggregateSourceNode* copy(thread_db* tdbb, NodeCopier& copier);
|
||||
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);
|
||||
virtual void pass2(thread_db* tdbb, CompilerScratch* csb);
|
||||
virtual void pass2Rse(thread_db* tdbb, CompilerScratch* csb);
|
||||
virtual bool containsStream(USHORT checkStream) const;
|
||||
|
||||
virtual void computeDbKeyStreams(UCHAR* streams) const
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool computable(CompilerScratch* csb, SSHORT stream, bool idx_use,
|
||||
bool allowOnlyCurrentStream, jrd_nod* value);
|
||||
virtual void findDependentFromStreams(const OptimizerRetrieval* optRet,
|
||||
SortedStreamList* streamList);
|
||||
virtual RecordSource* compile(thread_db* tdbb, CompilerScratch* csb, OptimizerBlk* opt,
|
||||
RseNode* rse, NodeStack* parent_stack, stream_array_t& beds, stream_array_t& key_streams,
|
||||
stream_array_t& local_streams, NodeStack& conjunct_stack, stream_array_t& streams,
|
||||
jrd_nod* sort, jrd_nod* aggregate, StreamsArray& outerStreams, SLONG conjunct_count,
|
||||
bool innerSubStream);
|
||||
|
||||
private:
|
||||
RecordSource* generate(thread_db* tdbb, OptimizerBlk* opt, NodeStack* parent_stack,
|
||||
UCHAR shellStream);
|
||||
|
||||
public:
|
||||
NestConst<jrd_nod> group;
|
||||
NestConst<jrd_nod> map;
|
||||
|
||||
private:
|
||||
NestConst<RseNode> rse;
|
||||
};
|
||||
|
||||
class UnionSourceNode : public TypedNode<RecordSourceNode, RecordSourceNode::TYPE_UNION>
|
||||
{
|
||||
public:
|
||||
explicit UnionSourceNode(MemoryPool& pool)
|
||||
: TypedNode<RecordSourceNode, RecordSourceNode::TYPE_UNION>(pool),
|
||||
clauses(pool),
|
||||
maps(pool),
|
||||
mapStream(NULL),
|
||||
recursive(false)
|
||||
{
|
||||
}
|
||||
|
||||
static UnionSourceNode* parse(thread_db* tdbb, CompilerScratch* csb, SSHORT blrOp);
|
||||
|
||||
virtual UnionSourceNode* copy(thread_db* tdbb, NodeCopier& copier);
|
||||
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);
|
||||
virtual void pass2(thread_db* tdbb, CompilerScratch* csb);
|
||||
virtual void pass2Rse(thread_db* tdbb, CompilerScratch* csb);
|
||||
virtual bool containsStream(USHORT checkStream) const;
|
||||
virtual void computeDbKeyStreams(UCHAR* streams) const;
|
||||
virtual bool computable(CompilerScratch* csb, SSHORT stream, bool idx_use,
|
||||
bool allowOnlyCurrentStream, jrd_nod* value);
|
||||
virtual void findDependentFromStreams(const OptimizerRetrieval* optRet,
|
||||
SortedStreamList* streamList);
|
||||
virtual RecordSource* compile(thread_db* tdbb, CompilerScratch* csb, OptimizerBlk* opt,
|
||||
RseNode* rse, NodeStack* parent_stack, stream_array_t& beds, stream_array_t& key_streams,
|
||||
stream_array_t& local_streams, NodeStack& conjunct_stack, stream_array_t& streams,
|
||||
jrd_nod* sort, jrd_nod* aggregate, StreamsArray& outerStreams, SLONG conjunct_count,
|
||||
bool innerSubStream);
|
||||
|
||||
private:
|
||||
RecordSource* generate(thread_db* tdbb, OptimizerBlk* opt, UCHAR* streams, USHORT nstreams,
|
||||
NodeStack* parent_stack, UCHAR shellStream);
|
||||
|
||||
private:
|
||||
Firebird::Array<NestConst<RseNode> > clauses; // RseNode's for union
|
||||
Firebird::Array<NestConst<jrd_nod> > maps; // RseNode's maps
|
||||
USHORT mapStream; // stream for next level record of recursive union
|
||||
bool recursive; // union node is a recursive union
|
||||
};
|
||||
|
||||
class WindowSourceNode : public TypedNode<RecordSourceNode, RecordSourceNode::TYPE_WINDOW>
|
||||
{
|
||||
public:
|
||||
explicit WindowSourceNode(MemoryPool& pool)
|
||||
: TypedNode<RecordSourceNode, RecordSourceNode::TYPE_WINDOW>(pool),
|
||||
rse(NULL),
|
||||
windows(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
static WindowSourceNode* parse(thread_db* tdbb, CompilerScratch* csb);
|
||||
|
||||
private:
|
||||
static jrd_nod* parsePartitionBy(thread_db* tdbb, CompilerScratch* csb);
|
||||
|
||||
public:
|
||||
virtual USHORT getStream() const
|
||||
{
|
||||
fb_assert(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual void getStreams(StreamsArray& list) const;
|
||||
virtual WindowSourceNode* copy(thread_db* tdbb, NodeCopier& copier);
|
||||
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);
|
||||
virtual void pass2(thread_db* tdbb, CompilerScratch* csb);
|
||||
virtual void pass2Rse(thread_db* tdbb, CompilerScratch* csb);
|
||||
virtual bool containsStream(USHORT checkStream) const;
|
||||
|
||||
virtual void computeDbKeyStreams(UCHAR* streams) const
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool computable(CompilerScratch* csb, SSHORT stream, bool idx_use,
|
||||
bool allowOnlyCurrentStream, jrd_nod* value);
|
||||
virtual void findDependentFromStreams(const OptimizerRetrieval* optRet,
|
||||
SortedStreamList* streamList);
|
||||
virtual RecordSource* compile(thread_db* tdbb, CompilerScratch* csb, OptimizerBlk* opt,
|
||||
RseNode* rse, NodeStack* parent_stack, stream_array_t& beds, stream_array_t& key_streams,
|
||||
stream_array_t& local_streams, NodeStack& conjunct_stack, stream_array_t& streams,
|
||||
jrd_nod* sort, jrd_nod* aggregate, StreamsArray& outerStreams, SLONG conjunct_count,
|
||||
bool innerSubStream);
|
||||
|
||||
private:
|
||||
NestConst<RseNode> rse;
|
||||
NestConst<jrd_nod> windows;
|
||||
};
|
||||
|
||||
class RseNode : public TypedNode<RecordSourceNode, RecordSourceNode::TYPE_RSE>
|
||||
{
|
||||
public:
|
||||
static const unsigned FLAG_VARIANT = 0x1; // variant (not invariant?)
|
||||
static const unsigned FLAG_SINGULAR = 0x2; // singleton select
|
||||
static const unsigned FLAG_WRITELOCK = 0x4; // locked for write
|
||||
static const unsigned FLAG_SCROLLABLE = 0x8; // scrollable cursor
|
||||
|
||||
explicit RseNode(MemoryPool& pool)
|
||||
: TypedNode<RecordSourceNode, RecordSourceNode::TYPE_RSE>(pool),
|
||||
rse_jointype(0),
|
||||
rse_invariants(NULL),
|
||||
rse_relations(pool),
|
||||
flags(0)
|
||||
{
|
||||
}
|
||||
|
||||
static RseNode* getFrom(jrd_nod* node)
|
||||
{
|
||||
fb_assert(node->nod_type == nod_class_recsrcnode_jrd);
|
||||
return reinterpret_cast<RseNode*>(node->nod_arg[0]);
|
||||
}
|
||||
|
||||
RseNode* clone()
|
||||
{
|
||||
RseNode* obj = FB_NEW(getPool()) RseNode(getPool());
|
||||
|
||||
obj->rse_jointype = rse_jointype;
|
||||
obj->rse_first = rse_first;
|
||||
obj->rse_skip = rse_skip;
|
||||
obj->rse_boolean = rse_boolean;
|
||||
obj->rse_sorted = rse_sorted;
|
||||
obj->rse_projection = rse_projection;
|
||||
obj->rse_aggregate = rse_aggregate;
|
||||
obj->rse_plan = rse_plan;
|
||||
obj->rse_invariants = rse_invariants;
|
||||
obj->flags = flags;
|
||||
obj->rse_relations = rse_relations;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
virtual void getStreams(StreamsArray& list) const
|
||||
{
|
||||
}
|
||||
|
||||
virtual RseNode* copy(thread_db* tdbb, NodeCopier& copier);
|
||||
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);
|
||||
|
||||
virtual void pass2(thread_db* tdbb, CompilerScratch* csb)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void pass2Rse(thread_db* tdbb, CompilerScratch* csb);
|
||||
virtual bool containsStream(USHORT checkStream) const;
|
||||
virtual void computeDbKeyStreams(UCHAR* streams) const;
|
||||
virtual bool computable(CompilerScratch* csb, SSHORT stream, bool idx_use,
|
||||
bool allowOnlyCurrentStream, jrd_nod* value);
|
||||
virtual void findDependentFromStreams(const OptimizerRetrieval* optRet,
|
||||
SortedStreamList* streamList);
|
||||
virtual RecordSource* compile(thread_db* tdbb, CompilerScratch* csb, OptimizerBlk* opt,
|
||||
RseNode* rse, NodeStack* parent_stack, stream_array_t& beds, stream_array_t& key_streams,
|
||||
stream_array_t& local_streams, NodeStack& conjunct_stack, stream_array_t& streams,
|
||||
jrd_nod* sort, jrd_nod* aggregate, StreamsArray& outerStreams, SLONG conjunct_count,
|
||||
bool innerSubStream);
|
||||
|
||||
private:
|
||||
void computeRseStreams(const CompilerScratch* csb, UCHAR* streams) const;
|
||||
void planCheck(const CompilerScratch* csb) const;
|
||||
static void planSet(CompilerScratch* csb, jrd_nod* plan);
|
||||
|
||||
public:
|
||||
USHORT rse_jointype; // inner, left, full
|
||||
NestConst<jrd_nod> rse_first;
|
||||
NestConst<jrd_nod> rse_skip;
|
||||
NestConst<jrd_nod> rse_boolean;
|
||||
NestConst<jrd_nod> rse_sorted;
|
||||
NestConst<jrd_nod> rse_projection;
|
||||
NestConst<jrd_nod> rse_aggregate; // singleton aggregate for optimizing to index
|
||||
NestConst<jrd_nod> rse_plan; // user-specified access plan
|
||||
NestConst<VarInvariantArray> rse_invariants; // Invariant nodes bound to top-level RSE
|
||||
Firebird::Array<NestConst<RecordSourceNode> > rse_relations;
|
||||
unsigned flags;
|
||||
};
|
||||
|
||||
|
||||
} //namespace Jrd
|
@ -29,6 +29,8 @@
|
||||
namespace Jrd
|
||||
{
|
||||
|
||||
class RseNode;
|
||||
|
||||
// view context block to cache view aliases
|
||||
|
||||
class ViewContext
|
||||
@ -184,7 +186,7 @@ public:
|
||||
Firebird::MetaName rel_owner_name; // ascii owner
|
||||
vec<jrd_fld*>* rel_fields; // vector of field blocks
|
||||
|
||||
RecordSelExpr* rel_view_rse; // view record select expression
|
||||
RseNode* rel_view_rse; // view record select expression
|
||||
ViewContexts rel_view_contexts; // sorted array of view contexts
|
||||
|
||||
Firebird::MetaName rel_security_name; // security class name for relation
|
||||
|
1704
src/jrd/cmp.cpp
1704
src/jrd/cmp.cpp
File diff suppressed because it is too large
Load Diff
@ -28,6 +28,7 @@
|
||||
// req.h includes exe.h => Jrd::CompilerScratch and Jrd::CompilerScratch::csb_repeat.
|
||||
#include "../jrd/scl.h"
|
||||
|
||||
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::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,
|
||||
@ -59,6 +60,7 @@ inline void CMP_post_access(Jrd::thread_db* tdbb,
|
||||
CMP_post_access(tdbb, csb, security_name, view_id, mask, type_name, name, "");
|
||||
}
|
||||
|
||||
void CMP_post_procedure_access(Jrd::thread_db*, Jrd::CompilerScratch*, Jrd::jrd_prc*);
|
||||
void CMP_post_resource(Jrd::ResourceList*, void*, Jrd::Resource::rsc_s, USHORT);
|
||||
void CMP_release(Jrd::thread_db*, Jrd::jrd_req*);
|
||||
void CMP_shutdown_database(Jrd::thread_db*);
|
||||
|
@ -102,6 +102,7 @@
|
||||
#include "../jrd/execute_statement.h"
|
||||
#include "../dsql/dsql_proto.h"
|
||||
#include "../jrd/rpb_chain.h"
|
||||
#include "../jrd/RecordSourceNodes.h"
|
||||
#include "../jrd/VirtualTable.h"
|
||||
#include "../jrd/trace/TraceManager.h"
|
||||
#include "../jrd/trace/TraceJrdHelpers.h"
|
||||
@ -3377,7 +3378,13 @@ static const jrd_nod* store(thread_db* tdbb, const jrd_nod* node, SSHORT which_t
|
||||
jrd_req* request = tdbb->getRequest();
|
||||
jrd_tra* transaction = request->req_transaction;
|
||||
impure_state* impure = request->getImpure<impure_state>(node->nod_impure);
|
||||
SSHORT stream = (USHORT)(IPTR) node->nod_arg[e_sto_relation]->nod_arg[e_rel_stream];
|
||||
|
||||
fb_assert(node->nod_arg[e_sto_relation]->nod_type == nod_class_recsrcnode_jrd);
|
||||
const RelationSourceNode* recSource = reinterpret_cast<const RelationSourceNode*>(
|
||||
node->nod_arg[e_sto_relation]->nod_arg[0]);
|
||||
fb_assert(recSource->type == RelationSourceNode::TYPE);
|
||||
|
||||
SSHORT stream = recSource->getStream();
|
||||
record_param* rpb = &request->req_rpb[stream];
|
||||
jrd_rel* relation = rpb->rpb_relation;
|
||||
|
||||
|
@ -50,6 +50,8 @@
|
||||
|
||||
#include "../jrd/DebugInterface.h"
|
||||
#include "../jrd/BlrReader.h"
|
||||
#include "../dsql/Nodes.h"
|
||||
#include "../dsql/Visitors.h"
|
||||
|
||||
// This macro enables DSQL tracing code
|
||||
//#define CMP_DEBUG
|
||||
@ -142,37 +144,9 @@ 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_recurse = 256; // union node is a recursive union
|
||||
const int nod_unique_sort = 512; // sorts using unique key - for distinct and group by
|
||||
const int nod_ansi_not = 1024; // ANY/ALL predicate is prefixed with a NOT one
|
||||
|
||||
// Special RecordSelExpr node
|
||||
|
||||
class RecordSelExpr : public jrd_node_base
|
||||
{
|
||||
public:
|
||||
USHORT rse_count;
|
||||
USHORT rse_jointype; // inner, left, full
|
||||
NestConst<jrd_nod> rse_first;
|
||||
NestConst<jrd_nod> rse_skip;
|
||||
NestConst<jrd_nod> rse_boolean;
|
||||
NestConst<jrd_nod> rse_sorted;
|
||||
NestConst<jrd_nod> rse_projection;
|
||||
NestConst<jrd_nod> rse_aggregate; // singleton aggregate for optimizing to index
|
||||
NestConst<jrd_nod> rse_plan; // user-specified access plan
|
||||
VarInvariantArray* rse_invariants; // Invariant nodes bound to top-level RSE
|
||||
jrd_nod* rse_relation[1];
|
||||
};
|
||||
|
||||
|
||||
const int rse_variant = 1; // variant (not invariant?)
|
||||
const int rse_singular = 2; // singleton select
|
||||
const int rse_writelock = 4; // locked for write
|
||||
const int rse_scrollable = 8; // scrollable cursor
|
||||
|
||||
// Number of nodes may fit into nod_arg of normal node to get to rse_relation
|
||||
const size_t rse_delta = (sizeof(RecordSelExpr) - sizeof(jrd_nod)) / sizeof(jrd_nod::blk_repeat_type);
|
||||
|
||||
// Types of nulls placement for each column in sort order
|
||||
const int rse_nulls_default = 0;
|
||||
const int rse_nulls_first = 1;
|
||||
@ -282,13 +256,6 @@ const int e_asgn_missing = 2; // Value for comparison for missing
|
||||
const int e_asgn_missing2 = 3; // Value for substitute for missing
|
||||
const int e_asgn_length = 4;
|
||||
|
||||
const int e_rel_stream = 0;
|
||||
const int e_rel_relation = 1;
|
||||
const int e_rel_view = 2; // parent view for posting access
|
||||
const int e_rel_alias = 3; // SQL alias for the relation
|
||||
const int e_rel_context = 4; // user-specified context number for the relation reference
|
||||
const int e_rel_length = 5;
|
||||
|
||||
const int e_idx_retrieval = 0;
|
||||
const int e_idx_length = 1;
|
||||
|
||||
@ -304,21 +271,6 @@ const int e_val_boolean = 0;
|
||||
const int e_val_value = 1;
|
||||
const int e_val_length = 2;
|
||||
|
||||
const int e_uni_stream = 0; // Stream for union
|
||||
const int e_uni_clauses = 1; // RecordSelExpr's for union
|
||||
const int e_uni_map_stream = 2; // stream for next level record of recursive union
|
||||
const int e_uni_length = 3;
|
||||
|
||||
const int e_agg_stream = 0;
|
||||
const int e_agg_rse = 1;
|
||||
const int e_agg_group = 2;
|
||||
const int e_agg_map = 3;
|
||||
const int e_agg_length = 4;
|
||||
|
||||
const int e_win_rse = 0;
|
||||
const int e_win_windows = 1;
|
||||
const int e_win_length = 2;
|
||||
|
||||
// Statistical expressions
|
||||
|
||||
const int e_stat_rse = 0;
|
||||
@ -336,16 +288,6 @@ const int e_esp_out_msg = 3;
|
||||
const int e_esp_procedure = 4;
|
||||
const int e_esp_length = 5;
|
||||
|
||||
// Stored procedure view
|
||||
|
||||
const int e_prc_inputs = 0;
|
||||
const int e_prc_in_msg = 1;
|
||||
const int e_prc_stream = 2;
|
||||
const int e_prc_procedure = 3;
|
||||
const int e_prc_view = 4;
|
||||
const int e_prc_context = 5;
|
||||
const int e_prc_length = 6;
|
||||
|
||||
// Generate id
|
||||
|
||||
const int e_gen_value = 0;
|
||||
@ -727,6 +669,24 @@ struct ItemInfo
|
||||
bool fullDomain;
|
||||
};
|
||||
|
||||
struct LegacyNodeOrRseNode
|
||||
{
|
||||
LegacyNodeOrRseNode(jrd_nod* aLegacyNode)
|
||||
: legacyNode(aLegacyNode),
|
||||
rseNode(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
LegacyNodeOrRseNode(RseNode* aRseNode)
|
||||
: legacyNode(NULL),
|
||||
rseNode(aRseNode)
|
||||
{
|
||||
}
|
||||
|
||||
jrd_nod* legacyNode;
|
||||
RseNode* rseNode;
|
||||
};
|
||||
|
||||
typedef Firebird::GenericMap<Firebird::Pair<Firebird::Left<Firebird::MetaNamePair, FieldInfo> > >
|
||||
MapFieldInfo;
|
||||
typedef Firebird::GenericMap<Firebird::Pair<Firebird::Right<Item, ItemInfo> > > MapItemInfo;
|
||||
@ -829,7 +789,7 @@ public:
|
||||
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<jrd_node_base*> csb_current_nodes; // RecordSelExpr's and other invariant
|
||||
Firebird::Array<LegacyNodeOrRseNode> csb_current_nodes; // RseNode's and other invariant
|
||||
// candidates within whose scope we are
|
||||
USHORT csb_n_stream; // Next available stream
|
||||
USHORT csb_msg_number; // Highest used message number
|
||||
@ -958,6 +918,10 @@ public:
|
||||
// declared as varchar
|
||||
const int XCP_MESSAGE_LENGTH = 1023 - sizeof(USHORT);
|
||||
|
||||
} //namespace Jrd
|
||||
typedef Firebird::HalfStaticArray<UCHAR, OPT_STATIC_ITEMS> StreamsArray;
|
||||
typedef Firebird::SortedArray<int> SortedStreamList;
|
||||
typedef UCHAR stream_array_t[MAX_STREAMS + 1];
|
||||
|
||||
} // namespace Jrd
|
||||
|
||||
#endif // JRD_EXE_H
|
||||
|
@ -130,7 +130,6 @@ class IndexBlock;
|
||||
class IndexLock;
|
||||
class ArrayField;
|
||||
struct sort_context;
|
||||
class RecordSelExpr;
|
||||
class vcl;
|
||||
class TextType;
|
||||
class Parameter;
|
||||
|
@ -28,8 +28,11 @@
|
||||
namespace Jrd {
|
||||
class Record;
|
||||
class jrd_nod;
|
||||
class RecordSourceNode;
|
||||
|
||||
typedef Firebird::Stack<Record*> RecordStack;
|
||||
typedef Firebird::Stack<jrd_nod*> NodeStack;
|
||||
typedef Firebird::Stack<RecordSourceNode*> RecordSourceNodeStack;
|
||||
typedef Firebird::Stack<SLONG> PageStack;
|
||||
typedef Firebird::Stack<UCHAR*> UCharStack;
|
||||
}
|
||||
|
@ -90,6 +90,7 @@
|
||||
#include "../common/utils_proto.h"
|
||||
|
||||
#include "../jrd/PreparedStatement.h"
|
||||
#include "../jrd/RecordSourceNodes.h"
|
||||
#include "../jrd/DebugInterface.h"
|
||||
#include "../common/classes/MsgPrint.h"
|
||||
#include "../jrd/Function.h"
|
||||
@ -3570,20 +3571,25 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation)
|
||||
{
|
||||
// parse the view blr, getting dependencies on relations, etc. at the same time
|
||||
|
||||
jrd_nod* rseNode;
|
||||
|
||||
if (dependencies)
|
||||
{
|
||||
const MetaName depName(REL.RDB$RELATION_NAME);
|
||||
relation->rel_view_rse =
|
||||
(RecordSelExpr*) MET_get_dependencies(tdbb, relation, NULL, 0, NULL,
|
||||
&REL.RDB$VIEW_BLR, NULL,
|
||||
&csb, depName, obj_view, 0, depTrans);
|
||||
rseNode = MET_get_dependencies(tdbb, relation, NULL, 0, NULL, &REL.RDB$VIEW_BLR,
|
||||
NULL, &csb, depName, obj_view, 0, depTrans);
|
||||
}
|
||||
else
|
||||
rseNode = MET_parse_blob(tdbb, relation, &REL.RDB$VIEW_BLR, &csb, NULL, false);
|
||||
|
||||
if (rseNode)
|
||||
{
|
||||
relation->rel_view_rse =
|
||||
(RecordSelExpr*) MET_parse_blob(tdbb, relation,
|
||||
&REL.RDB$VIEW_BLR, &csb, NULL, false);
|
||||
fb_assert(rseNode->nod_type == nod_class_recsrcnode_jrd);
|
||||
relation->rel_view_rse = reinterpret_cast<RseNode*>(rseNode->nod_arg[0]);
|
||||
fb_assert(relation->rel_view_rse->type == RseNode::TYPE);
|
||||
}
|
||||
else
|
||||
relation->rel_view_rse = NULL;
|
||||
|
||||
// retrieve the view context names
|
||||
|
||||
|
@ -92,14 +92,9 @@ NODE(nod_asn_list, asn_list, "")
|
||||
NODE(nod_not, not, " NOT ")
|
||||
NODE(nod_validate, validate, "")
|
||||
|
||||
NODE(nod_relation, relation, "")
|
||||
NODE(nod_rse, RecordSelExpr, "")
|
||||
NODE(nod_sort, sort, "")
|
||||
NODE(nod_union, union, "")
|
||||
NODE(nod_aggregate, aggregate, "")
|
||||
NODE(nod_map, map, "")
|
||||
NODE(nod_exec_proc, exec_proc, "")
|
||||
NODE(nod_procedure, procedure, "")
|
||||
NODE(nod_block, block, "")
|
||||
NODE(nod_error_handler, error_handler, "")
|
||||
NODE(nod_cast, cast, "CAST")
|
||||
@ -115,9 +110,6 @@ NODE(nod_asn_list, asn_list, "")
|
||||
NODE(nod_indices, indices, "INDICES")
|
||||
NODE(nod_retrieve, retrieve, "RETRIEVE")
|
||||
|
||||
NODE(nod_relation2, relation2, "RELATION2")
|
||||
NODE(nod_rid2, rid2, "RID2")
|
||||
|
||||
NODE(nod_set_generator, set_generator, "")
|
||||
|
||||
/* Required for NULL handling */
|
||||
@ -170,7 +162,7 @@ NODE(nod_asn_list, asn_list, "")
|
||||
NODE(nod_domain_validation, domain_validation, "")
|
||||
NODE(nod_class_exprnode_jrd, class_exprnode_jrd, "class_exprnode_jrd")
|
||||
NODE(nod_class_stmtnode_jrd, class_stmtnode_jrd, "class_stmtnode_jrd")
|
||||
NODE(nod_class_recsrcnode_jrd, class_recsrcnode_jrd, "class_recsrcnode_jrd")
|
||||
NODE(nod_stmt_expr, stmt_expr, "stmt_expr")
|
||||
NODE(nod_derived_expr, derived_expr, "derived_expr")
|
||||
NODE(nod_continue_loop, continue_loop, "")
|
||||
NODE(nod_window, window, "")
|
||||
|
921
src/jrd/opt.cpp
921
src/jrd/opt.cpp
File diff suppressed because it is too large
Load Diff
@ -33,7 +33,6 @@ namespace Jrd {
|
||||
class jrd_req;
|
||||
class jrd_rel;
|
||||
class jrd_nod;
|
||||
class RecordSelExpr;
|
||||
class RecordSource;
|
||||
struct index_desc;
|
||||
class CompilerScratch;
|
||||
@ -43,7 +42,7 @@ namespace Jrd {
|
||||
|
||||
bool OPT_access_path(const Jrd::jrd_req*, UCHAR*, SLONG, ULONG*);
|
||||
Jrd::RecordSource* OPT_compile(Jrd::thread_db*, Jrd::CompilerScratch*,
|
||||
Jrd::RecordSelExpr*, Jrd::NodeStack*);
|
||||
Jrd::RseNode*, Jrd::NodeStack*);
|
||||
void OPT_gen_aggregate_distincts(Jrd::thread_db*, Jrd::CompilerScratch*, Jrd::jrd_nod*);
|
||||
Jrd::SortedStream* OPT_gen_sort(Jrd::thread_db*, Jrd::CompilerScratch*, const UCHAR*,
|
||||
const UCHAR*, Jrd::RecordSource*, Jrd::jrd_nod*, bool);
|
||||
|
533
src/jrd/par.cpp
533
src/jrd/par.cpp
@ -62,6 +62,7 @@
|
||||
#include "../jrd/met_proto.h"
|
||||
#include "../jrd/par_proto.h"
|
||||
#include "../common/utils_proto.h"
|
||||
#include "../jrd/RecordSourceNodes.h"
|
||||
#include "../jrd/SysFunction.h"
|
||||
#include "../jrd/BlrReader.h"
|
||||
#include "../jrd/Function.h"
|
||||
@ -86,22 +87,13 @@ static NodeParseFunc blr_parsers[256] = {NULL};
|
||||
static SSHORT find_proc_field(const jrd_prc*, const Firebird::MetaName&);
|
||||
static jrd_nod* par_cast(thread_db*, CompilerScratch*);
|
||||
static PsqlException* par_conditions(thread_db*, CompilerScratch*);
|
||||
static SSHORT par_context(CompilerScratch*, SSHORT *);
|
||||
static void par_dependency(thread_db*, CompilerScratch*, SSHORT, SSHORT, const Firebird::MetaName&);
|
||||
static jrd_nod* par_exec_proc(thread_db*, CompilerScratch*, SSHORT);
|
||||
static jrd_nod* par_fetch(thread_db*, CompilerScratch*, jrd_nod*);
|
||||
static jrd_nod* par_field(thread_db*, CompilerScratch*, SSHORT);
|
||||
static jrd_nod* par_literal(thread_db*, CompilerScratch*);
|
||||
static jrd_nod* par_map(thread_db*, CompilerScratch*, USHORT);
|
||||
static jrd_nod* par_message(thread_db*, CompilerScratch*);
|
||||
static jrd_nod* par_modify(thread_db*, CompilerScratch*, SSHORT);
|
||||
static jrd_nod* par_partition_by(thread_db*, CompilerScratch*);
|
||||
static jrd_nod* par_plan(thread_db*, CompilerScratch*);
|
||||
static jrd_nod* par_procedure(thread_db*, CompilerScratch*, SSHORT);
|
||||
static void par_procedure_parms(thread_db*, CompilerScratch*, jrd_prc*, jrd_nod**, jrd_nod**, bool);
|
||||
static jrd_nod* par_relation(thread_db*, CompilerScratch*, SSHORT, bool);
|
||||
static jrd_nod* par_sort(thread_db*, CompilerScratch*, bool, bool);
|
||||
static jrd_nod* par_union(thread_db*, CompilerScratch*, bool);
|
||||
|
||||
|
||||
jrd_nod* PAR_blr(thread_db* tdbb, jrd_rel* relation, const UCHAR* blr, ULONG blr_length,
|
||||
@ -169,7 +161,7 @@ jrd_nod* PAR_blr(thread_db* tdbb, jrd_rel* relation, const UCHAR* blr, ULONG blr
|
||||
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)
|
||||
// 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)
|
||||
{
|
||||
@ -588,7 +580,7 @@ jrd_nod* PAR_make_field(thread_db* tdbb, CompilerScratch* csb,
|
||||
}
|
||||
|
||||
if (csb->csb_g_flags & csb_get_dependencies) {
|
||||
par_dependency(tdbb, csb, stream, id, base_field);
|
||||
PAR_dependency(tdbb, csb, stream, id, base_field);
|
||||
}
|
||||
|
||||
jrd_nod* temp_node = PAR_gen_field(tdbb, stream, id);
|
||||
@ -961,11 +953,11 @@ static PsqlException* par_conditions(thread_db* tdbb, CompilerScratch* csb)
|
||||
}
|
||||
|
||||
|
||||
static SSHORT par_context(CompilerScratch* csb, SSHORT* context_ptr)
|
||||
SSHORT PAR_context(CompilerScratch* csb, SSHORT* context_ptr)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* p a r _ c o n t e x t
|
||||
* P A R _ c o n t e x t
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
@ -1007,15 +999,12 @@ static SSHORT par_context(CompilerScratch* csb, SSHORT* context_ptr)
|
||||
}
|
||||
|
||||
|
||||
static void par_dependency(thread_db* tdbb,
|
||||
CompilerScratch* csb,
|
||||
SSHORT stream,
|
||||
SSHORT id,
|
||||
const Firebird::MetaName& field_name)
|
||||
void PAR_dependency(thread_db* tdbb, CompilerScratch* csb, SSHORT stream, SSHORT id,
|
||||
const MetaName& field_name)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* p a r _ d e p e n d e n c y
|
||||
* P A R _ d e p e n d e n c y
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
@ -1094,10 +1083,10 @@ static jrd_nod* par_exec_proc(thread_db* tdbb, CompilerScratch* csb, SSHORT blr_
|
||||
node->nod_count = count_table[blr_exec_proc];
|
||||
node->nod_arg[e_esp_procedure] = (jrd_nod*) procedure;
|
||||
|
||||
par_procedure_parms(tdbb, csb, procedure, &node->nod_arg[e_esp_in_msg],
|
||||
&node->nod_arg[e_esp_inputs], true);
|
||||
par_procedure_parms(tdbb, csb, procedure, &node->nod_arg[e_esp_out_msg],
|
||||
&node->nod_arg[e_esp_outputs], false);
|
||||
PAR_procedure_parms(tdbb, csb, procedure, &node->nod_arg[e_esp_in_msg],
|
||||
&node->nod_arg[e_esp_inputs], true);
|
||||
PAR_procedure_parms(tdbb, csb, procedure, &node->nod_arg[e_esp_out_msg],
|
||||
&node->nod_arg[e_esp_outputs], false);
|
||||
|
||||
CompilerScratch::Dependency dependency(obj_procedure);
|
||||
dependency.procedure = procedure;
|
||||
@ -1125,15 +1114,19 @@ static jrd_nod* par_fetch(thread_db* tdbb, CompilerScratch* csb, jrd_nod* node)
|
||||
|
||||
ForNode* forNode = reinterpret_cast<ForNode*>(node->nod_arg[0]);
|
||||
|
||||
// Fake RecordSelExpr
|
||||
// Fake RseNode
|
||||
|
||||
forNode->rse = PAR_make_node(tdbb, 1 + rse_delta + 2);
|
||||
RecordSelExpr* rse = reinterpret_cast<RecordSelExpr*>(static_cast<jrd_nod*>(forNode->rse));
|
||||
rse->nod_type = nod_rse;
|
||||
rse->nod_count = 0;
|
||||
rse->rse_count = 1;
|
||||
jrd_nod* relation = PAR_parse_node(tdbb, csb, RELATION);
|
||||
rse->rse_relation[0] = relation;
|
||||
RseNode* rse = forNode->rse = FB_NEW(*tdbb->getDefaultPool()) RseNode(
|
||||
*tdbb->getDefaultPool());
|
||||
|
||||
jrd_nod* relationNode = PAR_parse_node(tdbb, csb, RELATION);
|
||||
fb_assert(relationNode->nod_type == nod_class_recsrcnode_jrd);
|
||||
|
||||
RelationSourceNode* relationSource = reinterpret_cast<RelationSourceNode*>(
|
||||
relationNode->nod_arg[0]);
|
||||
fb_assert(relationSource->type == RelationSourceNode::TYPE);
|
||||
|
||||
rse->rse_relations.add(relationSource);
|
||||
|
||||
// Fake boolean
|
||||
|
||||
@ -1145,7 +1138,7 @@ static jrd_nod* par_fetch(thread_db* tdbb, CompilerScratch* csb, jrd_nod* node)
|
||||
booleanNode = booleanNode->nod_arg[0];
|
||||
booleanNode->nod_type = nod_dbkey;
|
||||
booleanNode->nod_count = 0;
|
||||
booleanNode->nod_arg[0] = relation->nod_arg[e_rel_stream];
|
||||
booleanNode->nod_arg[0] = (jrd_nod*)(IPTR) relationSource->getStream();
|
||||
|
||||
// Pick up statement
|
||||
|
||||
@ -1303,9 +1296,9 @@ static jrd_nod* par_field(thread_db* tdbb, CompilerScratch* csb, SSHORT blr_oper
|
||||
if (csb->csb_g_flags & csb_get_dependencies)
|
||||
{
|
||||
if (blr_operator == blr_fid)
|
||||
par_dependency(tdbb, csb, stream, id, "");
|
||||
PAR_dependency(tdbb, csb, stream, id, "");
|
||||
else
|
||||
par_dependency(tdbb, csb, stream, id, name);
|
||||
PAR_dependency(tdbb, csb, stream, id, name);
|
||||
}
|
||||
|
||||
jrd_nod* node = PAR_gen_field(tdbb, stream, id);
|
||||
@ -1434,43 +1427,6 @@ static jrd_nod* par_literal(thread_db* tdbb, CompilerScratch* csb)
|
||||
}
|
||||
|
||||
|
||||
static jrd_nod* par_map(thread_db* tdbb, CompilerScratch* csb, USHORT stream)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* p a r _ m a p
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Parse a MAP clause for a union or global aggregate expression.
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
|
||||
if (csb->csb_blr_reader.getByte() != blr_map)
|
||||
PAR_syntax_error(csb, "blr_map");
|
||||
|
||||
SSHORT count = csb->csb_blr_reader.getWord();
|
||||
NodeStack map;
|
||||
|
||||
while (--count >= 0)
|
||||
{
|
||||
jrd_nod* assignment = PAR_make_node(tdbb, e_asgn_length);
|
||||
assignment->nod_type = nod_assignment;
|
||||
assignment->nod_count = e_asgn_length;
|
||||
assignment->nod_arg[e_asgn_to] = PAR_gen_field(tdbb, stream, csb->csb_blr_reader.getWord());
|
||||
assignment->nod_arg[e_asgn_from] = PAR_parse_node(tdbb, csb, VALUE);
|
||||
map.push(assignment);
|
||||
}
|
||||
|
||||
jrd_nod* node = PAR_make_list(tdbb, map);
|
||||
node->nod_type = nod_map;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
static jrd_nod* par_message(thread_db* tdbb, CompilerScratch* csb)
|
||||
{
|
||||
/**************************************
|
||||
@ -1651,64 +1607,6 @@ size_t PAR_name(CompilerScratch* csb, Firebird::string& name)
|
||||
}
|
||||
|
||||
|
||||
static jrd_nod* par_partition_by(thread_db* tdbb, CompilerScratch* csb)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* p a r _ p a r t i t i o n _ b y
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Parse PARTITION BY subclauses of window functions.
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
|
||||
if (csb->csb_blr_reader.getByte() != blr_partition_by)
|
||||
PAR_syntax_error(csb, "blr_partition_by");
|
||||
|
||||
SSHORT context;
|
||||
SSHORT partitionStream;
|
||||
partitionStream = par_context(csb, &context);
|
||||
|
||||
jrd_nod* list = PAR_make_node(tdbb, e_part_length);
|
||||
list->nod_type = nod_list;
|
||||
list->nod_count = e_part_count;
|
||||
|
||||
const UCHAR count = csb->csb_blr_reader.getByte();
|
||||
|
||||
if (count != 0)
|
||||
{
|
||||
jrd_nod*& groupNode = list->nod_arg[e_part_group];
|
||||
jrd_nod*& regroupNode = list->nod_arg[e_part_regroup];
|
||||
|
||||
groupNode = PAR_args(tdbb, csb, VALUE, count, count * 3);
|
||||
regroupNode = PAR_args(tdbb, csb, VALUE, count, count);
|
||||
|
||||
// We have allocated groupNode with bigger length than expressions. This is to use in
|
||||
// OPT_gen_sort. Now fill that info.
|
||||
|
||||
groupNode->nod_type = nod_sort;
|
||||
|
||||
for (unsigned i = 0; i < count; ++i)
|
||||
{
|
||||
groupNode->nod_arg[count + i] = (jrd_nod*)(IPTR) false; // ascending
|
||||
groupNode->nod_arg[count * 2 + i] = (jrd_nod*)(IPTR) rse_nulls_first;
|
||||
}
|
||||
}
|
||||
|
||||
if (csb->csb_blr_reader.getByte() != blr_sort)
|
||||
PAR_syntax_error(csb, "blr_sort");
|
||||
|
||||
list->nod_arg[e_part_order] = par_sort(tdbb, csb, true, true);
|
||||
list->nod_arg[e_part_map] = par_map(tdbb, csb, partitionStream);
|
||||
list->nod_arg[e_part_stream] = (jrd_nod*)(IPTR) partitionStream;
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
static jrd_nod* par_plan(thread_db* tdbb, CompilerScratch* csb)
|
||||
{
|
||||
/**************************************
|
||||
@ -1762,17 +1660,23 @@ static jrd_nod* par_plan(thread_db* tdbb, CompilerScratch* csb)
|
||||
// this would add a new context; while this is a reference to
|
||||
// an existing context
|
||||
|
||||
jrd_nod* relation_node = par_relation(tdbb, csb, n, false);
|
||||
RelationSourceNode* recSource = RelationSourceNode::parse(tdbb, csb, n, false);
|
||||
|
||||
jrd_nod* relation_node = PAR_make_node(tdbb, 1);
|
||||
relation_node->nod_type = nod_class_recsrcnode_jrd;
|
||||
relation_node->nod_count = 0;
|
||||
relation_node->nod_arg[0] = (jrd_nod*) recSource;
|
||||
|
||||
plan->nod_arg[e_retrieve_relation] = relation_node;
|
||||
jrd_rel* relation = (jrd_rel*) relation_node->nod_arg[e_rel_relation];
|
||||
jrd_rel* relation = (jrd_rel*) recSource->relation;
|
||||
|
||||
n = csb->csb_blr_reader.getByte();
|
||||
if (n >= csb->csb_rpt.getCount() || !(csb->csb_rpt[n].csb_flags & csb_used))
|
||||
PAR_error(csb, Arg::Gds(isc_ctxnotdef));
|
||||
const SSHORT stream = csb->csb_rpt[n].csb_stream;
|
||||
|
||||
relation_node->nod_arg[e_rel_stream] = (jrd_nod*) (IPTR) stream;
|
||||
relation_node->nod_arg[e_rel_context] = (jrd_nod*) (IPTR) n;
|
||||
recSource->setStream(stream);
|
||||
recSource->context = n;
|
||||
|
||||
// Access plan types (sequential is default)
|
||||
|
||||
@ -1913,123 +1817,12 @@ static jrd_nod* par_plan(thread_db* tdbb, CompilerScratch* csb)
|
||||
}
|
||||
|
||||
|
||||
static jrd_nod* par_procedure(thread_db* tdbb, CompilerScratch* csb, SSHORT blr_operator)
|
||||
void PAR_procedure_parms(thread_db* tdbb, CompilerScratch* csb, jrd_prc* procedure,
|
||||
jrd_nod** message_ptr, jrd_nod** parameter_ptr, bool input_flag)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* p a r _ p r o c e d u r e
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Parse an procedural view reference.
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
|
||||
jrd_prc* procedure = NULL;
|
||||
Firebird::string* alias_string = NULL;
|
||||
QualifiedName name;
|
||||
|
||||
switch (blr_operator)
|
||||
{
|
||||
case blr_pid:
|
||||
case blr_pid2:
|
||||
{
|
||||
const SSHORT pid = csb->csb_blr_reader.getWord();
|
||||
|
||||
if (blr_operator == blr_pid2)
|
||||
{
|
||||
alias_string = FB_NEW(csb->csb_pool) Firebird::string(csb->csb_pool);
|
||||
PAR_name(csb, *alias_string);
|
||||
}
|
||||
|
||||
if (!(procedure = MET_lookup_procedure_id(tdbb, pid, false, false, 0)))
|
||||
{
|
||||
name.identifier.printf("id %d", pid);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case blr_procedure:
|
||||
case blr_procedure2:
|
||||
case blr_procedure3:
|
||||
case blr_procedure4:
|
||||
{
|
||||
if (blr_operator == blr_procedure3 || blr_operator == blr_procedure4)
|
||||
{
|
||||
PAR_name(csb, name.package);
|
||||
}
|
||||
|
||||
PAR_name(csb, name.identifier);
|
||||
|
||||
if (blr_operator == blr_procedure2 || blr_operator == blr_procedure4)
|
||||
{
|
||||
alias_string = FB_NEW(csb->csb_pool) Firebird::string(csb->csb_pool);
|
||||
PAR_name(csb, *alias_string);
|
||||
}
|
||||
|
||||
procedure = MET_lookup_procedure(tdbb, name, false);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fb_assert(false);
|
||||
}
|
||||
|
||||
if (!procedure)
|
||||
{
|
||||
PAR_error(csb, Arg::Gds(isc_prcnotdef) << Arg::Str(name.toString()));
|
||||
}
|
||||
|
||||
if (procedure->prc_type == prc_executable)
|
||||
{
|
||||
const string name = procedure->getName().toString();
|
||||
|
||||
if (tdbb->getAttachment()->att_flags & ATT_gbak_attachment)
|
||||
{
|
||||
PAR_warning(Arg::Warning(isc_illegal_prc_type) << Arg::Str(name));
|
||||
}
|
||||
else
|
||||
{
|
||||
PAR_error(csb, Arg::Gds(isc_illegal_prc_type) << Arg::Str(name));
|
||||
}
|
||||
}
|
||||
|
||||
jrd_nod* const node = PAR_make_node(tdbb, e_prc_length);
|
||||
node->nod_type = nod_procedure;
|
||||
node->nod_count = count_table[blr_procedure];
|
||||
node->nod_arg[e_prc_procedure] = (jrd_nod*)(IPTR) procedure->getId();
|
||||
|
||||
SSHORT context;
|
||||
const SSHORT stream = par_context(csb, &context);
|
||||
node->nod_arg[e_prc_stream] = (jrd_nod*)(IPTR) stream;
|
||||
node->nod_arg[e_prc_context] = (jrd_nod*)(IPTR) context;
|
||||
|
||||
csb->csb_rpt[stream].csb_procedure = procedure;
|
||||
csb->csb_rpt[stream].csb_alias = alias_string;
|
||||
|
||||
par_procedure_parms(tdbb, csb, procedure, &node->nod_arg[e_prc_in_msg],
|
||||
&node->nod_arg[e_prc_inputs], true);
|
||||
|
||||
if (csb->csb_g_flags & csb_get_dependencies)
|
||||
{
|
||||
par_dependency(tdbb, csb, stream, (SSHORT) -1, "");
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
static void par_procedure_parms(thread_db* tdbb,
|
||||
CompilerScratch* csb,
|
||||
jrd_prc* procedure,
|
||||
jrd_nod** message_ptr,
|
||||
jrd_nod** parameter_ptr, bool input_flag)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* p a r _ p r o c e d u r e _ p a r m s
|
||||
* P A R _ p r o c e d u r e _ p a r m s
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
@ -2138,125 +1931,6 @@ static void par_procedure_parms(thread_db* tdbb,
|
||||
}
|
||||
|
||||
|
||||
static jrd_nod* par_relation(thread_db* tdbb,
|
||||
CompilerScratch* csb, SSHORT blr_operator, bool parse_context)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* p a r _ r e l a t i o n
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Parse a relation reference.
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
|
||||
// Find relation either by id or by name
|
||||
jrd_rel* relation = NULL;
|
||||
Firebird::string* alias_string = NULL;
|
||||
Firebird::MetaName name;
|
||||
|
||||
switch (blr_operator)
|
||||
{
|
||||
case blr_rid:
|
||||
case blr_rid2:
|
||||
{
|
||||
const SSHORT id = csb->csb_blr_reader.getWord();
|
||||
|
||||
if (blr_operator == blr_rid2)
|
||||
{
|
||||
alias_string = FB_NEW(csb->csb_pool) Firebird::string(csb->csb_pool);
|
||||
PAR_name(csb, *alias_string);
|
||||
}
|
||||
|
||||
if (!(relation = MET_lookup_relation_id(tdbb, id, false)))
|
||||
{
|
||||
name.printf("id %d", id);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case blr_relation:
|
||||
case blr_relation2:
|
||||
{
|
||||
PAR_name(csb, name);
|
||||
|
||||
if (blr_operator == blr_relation2)
|
||||
{
|
||||
alias_string = FB_NEW(csb->csb_pool) Firebird::string(csb->csb_pool);
|
||||
PAR_name(csb, *alias_string);
|
||||
}
|
||||
|
||||
relation = MET_lookup_relation(tdbb, name);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fb_assert(false);
|
||||
}
|
||||
|
||||
if (!relation)
|
||||
{
|
||||
PAR_error(csb, Arg::Gds(isc_relnotdef) << Arg::Str(name), false);
|
||||
}
|
||||
|
||||
// Make a relation reference node
|
||||
|
||||
jrd_nod* const node = PAR_make_node(tdbb, e_rel_length);
|
||||
node->nod_count = 0;
|
||||
|
||||
// if an alias was passed, store with the relation
|
||||
|
||||
if (alias_string)
|
||||
{
|
||||
node->nod_arg[e_rel_alias] =
|
||||
(jrd_nod*) stringDup(*tdbb->getDefaultPool(), *alias_string);
|
||||
}
|
||||
|
||||
// Scan the relation if it hasn't already been scanned for meta data
|
||||
|
||||
if ((!(relation->rel_flags & REL_scanned) || (relation->rel_flags & REL_being_scanned)) &&
|
||||
((relation->rel_flags & REL_force_scan) || !(csb->csb_g_flags & csb_internal)))
|
||||
{
|
||||
relation->rel_flags &= ~REL_force_scan;
|
||||
MET_scan_relation(tdbb, relation);
|
||||
}
|
||||
else if (relation->rel_flags & REL_sys_triggers)
|
||||
{
|
||||
MET_parse_sys_trigger(tdbb, relation);
|
||||
}
|
||||
|
||||
// generate a stream for the relation reference, assuming it is a real reference
|
||||
|
||||
if (parse_context)
|
||||
{
|
||||
SSHORT context;
|
||||
const SSHORT stream = par_context(csb, &context);
|
||||
fb_assert(stream <= MAX_STREAMS);
|
||||
node->nod_arg[e_rel_stream] = (jrd_nod*) (IPTR) stream;
|
||||
node->nod_arg[e_rel_context] = (jrd_nod*) (IPTR) context;
|
||||
|
||||
csb->csb_rpt[stream].csb_relation = relation;
|
||||
csb->csb_rpt[stream].csb_alias = alias_string;
|
||||
|
||||
if (csb->csb_g_flags & csb_get_dependencies)
|
||||
{
|
||||
par_dependency(tdbb, csb, stream, (SSHORT) -1, "");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
delete alias_string;
|
||||
}
|
||||
|
||||
node->nod_arg[e_rel_relation] = (jrd_nod*) relation;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
jrd_nod* PAR_rse(thread_db* tdbb, CompilerScratch* csb, SSHORT rse_op)
|
||||
{
|
||||
/**************************************
|
||||
@ -2272,21 +1946,20 @@ jrd_nod* PAR_rse(thread_db* tdbb, CompilerScratch* csb, SSHORT rse_op)
|
||||
SET_TDBB(tdbb);
|
||||
|
||||
SSHORT count = (unsigned int) csb->csb_blr_reader.getByte();
|
||||
RecordSelExpr* rse = (RecordSelExpr*) PAR_make_node(tdbb, count + rse_delta + 2);
|
||||
rse->nod_count = 0;
|
||||
rse->rse_count = count;
|
||||
jrd_nod** ptr = rse->rse_relation;
|
||||
RseNode* rse = FB_NEW(*tdbb->getDefaultPool()) RseNode(*tdbb->getDefaultPool());
|
||||
|
||||
while (--count >= 0)
|
||||
{
|
||||
// AB: Added TYPE_RSE for derived table support
|
||||
*ptr++ = PAR_parse_node(tdbb, csb, RELATION); // TYPE_RSE);
|
||||
//*ptr++ = PAR_parse_node(tdbb, csb, RELATION);
|
||||
jrd_nod* node = PAR_parse_node(tdbb, csb, RELATION); // TYPE_RSE;
|
||||
fb_assert(node->nod_type == nod_class_recsrcnode_jrd);
|
||||
rse->rse_relations.add(reinterpret_cast<RecordSourceNode*>(node->nod_arg[0]));
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
const UCHAR op = csb->csb_blr_reader.getByte();
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case blr_boolean:
|
||||
@ -2308,13 +1981,13 @@ jrd_nod* PAR_rse(thread_db* tdbb, CompilerScratch* csb, SSHORT rse_op)
|
||||
case blr_sort:
|
||||
if (rse_op == blr_rs_stream)
|
||||
PAR_syntax_error(csb, "RecordSelExpr stream clause");
|
||||
rse->rse_sorted = par_sort(tdbb, csb, true, false);
|
||||
rse->rse_sorted = PAR_sort(tdbb, csb, true, false);
|
||||
break;
|
||||
|
||||
case blr_project:
|
||||
if (rse_op == blr_rs_stream)
|
||||
PAR_syntax_error(csb, "RecordSelExpr stream clause");
|
||||
rse->rse_projection = par_sort(tdbb, csb, false, false);
|
||||
rse->rse_projection = PAR_sort(tdbb, csb, false, false);
|
||||
break;
|
||||
|
||||
case blr_join_type:
|
||||
@ -2336,7 +2009,7 @@ jrd_nod* PAR_rse(thread_db* tdbb, CompilerScratch* csb, SSHORT rse_op)
|
||||
break;
|
||||
|
||||
case blr_writelock:
|
||||
rse->nod_flags |= rse_writelock;
|
||||
rse->flags |= RseNode::FLAG_WRITELOCK;
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -2345,22 +2018,29 @@ jrd_nod* PAR_rse(thread_db* tdbb, CompilerScratch* csb, SSHORT rse_op)
|
||||
// An outer join is only allowed when the stream count is 2
|
||||
// and a boolean expression has been supplied
|
||||
|
||||
if (!rse->rse_jointype || (rse->rse_count == 2 && rse->rse_boolean))
|
||||
if (!rse->rse_jointype || (rse->rse_relations.getCount() == 2 && rse->rse_boolean))
|
||||
{
|
||||
// Convert right outer joins to left joins to avoid
|
||||
// RIGHT JOIN handling at lower engine levels
|
||||
if (rse->rse_jointype == blr_right)
|
||||
{
|
||||
// Swap sub-streams
|
||||
jrd_nod* temp = rse->rse_relation[0];
|
||||
rse->rse_relation[0] = rse->rse_relation[1];
|
||||
rse->rse_relation[1] = temp;
|
||||
RecordSourceNode* temp = rse->rse_relations[0];
|
||||
rse->rse_relations[0] = rse->rse_relations[1];
|
||||
rse->rse_relations[1] = temp;
|
||||
|
||||
rse->rse_jointype = blr_left;
|
||||
}
|
||||
return (jrd_nod*) rse;
|
||||
|
||||
jrd_nod* node = PAR_make_node(tdbb, 1);
|
||||
node->nod_type = nod_class_recsrcnode_jrd;
|
||||
node->nod_count = 0;
|
||||
node->nod_arg[0] = reinterpret_cast<jrd_nod*>(rse);
|
||||
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
PAR_syntax_error(csb, (TEXT*)((rse_op == blr_rs_stream) ?
|
||||
"RecordSelExpr stream clause" :
|
||||
"record selection expression clause"));
|
||||
@ -2369,11 +2049,11 @@ jrd_nod* PAR_rse(thread_db* tdbb, CompilerScratch* csb, SSHORT rse_op)
|
||||
}
|
||||
|
||||
|
||||
static jrd_nod* par_sort(thread_db* tdbb, CompilerScratch* csb, bool flag, bool nullForEmpty)
|
||||
jrd_nod* PAR_sort(thread_db* tdbb, CompilerScratch* csb, bool flag, bool nullForEmpty)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* p a r _ s o r t
|
||||
* P A R _ s o r t
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
@ -2419,6 +2099,7 @@ static jrd_nod* par_sort(thread_db* tdbb, CompilerScratch* csb, bool flag, bool
|
||||
|
||||
*ptr2++ = (jrd_nod*) (IPTR) ((code == blr_descending) ? TRUE : FALSE);
|
||||
}
|
||||
|
||||
*ptr++ = PAR_parse_node(tdbb, csb, VALUE);
|
||||
}
|
||||
|
||||
@ -2426,55 +2107,6 @@ static jrd_nod* par_sort(thread_db* tdbb, CompilerScratch* csb, bool flag, bool
|
||||
}
|
||||
|
||||
|
||||
static jrd_nod* par_union(thread_db* tdbb, CompilerScratch* csb, bool recursive)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* p a r _ u n i o n
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Parse a union reference.
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
|
||||
// Make the node, parse the context number, get a stream assigned,
|
||||
// and get the number of sub-RecordSelExpr's.
|
||||
|
||||
jrd_nod* node = PAR_make_node(tdbb, e_uni_length);
|
||||
node->nod_count = 3;
|
||||
const USHORT stream = par_context(csb, 0);
|
||||
node->nod_arg[e_uni_stream] = (jrd_nod*) (IPTR) stream;
|
||||
|
||||
// assign separate context for mapped record if union is recursive
|
||||
USHORT map_stream = stream;
|
||||
if (recursive)
|
||||
{
|
||||
node->nod_flags |= nod_recurse;
|
||||
map_stream = par_context(csb, 0);
|
||||
node->nod_arg[e_uni_map_stream] = (jrd_nod*) (IPTR) map_stream;
|
||||
}
|
||||
|
||||
SSHORT count = (unsigned int) csb->csb_blr_reader.getByte();
|
||||
|
||||
// Pick up the sub-RecordSelExpr's and maps
|
||||
|
||||
NodeStack clauses;
|
||||
|
||||
while (--count >= 0)
|
||||
{
|
||||
clauses.push(PAR_parse_node(tdbb, csb, TYPE_RSE));
|
||||
clauses.push(par_map(tdbb, csb, map_stream));
|
||||
}
|
||||
|
||||
node->nod_arg[e_uni_clauses] = PAR_make_list(tdbb, clauses);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
jrd_nod* PAR_parse_node(thread_db* tdbb, CompilerScratch* csb, USHORT expected)
|
||||
{
|
||||
/**************************************
|
||||
@ -2856,8 +2488,7 @@ jrd_nod* PAR_parse_node(thread_db* tdbb, CompilerScratch* csb, USHORT expected)
|
||||
case blr_procedure2:
|
||||
case blr_procedure3:
|
||||
case blr_procedure4:
|
||||
node = par_procedure(tdbb, csb, blr_operator);
|
||||
set_type = false;
|
||||
node->nod_arg[0] = (jrd_nod*) ProcedureSourceNode::parse(tdbb, csb, blr_operator);
|
||||
break;
|
||||
|
||||
case blr_index:
|
||||
@ -2909,56 +2540,38 @@ jrd_nod* PAR_parse_node(thread_db* tdbb, CompilerScratch* csb, USHORT expected)
|
||||
|
||||
case blr_singular:
|
||||
node = PAR_parse_node(tdbb, csb, TYPE_RSE);
|
||||
((RecordSelExpr*) node)->nod_flags |= rse_singular;
|
||||
fb_assert(node->nod_type == nod_class_recsrcnode_jrd);
|
||||
reinterpret_cast<RseNode*>(node->nod_arg[0])->flags |= RseNode::FLAG_SINGULAR;
|
||||
break;
|
||||
|
||||
case blr_scrollable:
|
||||
node = PAR_parse_node(tdbb, csb, TYPE_RSE);
|
||||
((RecordSelExpr*) node)->nod_flags |= rse_scrollable;
|
||||
fb_assert(node->nod_type == nod_class_recsrcnode_jrd);
|
||||
reinterpret_cast<RseNode*>(node->nod_arg[0])->flags |= RseNode::FLAG_SCROLLABLE;
|
||||
break;
|
||||
|
||||
case blr_relation:
|
||||
case blr_rid:
|
||||
case blr_relation2:
|
||||
case blr_rid2:
|
||||
node = par_relation(tdbb, csb, blr_operator, true);
|
||||
node->nod_arg[0] = (jrd_nod*) RelationSourceNode::parse(tdbb, csb, blr_operator, true);
|
||||
break;
|
||||
|
||||
case blr_union:
|
||||
node = par_union(tdbb, csb, false);
|
||||
break;
|
||||
|
||||
case blr_recurse:
|
||||
node = par_union(tdbb, csb, true);
|
||||
node->nod_arg[0] = (jrd_nod*) UnionSourceNode::parse(tdbb, csb, blr_operator);
|
||||
break;
|
||||
|
||||
case blr_window:
|
||||
{
|
||||
node->nod_arg[e_win_rse] = PAR_parse_node(tdbb, csb, TYPE_RSE);
|
||||
|
||||
unsigned partitionCount = csb->csb_blr_reader.getByte();
|
||||
NodeStack stack;
|
||||
|
||||
for (unsigned i = 0; i < partitionCount; ++i)
|
||||
stack.push(par_partition_by(tdbb, csb));
|
||||
|
||||
node->nod_arg[e_win_windows] = PAR_make_list(tdbb, stack);
|
||||
}
|
||||
node->nod_arg[0] = (jrd_nod*) WindowSourceNode::parse(tdbb, csb);
|
||||
break;
|
||||
|
||||
case blr_aggregate:
|
||||
{
|
||||
const USHORT stream = par_context(csb, NULL);
|
||||
fb_assert(stream <= MAX_STREAMS);
|
||||
node->nod_arg[e_agg_stream] = (jrd_nod*) (IPTR) stream;
|
||||
node->nod_arg[e_agg_rse] = PAR_parse_node(tdbb, csb, TYPE_RSE);
|
||||
node->nod_arg[e_agg_group] = PAR_parse_node(tdbb, csb, OTHER);
|
||||
node->nod_arg[e_agg_map] = par_map(tdbb, csb, stream);
|
||||
}
|
||||
node->nod_arg[0] = (jrd_nod*) AggregateSourceNode::parse(tdbb, csb);
|
||||
break;
|
||||
|
||||
case blr_group_by:
|
||||
node = par_sort(tdbb, csb, false, false);
|
||||
node = PAR_sort(tdbb, csb, false, false);
|
||||
return node->nod_count ? node : NULL;
|
||||
|
||||
case blr_field:
|
||||
|
@ -52,6 +52,9 @@ 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);
|
||||
SSHORT PAR_context(Jrd::CompilerScratch*, SSHORT*);
|
||||
void PAR_dependency(Jrd::thread_db*, Jrd::CompilerScratch*, SSHORT, SSHORT,
|
||||
const Firebird::MetaName&);
|
||||
USHORT PAR_desc(Jrd::thread_db*, Jrd::CompilerScratch*, dsc*, Jrd::ItemInfo* = NULL);
|
||||
void PAR_error(Jrd::CompilerScratch*, const Firebird::Arg::StatusVector&, bool isSyntaxError = true);
|
||||
Jrd::jrd_nod* PAR_gen_field(Jrd::thread_db*, USHORT, USHORT);
|
||||
@ -63,7 +66,10 @@ size_t PAR_name(Jrd::CompilerScratch* csb, Firebird::string& name);
|
||||
Jrd::CompilerScratch* PAR_parse(Jrd::thread_db*, const UCHAR* blr, ULONG blr_length,
|
||||
bool internal_flag, USHORT = 0, const UCHAR* = NULL);
|
||||
|
||||
void PAR_procedure_parms(Jrd::thread_db*, Jrd::CompilerScratch*, Jrd::jrd_prc*,
|
||||
Jrd::jrd_nod**, Jrd::jrd_nod**, bool);
|
||||
Jrd::jrd_nod* PAR_rse(Jrd::thread_db*, Jrd::CompilerScratch*, SSHORT);
|
||||
Jrd::jrd_nod* PAR_sort(Jrd::thread_db*, Jrd::CompilerScratch*, bool, bool);
|
||||
SLONG PAR_symbol_to_gdscode(const Firebird::string&);
|
||||
|
||||
typedef Jrd::DmlNode* (*NodeParseFunc)(Jrd::thread_db* tdbb, MemoryPool& pool,
|
||||
|
@ -47,8 +47,6 @@ namespace Jrd
|
||||
class BaseBufferedStream;
|
||||
class BufferedStream;
|
||||
|
||||
typedef Firebird::HalfStaticArray<UCHAR, OPT_STATIC_ITEMS> StreamsArray;
|
||||
|
||||
// Abstract base class
|
||||
|
||||
class RecordSource
|
||||
@ -900,7 +898,7 @@ namespace Jrd
|
||||
|
||||
public:
|
||||
Union(CompilerScratch* csb, UCHAR stream,
|
||||
size_t argCount, RecordSource* const* args, jrd_nod* const* maps,
|
||||
size_t argCount, RecordSource* const* args, NestConst<jrd_nod>* maps,
|
||||
size_t streamCount, const UCHAR* streams);
|
||||
|
||||
void open(thread_db* tdbb) const;
|
||||
|
@ -35,7 +35,7 @@ using namespace Jrd;
|
||||
// --------------------------
|
||||
|
||||
Union::Union(CompilerScratch* csb, UCHAR stream,
|
||||
size_t argCount, RecordSource* const* args, jrd_nod* const* maps,
|
||||
size_t argCount, RecordSource* const* args, NestConst<jrd_nod>* maps,
|
||||
size_t streamCount, const UCHAR* streams)
|
||||
: RecordStream(csb, stream), m_args(csb->csb_pool), m_maps(csb->csb_pool),
|
||||
m_streams(csb->csb_pool)
|
||||
|
@ -163,25 +163,29 @@ static const VERB verbs[] =
|
||||
PAIR(nod_and, blr_and, 2, 2, TYPE_BOOL, TYPE_BOOL),
|
||||
PAIR(nod_or, blr_or, 2, 2, TYPE_BOOL, TYPE_BOOL),
|
||||
PAIR(nod_not, blr_not, 1, 1, TYPE_BOOL, TYPE_BOOL),
|
||||
PAIR(nod_rse, blr_rse, 0, 0, TYPE_RSE, OTHER),
|
||||
PAIR(nod_class_recsrcnode_jrd, blr_rse, 0, 0, TYPE_RSE, OTHER),
|
||||
|
||||
PAIR(nod_map, blr_map, 0, 0, OTHER, OTHER),
|
||||
PAIR(nod_union, blr_union, 0, 0, RELATION, OTHER),
|
||||
PAIR(nod_union, blr_recurse, 0, 0, RELATION, OTHER),
|
||||
PAIR(nod_aggregate, blr_aggregate, e_agg_length, 0, RELATION, OTHER),
|
||||
PAIR(nod_relation, blr_relation, 0, 0, RELATION, OTHER),
|
||||
PAIR(nod_relation, blr_rid, 0, 0, RELATION, OTHER),
|
||||
PAIR(nod_rse, blr_rs_stream, 0, 0, RELATION, OTHER),
|
||||
PAIR(nod_class_recsrcnode_jrd, blr_union, 1, 0, RELATION, OTHER),
|
||||
PAIR(nod_class_recsrcnode_jrd, blr_recurse, 1, 0, RELATION, OTHER),
|
||||
PAIR(nod_class_recsrcnode_jrd, blr_aggregate, 1, 0, RELATION, OTHER),
|
||||
PAIR(nod_class_recsrcnode_jrd, blr_relation, 1, 0, RELATION, OTHER),
|
||||
PAIR(nod_class_recsrcnode_jrd, blr_rid, 1, 0, RELATION, OTHER),
|
||||
PAIR(nod_class_recsrcnode_jrd, blr_rs_stream, 0, 0, RELATION, OTHER),
|
||||
PAIR(nod_exec_proc, blr_exec_proc, e_esp_length, 4, STATEMENT, OTHER),
|
||||
PAIR(nod_procedure, blr_procedure, e_prc_length, 2, RELATION, OTHER),
|
||||
PAIR(nod_procedure, blr_pid, e_prc_length, 2, RELATION, OTHER),
|
||||
PAIR(nod_class_recsrcnode_jrd, blr_procedure, 1, 0, RELATION, OTHER),
|
||||
PAIR(nod_class_recsrcnode_jrd, blr_procedure2, 1, 0, RELATION, OTHER),
|
||||
PAIR(nod_class_recsrcnode_jrd, blr_procedure3, 1, 0, RELATION, OTHER),
|
||||
PAIR(nod_class_recsrcnode_jrd, blr_procedure4, 1, 0, RELATION, OTHER),
|
||||
PAIR(nod_class_recsrcnode_jrd, blr_pid, 1, 0, RELATION, OTHER),
|
||||
PAIR(nod_class_recsrcnode_jrd, blr_pid2, 1, 0, RELATION, OTHER),
|
||||
PAIR(nod_exec_proc, blr_exec_pid, e_esp_length, 4, STATEMENT, OTHER),
|
||||
PAIR(nod_block, blr_block, e_blk_length, e_blk_length, STATEMENT, STATEMENT),
|
||||
PAIR(nod_error_handler, blr_error_handler, e_err_length, 1, STATEMENT, OTHER),
|
||||
PAIR(nod_class_stmtnode_jrd, blr_abort, 1, 0, STATEMENT, OTHER),
|
||||
PAIR(nod_cast, blr_cast, e_cast_length, 1, VALUE, VALUE),
|
||||
PAIR(nod_rse, blr_singular, 0, 0, TYPE_RSE, OTHER),
|
||||
PAIR(nod_rse, blr_scrollable, 0, 0, TYPE_RSE, OTHER),
|
||||
PAIR(nod_class_recsrcnode_jrd, blr_singular, 0, 0, TYPE_RSE, OTHER),
|
||||
PAIR(nod_class_recsrcnode_jrd, blr_scrollable, 0, 0, TYPE_RSE, OTHER),
|
||||
PAIR(nod_start_savepoint, blr_start_savepoint, 1, 0, STATEMENT, OTHER),
|
||||
PAIR(nod_end_savepoint, blr_end_savepoint, 1, 0, STATEMENT, OTHER),
|
||||
|
||||
@ -193,8 +197,8 @@ static const VERB verbs[] =
|
||||
PAIR(nod_indices, blr_indices, 1, 0, ACCESS_TYPE, VALUE),
|
||||
PAIR(nod_retrieve, blr_retrieve, 2, 0, ACCESS_TYPE, VALUE),
|
||||
|
||||
PAIR(nod_relation, blr_relation2, 0, 0, RELATION, OTHER),
|
||||
PAIR(nod_relation, blr_rid2, 0, 0, RELATION, OTHER),
|
||||
PAIR(nod_class_recsrcnode_jrd, blr_relation2, 1, 0, RELATION, OTHER),
|
||||
PAIR(nod_class_recsrcnode_jrd, blr_rid2, 1, 0, RELATION, OTHER),
|
||||
PAIR2(nod_set_generator, blr_set_generator, e_gen_length, 1, STATEMENT, VALUE),
|
||||
PAIR(nod_ansi_any, blr_ansi_any, e_any_length, 1, TYPE_BOOL, TYPE_RSE),
|
||||
PAIR(nod_exists, blr_exists, e_any_length, 1, TYPE_BOOL, TYPE_RSE),
|
||||
@ -222,7 +226,7 @@ static const VERB verbs[] =
|
||||
PAIR(nod_similar, blr_similar, 3, 3, TYPE_BOOL, VALUE),
|
||||
PAIR(nod_stmt_expr, blr_stmt_expr, e_stmt_expr_length, 2, VALUE, OTHER),
|
||||
PAIR(nod_derived_expr, blr_derived_expr, e_derived_expr_length, e_derived_expr_count, VALUE, VALUE),
|
||||
PAIR(nod_window, blr_window, e_agg_length, 0, RELATION, OTHER),
|
||||
PAIR(nod_class_recsrcnode_jrd, blr_window, 1, 0, RELATION, OTHER),
|
||||
PAIR(nod_continue_loop, blr_continue_loop, 1, 0, STATEMENT, OTHER),
|
||||
PAIR(nod_class_exprnode_jrd, blr_agg_function, 1, 0, VALUE, VALUE),
|
||||
PAIR(nod_class_exprnode_jrd, blr_substring_similar, 1, 0, VALUE, VALUE),
|
||||
|
Loading…
Reference in New Issue
Block a user