|
From: <asf...@us...> - 2010-08-24 04:10:38
|
Revision: 51464
http://firebird.svn.sourceforge.net/firebird/?rev=51464&view=rev
Author: asfernandes
Date: 2010-08-24 03:25:01 +0000 (Tue, 24 Aug 2010)
Log Message:
-----------
Refactor nod_rse, nod_relation, nod_procedure, nod_union, nod_aggregate and nod_window.
Modified Paths:
--------------
firebird/trunk/builds/posix/make.shared.variables
firebird/trunk/builds/win32/msvc10/engine.vcxproj
firebird/trunk/builds/win32/msvc10/engine.vcxproj.filters
firebird/trunk/builds/win32/msvc10/engine_classic.vcxproj
firebird/trunk/builds/win32/msvc10/engine_classic.vcxproj.filters
firebird/trunk/builds/win32/msvc10/engine_embed.vcxproj
firebird/trunk/builds/win32/msvc10/engine_embed.vcxproj.filters
firebird/trunk/builds/win32/msvc9/engine.vcproj
firebird/trunk/builds/win32/msvc9/engine_classic.vcproj
firebird/trunk/builds/win32/msvc9/engine_embed.vcproj
firebird/trunk/src/dsql/ExprNodes.cpp
firebird/trunk/src/dsql/Nodes.h
firebird/trunk/src/dsql/StmtNodes.cpp
firebird/trunk/src/dsql/StmtNodes.h
firebird/trunk/src/dsql/Visitors.h
firebird/trunk/src/jrd/Attachment.h
firebird/trunk/src/jrd/Optimizer.cpp
firebird/trunk/src/jrd/Optimizer.h
firebird/trunk/src/jrd/Relation.h
firebird/trunk/src/jrd/cmp.cpp
firebird/trunk/src/jrd/cmp_proto.h
firebird/trunk/src/jrd/exe.cpp
firebird/trunk/src/jrd/exe.h
firebird/trunk/src/jrd/jrd.h
firebird/trunk/src/jrd/lls.h
firebird/trunk/src/jrd/met.epp
firebird/trunk/src/jrd/nod.h
firebird/trunk/src/jrd/opt.cpp
firebird/trunk/src/jrd/opt_proto.h
firebird/trunk/src/jrd/par.cpp
firebird/trunk/src/jrd/par_proto.h
firebird/trunk/src/jrd/recsrc/RecordSource.h
firebird/trunk/src/jrd/recsrc/Union.cpp
firebird/trunk/src/misc/blrtable.cpp
Added Paths:
-----------
firebird/trunk/src/jrd/RecordSourceNodes.cpp
firebird/trunk/src/jrd/RecordSourceNodes.h
Modified: firebird/trunk/builds/posix/make.shared.variables
===================================================================
--- firebird/trunk/builds/posix/make.shared.variables 2010-08-24 03:15:58 UTC (rev 51463)
+++ firebird/trunk/builds/posix/make.shared.variables 2010-08-24 03:25:01 UTC (rev 51464)
@@ -42,7 +42,7 @@
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 \
Modified: firebird/trunk/builds/win32/msvc10/engine.vcxproj
===================================================================
--- firebird/trunk/builds/win32/msvc10/engine.vcxproj 2010-08-24 03:15:58 UTC (rev 51463)
+++ firebird/trunk/builds/win32/msvc10/engine.vcxproj 2010-08-24 03:25:01 UTC (rev 51464)
@@ -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" />
Modified: firebird/trunk/builds/win32/msvc10/engine.vcxproj.filters
===================================================================
--- firebird/trunk/builds/win32/msvc10/engine.vcxproj.filters 2010-08-24 03:15:58 UTC (rev 51463)
+++ firebird/trunk/builds/win32/msvc10/engine.vcxproj.filters 2010-08-24 03:25:01 UTC (rev 51464)
@@ -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>
Modified: firebird/trunk/builds/win32/msvc10/engine_classic.vcxproj
===================================================================
--- firebird/trunk/builds/win32/msvc10/engine_classic.vcxproj 2010-08-24 03:15:58 UTC (rev 51463)
+++ firebird/trunk/builds/win32/msvc10/engine_classic.vcxproj 2010-08-24 03:25:01 UTC (rev 51464)
@@ -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" />
Modified: firebird/trunk/builds/win32/msvc10/engine_classic.vcxproj.filters
===================================================================
--- firebird/trunk/builds/win32/msvc10/engine_classic.vcxproj.filters 2010-08-24 03:15:58 UTC (rev 51463)
+++ firebird/trunk/builds/win32/msvc10/engine_classic.vcxproj.filters 2010-08-24 03:25:01 UTC (rev 51464)
@@ -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>
Modified: firebird/trunk/builds/win32/msvc10/engine_embed.vcxproj
===================================================================
--- firebird/trunk/builds/win32/msvc10/engine_embed.vcxproj 2010-08-24 03:15:58 UTC (rev 51463)
+++ firebird/trunk/builds/win32/msvc10/engine_embed.vcxproj 2010-08-24 03:25:01 UTC (rev 51464)
@@ -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" />
Modified: firebird/trunk/builds/win32/msvc10/engine_embed.vcxproj.filters
===================================================================
--- firebird/trunk/builds/win32/msvc10/engine_embed.vcxproj.filters 2010-08-24 03:15:58 UTC (rev 51463)
+++ firebird/trunk/builds/win32/msvc10/engine_embed.vcxproj.filters 2010-08-24 03:25:01 UTC (rev 51464)
@@ -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>
Modified: firebird/trunk/builds/win32/msvc9/engine.vcproj
===================================================================
--- firebird/trunk/builds/win32/msvc9/engine.vcproj 2010-08-24 03:15:58 UTC (rev 51463)
+++ firebird/trunk/builds/win32/msvc9/engine.vcproj 2010-08-24 03:25:01 UTC (rev 51464)
@@ -572,6 +572,10 @@
>
</File>
<File
+ RelativePath="..\..\..\src\jrd\RecordSourceNodes.cpp"
+ >
+ </File>
+ <File
RelativePath="..\..\..\src\jrd\Relation.cpp"
>
</File>
@@ -1392,6 +1396,10 @@
>
</File>
<File
+ RelativePath="..\..\..\src\jrd\RecordSourceNodes.h"
+ >
+ </File>
+ <File
RelativePath="..\..\..\src\jrd\recsrc\RecordSource.h"
>
</File>
Modified: firebird/trunk/builds/win32/msvc9/engine_classic.vcproj
===================================================================
--- firebird/trunk/builds/win32/msvc9/engine_classic.vcproj 2010-08-24 03:15:58 UTC (rev 51463)
+++ firebird/trunk/builds/win32/msvc9/engine_classic.vcproj 2010-08-24 03:25:01 UTC (rev 51464)
@@ -572,6 +572,10 @@
>
</File>
<File
+ RelativePath="..\..\..\src\jrd\RecordSourceNodes.cpp"
+ >
+ </File>
+ <File
RelativePath="..\..\..\src\jrd\Relation.cpp"
>
</File>
@@ -1392,6 +1396,10 @@
>
</File>
<File
+ RelativePath="..\..\..\src\jrd\RecordSourceNodes.h"
+ >
+ </File>
+ <File
RelativePath="..\..\..\src\jrd\recsrc\RecordSource.h"
>
</File>
Modified: firebird/trunk/builds/win32/msvc9/engine_embed.vcproj
===================================================================
--- firebird/trunk/builds/win32/msvc9/engine_embed.vcproj 2010-08-24 03:15:58 UTC (rev 51463)
+++ firebird/trunk/builds/win32/msvc9/engine_embed.vcproj 2010-08-24 03:25:01 UTC (rev 51464)
@@ -572,6 +572,10 @@
>
</File>
<File
+ RelativePath="..\..\..\src\jrd\RecordSourceNodes.cpp"
+ >
+ </File>
+ <File
RelativePath="..\..\..\src\jrd\Relation.cpp"
>
</File>
@@ -1392,6 +1396,10 @@
>
</File>
<File
+ RelativePath="..\..\..\src\jrd\RecordSourceNodes.h"
+ >
+ </File>
+ <File
RelativePath="..\..\..\src\jrd\recsrc\RecordSource.h"
>
</File>
Modified: firebird/trunk/src/dsql/ExprNodes.cpp
===================================================================
--- firebird/trunk/src/dsql/ExprNodes.cpp 2010-08-24 03:15:58 UTC (rev 51463)
+++ firebird/trunk/src/dsql/ExprNodes.cpp 2010-08-24 03:25:01 UTC (rev 51464)
@@ -709,7 +709,7 @@
// 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 @@
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;
}
Modified: firebird/trunk/src/dsql/Nodes.h
===================================================================
--- firebird/trunk/src/dsql/Nodes.h 2010-08-24 03:15:58 UTC (rev 51463)
+++ firebird/trunk/src/dsql/Nodes.h 2010-08-24 03:25:01 UTC (rev 51464)
@@ -38,7 +38,7 @@
class dsql_nod;
class ExprNode;
class jrd_nod;
-class RecordSelExpr;
+class RseNode;
class SlidingWindow;
class TypeClause;
@@ -550,7 +550,7 @@
}
public:
- virtual void pass2Cursor(RecordSelExpr*& /*rsePtr*/, Cursor**& /*cursorPtr*/)
+ virtual void pass2Cursor(RseNode*& /*rsePtr*/, Cursor**& /*cursorPtr*/)
{
}
Modified: firebird/trunk/src/dsql/StmtNodes.cpp
===================================================================
--- firebird/trunk/src/dsql/StmtNodes.cpp 2010-08-24 03:15:58 UTC (rev 51463)
+++ firebird/trunk/src/dsql/StmtNodes.cpp 2010-08-24 03:25:01 UTC (rev 51464)
@@ -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 @@
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 @@
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::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;
}
Modified: firebird/trunk/src/dsql/StmtNodes.h
===================================================================
--- firebird/trunk/src/dsql/StmtNodes.h 2010-08-24 03:15:58 UTC (rev 51463)
+++ firebird/trunk/src/dsql/StmtNodes.h 2010-08-24 03:25:01 UTC (rev 51464)
@@ -220,9 +220,9 @@
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 @@
dsql_nod* dsqlLabel;
bool dsqlForceSingular;
NestConst<jrd_nod> stall;
- NestConst<jrd_nod> rse;
+ NestConst<RseNode> rse;
NestConst<jrd_nod> statement;
NestConst<Cursor> cursor;
};
Modified: firebird/trunk/src/dsql/Visitors.h
===================================================================
--- firebird/trunk/src/dsql/Visitors.h 2010-08-24 03:15:58 UTC (rev 51463)
+++ firebird/trunk/src/dsql/Visitors.h 2010-08-24 03:25:01 UTC (rev 51464)
@@ -427,7 +427,7 @@
virtual USHORT getFieldId(jrd_nod* input);
-protected:
+public:
CompilerScratch* csb;
UCHAR* remap;
jrd_nod* message;
Modified: firebird/trunk/src/jrd/Attachment.h
===================================================================
--- firebird/trunk/src/jrd/Attachment.h 2010-08-24 03:15:58 UTC (rev 51463)
+++ firebird/trunk/src/jrd/Attachment.h 2010-08-24 03:25:01 UTC (rev 51464)
@@ -65,7 +65,6 @@
class IndexLock;
class ArrayField;
struct sort_context;
- class RecordSelExpr;
class vcl;
class TextType;
class Parameter;
Modified: firebird/trunk/src/jrd/Optimizer.cpp
===================================================================
--- firebird/trunk/src/jrd/Optimizer.cpp 2010-08-24 03:15:58 UTC (rev 51463)
+++ firebird/trunk/src/jrd/Optimizer.cpp 2010-08-24 03:25:01 UTC (rev 51464)
@@ -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,44 +90,17 @@
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_class_recsrcnode_jrd:
+ return reinterpret_cast<RecordSourceNode*>(node->nod_arg[0])->computable(
+ csb, stream, idx_use, allowOnlyCurrentStream, NULL);
- 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_exprnode_jrd:
{
ExprNode* exprNode = reinterpret_cast<ExprNode*>(node->nod_arg[0]);
@@ -146,17 +120,13 @@
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 @@
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 @@
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);
- }
- }
- // 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;
- }
+ 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]);
- 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;
+ return rse->computable(csb, stream, idx_use, allowOnlyCurrentStream,
+ node->nod_arg[e_stat_value]);
}
}
- // 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 @@
return OPT_make_binary_node(node_type, node1, node2, false);
}
+
void OptimizerRetrieval::findDependentFromStreams(jrd_nod* node, SortedStreamList* streamList) const
{
/**************************************
@@ -1081,30 +958,8 @@
// Recurse thru interesting sub-nodes
- if (node->nod_type == nod_procedure)
+ if (node->nod_type == nod_class_exprnode_jrd)
{
- 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)
- {
ExprNode* exprNode = reinterpret_cast<ExprNode*>(node->nod_arg[0]);
for (NestConst<NestConst<jrd_nod> >* i = exprNode->jrdChildNodes.begin();
@@ -1113,19 +968,19 @@
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;
-
switch (node->nod_type)
{
case nod_field:
@@ -1136,9 +991,8 @@
(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 @@
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];
- break;
- case nod_rse:
- rse = (RecordSelExpr*) node;
- value = NULL;
- break;
+ 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]);
- case nod_aggregate:
- rse = (RecordSelExpr*) node->nod_arg[e_agg_rse];
- rse->rse_sorted = node->nod_arg[e_agg_group];
- value = NULL;
- break;
+ rse->findDependentFromStreams(this, streamList);
- case nod_window:
- rse = (RecordSelExpr*) node->nod_arg[e_win_rse];
- value = NULL;
- break;
+ jrd_nod* value = node->nod_arg[e_stat_value];
- default:
- return;
- }
+ // Check value expression, if any
+ if (value)
+ findDependentFromStreams(value, streamList);
- // Node is a record selection expression.
- if (sub = rse->rse_first) {
- findDependentFromStreams(sub, streamList);
+ break;
+ }
}
-
- 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()
Modified: firebird/trunk/src/jrd/Optimizer.h
===================================================================
--- firebird/trunk/src/jrd/Optimizer.h 2010-08-24 03:15:58 UTC (rev 51463)
+++ firebird/trunk/src/jrd/Optimizer.h 2010-08-24 03:25:01 UTC (rev 51464)
@@ -80,24 +80,6 @@
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 @@
Firebird::Array<IndexScratchSegment*> segments;
};
-typedef Firebird::SortedArray<int> SortedStreamList;
-
class InversionCandidate
{
public:
@@ -182,9 +162,10 @@
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();
Added: firebird/trunk/src/jrd/RecordSourceNodes.cpp
===================================================================
--- firebird/trunk/src/jrd/RecordSourceNodes.cpp (rev 0)
+++ firebird/trunk/src/jrd/RecordSourceNodes.cpp 2010-08-24 03:25:01 UTC (rev 51464)
@@ -0,0 +1,2444 @@
+/*
+ * 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 "firebird.h"
+#include "../jrd/common.h"
+#include "../jrd/align.h"
+#include "../jrd/RecordSourceNodes.h"
+#include "../jrd/DataTypeUtil.h"
+#include "../jrd/Optimizer.h"
+#include "../jrd/recsrc/RecordSource.h"
+#include "../jrd/btr_proto.h"
+#include "../jrd/cmp_proto.h"
+#include "../jrd/dbg_proto.h"
+#include "../jrd/dsc_proto.h"
+#include "../jrd/met_proto.h"
+#include "../jrd/opt_proto.h"
+#include "../jrd/par_proto.h"
+
+using namespace Firebird;
+using namespace Jrd;
+
+
+static jrd_nod* 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);
+static void processMap(thread_db* tdbb, CompilerScratch* csb, jrd_nod* map, Format** input_format);
+static void genDeliverUnmapped(thread_db* tdbb, NodeStack* deliverStack, jrd_nod* map,
+ NodeStack* parentStack, UCHAR shellStream);
+static void markIndices(CompilerScratch::csb_repeat* csb_tail, SSHORT relation_id);
+static void sortIndicesBySelectivity(CompilerScratch::csb_repeat* csb_tail);
+
+
+//--------------------
+
+
+// Parse a relation reference.
+RelationSourceNode* RelationSourceNode::parse(thread_db* tdbb, CompilerScratch* csb,
+ SSHORT blrOp, bool parseContext)
+{
+ SET_TDBB(tdbb);
+
+ // Make a relation reference node
+
+ RelationSourceNode* node = FB_NEW(*tdbb->getDefaultPool()) RelationSourceNode(
+ *tdbb->getDefaultPool());
+
+ // Find relation either by id or by name
+ string* alias_string = NULL;
+ MetaName name;
+
+ switch (blrOp)
+ {
+ case blr_rid:
+ case blr_rid2:
+ {
+ const SSHORT id = csb->csb_blr_reader.getWord();
+
+ if (blrOp == blr_rid2)
+ {
+ alias_string = FB_NEW(csb->csb_pool) string(csb->csb_pool);
+ PAR_name(csb, *alias_string);
+ }
+
+ if (!(node->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 (blrOp == blr_relation2)
+ {
+ alias_string = FB_NEW(csb->csb_pool) string(csb->csb_pool);
+ PAR_name(csb, *alias_string);
+ }
+
+ node->relation = MET_lookup_relation(tdbb, name);
+ break;
+ }
+
+ default:
+ fb_assert(false);
+ }
+
+ if (!node->relation)
+ PAR_error(csb, Arg::Gds(isc_relnotdef) << Arg::Str(name), false);
+
+ // if an alias was passed, store with the relation
+
+ if (alias_string)
+ node->alias = stringDup(*tdbb->getDefaultPool(), *alias_string);
+
+ // Scan the relation if it hasn't already been scanned for meta data
+
+ if ((!(node->relation->rel_flags & REL_scanned) || (node->relation->rel_flags & REL_being_scanned)) &&
+ ((node->relation->rel_flags & REL_force_scan) || !(csb->csb_g_flags & csb_internal)))
+ {
+ node->relation->rel_flags &= ~REL_force_scan;
+ MET_scan_relation(tdbb, node->relation);
+ }
+ else if (node->relation->rel_flags & REL_sys_triggers)
+ MET_parse_sys_trigger(tdbb, node->relation);
+
+ // generate a stream for the relation reference, assuming it is a real reference
+
+ if (parseContext)
+ {
+ node->stream = PAR_context(csb, &node->context);
+ fb_assert(node->stream <= MAX_STREAMS);
+
+ csb->csb_rpt[node->stream].csb_relation = node->relation;
+ csb->csb_rpt[node->stream].csb_alias = alias_string;
+
+ if (csb->csb_g_flags & csb_get_dependencies)
+ PAR_dependency(tdbb, csb, node->stream, (SSHORT) -1, "");
+ }
+ else
+ delete alias_string;
+
+ return node;
+}
+
+RelationSourceNode* RelationSourceNode::copy(thread_db* tdbb, NodeCopier& copier)
+{
+ if (!copier.remap)
+ BUGCHECK(221); // msg 221 (CMP) copy: cannot remap
+
+ RelationSourceNode* newSource = FB_NEW(*tdbb->getDefaultPool()) RelationSourceNode(
+ *tdbb->getDefaultPool());
+
+ // Last entry in the remap contains the the original stream number.
+ // Get that stream number so that the flags can be copied
+ // into the newly created child stream.
+
+ const int relative_stream = stream ? copier.remap[stream - 1] : stream;
+ newSource->stream = copier.csb->nextStream();
+ copier.remap[stream] = (UCHAR) newSource->stream;
+
+ newSource->context = context;
+ newSource->relation = relation;
+ newSource->view = view;
+
+ CompilerScratch::csb_repeat* element = CMP_csb_element(copier.csb, newSource->stream);
+ element->csb_relation = (jrd_rel*) newSource->relation;
+ element->csb_view = newSource->view;
+ element->csb_view_stream = copier.remap[0];
+
+ /** If there was a parent stream no., then copy the flags
+ from that stream to its children streams. (Bug 10164/10166)
+ For e.g.
+ consider a view V1 with 2 streams
+ stream #1 from table T1
+ stream #2 from table T2
+ consider a procedure P1 with 2 streams
+ stream #1 from table X
+ stream #2 from view V1
+
+ During pass1 of procedure request, the engine tries to expand
+ all the views into their base tables. It creates a compilier
+ scratch block which initially looks like this
+ stream 1 -------- X
+ stream 2 -------- V1
+ while expanding V1 the engine calls copy() with nod_relation.
+ A new stream 3 is created. Now the CompilerScratch looks like
+ stream 1 -------- X
+ stream 2 -------- V1 map [2,3]
+ stream 3 -------- T1
+ After T1 stream has been created the flags are copied from
+ stream #1 because V1's definition said the original stream
+ number for T1 was 1. However since its being merged with
+ the procedure request, stream #1 belongs to a different table.
+ The flags should be copied from stream 2 i.e. V1. We can get
+ this info from variable remap.
+
+ Since we didn't do this properly before, V1's children got
+ tagged with whatever flags X possesed leading to various
+ errors.
+
+ We now store the proper stream no in relative_stream and
+ later use it to copy the flags. -Sudesh (03/05/99)
+ **/
+
+ copier.csb->csb_rpt[newSource->stream].csb_flags |=
+ copier.csb->csb_rpt[relative_stream].csb_flags & csb_no_dbkey;
+
+ return newSource;
+}
+
+void RelationSourceNode::ignoreDbKey(thread_db* tdbb, CompilerScratch* csb, const jrd_rel* view) const
+{
+ csb->csb_rpt[stream].csb_flags |= csb_no_dbkey;
+ const CompilerScratch::csb_repeat* tail = &csb->csb_rpt[stream];
+ const jrd_rel* relation = tail->csb_relation;
+
+ if (relation)
+ {
+ CMP_post_access(tdbb, csb, relation->rel_security_name,
+ (tail->csb_view) ? tail->csb_view->rel_id : (view ? view->rel_id : 0),
+ SCL_read, SCL_object_table, relation->rel_name);
+ }
+}
+
+void RelationSourceNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, RseNode* rse,
+ jrd_nod** boolean, RecordSourceNodeStack& stack)
+{
+ stack.push(this); // Assume that the source will be used. Push it on the final stream stack.
+
+ // We have a view or a base table;
+ // prepare to check protection of relation when a field in the stream of the
+ // relation is accessed.
+
+ jrd_rel* const parent_view = csb->csb_view;
+ const USHORT view_stream = csb->csb_view_stream;
+
+ jrd_rel* relationView = relation;
+ CMP_post_resource(&csb->csb_resources, relationView, Resource::rsc_relation, relationView->rel_id);
+ view = parent_view;
+
+ CompilerScratch::csb_repeat* const element = CMP_csb_element(csb, stream);
+ element->csb_view = parent_view;
+ fb_assert(view_stream <= MAX_STREAMS);
+ element->csb_view_stream = (UCHAR) view_stream;
+
+ // in the case where there is a parent view, find the context name
+
+ if (parent_view)
+ {
+ const ViewContexts& ctx = parent_view->rel_view_contexts;
+ const USHORT key = context;
+ size_t pos;
+
+ if (ctx.find(key, pos))
+ {
+ element->csb_alias = FB_NEW(csb->csb_pool)
+ string(csb->csb_pool, ctx[pos]->vcx_context_name);
+ }
+ }
+
+ // check for a view - if not, nothing more to do
+
+ RseNode* view_rse = relationView->rel_view_rse;
+ if (!view_rse)
+ return;
+
+ // we've got a view, expand it
+
+ DEBUG;
+ stack.pop();
+ UCHAR* map = CMP_alloc_map(tdbb, csb, stream);
+
+ AutoSetRestore<USHORT> autoRemapVariable(&csb->csb_remap_variable,
+ (csb->csb_variables ? csb->csb_variables->count() : 0) + 1);
+ AutoSetRestore<jrd_rel*> autoView(&csb->csb_view, relationView);
+ AutoSetRestore<USHORT> autoViewStream(&csb->csb_view_stream, stream);
+
+ // We don't expand the view in two cases:
+ // 1) If the view has a projection, sort, first/skip or explicit plan.
+ // 2) If it's part of an outer join.
+
+ if (rse->rse_jointype || // view_rse->rse_jointype || ???
+ view_rse->rse_sorted || view_rse->rse_projection || view_rse->rse_first ||
+ view_rse->rse_skip || view_rse->rse_plan)
+ {
+ NodeCopier copier(csb, map);
+ RseNode* copy = view_rse->copy(tdbb, copier);
+ DEBUG;
+ copy->pass1(tdbb, csb, csb->csb_view);
+ stack.push(copy);
+ DEBUG;
+ return;
+ }
+
+ // if we have a projection which we can bubble up to the parent rse, set the
+ // parent rse to our projection temporarily to flag the fact that we have already
+ // seen one so that lower-level views will not try to map their projection; the
+ // projection will be copied and correctly mapped later, but we don't have all
+ // the base streams yet
+
+ if (view_rse->rse_projection)
+ rse->rse_projection = view_rse->rse_projection;
+
+ // disect view into component relations
+
+ NestConst<RecordSourceNode>* arg = view_rse->rse_relations.begin();
+ for (const NestConst<RecordSourceNode>* const end = view_rse->rse_relations.end(); arg != end; ++arg)
+ {
+ // this call not only copies the node, it adds any streams it finds to the map
+ NodeCopier copier(csb, map);
+ RecordSourceNode* node = (*arg)->copy(tdbb, copier);
+
+ // Now go out and process the base table itself. This table might also be a view,
+ // in which case we will continue the process by recursion.
+ processSource(tdbb, csb, rse, node, boolean, stack);
+ }
+
+ // When there is a projection in the view, copy the projection up to the query RseNode.
+ // In order to make this work properly, we must remap the stream numbers of the fields
+ // in the view to the stream number of the base table. Note that the map at this point
+ // contains the stream numbers of the referenced relations, since it was added during the call
+ // to copy() above. After the copy() below, the fields in the projection will reference the
+ // base table(s) instead of the view's context (see bug #8822), so we are ready to context-
+ // recognize them in CMP_pass1() - that is, replace the field nodes with actual field blocks.
+
+ if (view_rse->rse_projection)
+ {
+ rse->rse_projection =
+ CMP_pass1(tdbb, csb, NodeCopier::copy(tdbb, csb, view_rse->rse_projection, map));
+ }
+
+ // if we encounter a boolean, copy it and retain it by ANDing it in with the
+ // boolean on the parent view, if any
+
+ if (view_rse->rse_boolean)
+ {
+ jrd_nod* node = CMP_pass1(tdbb, csb, NodeCopier::copy(tdbb,
+ csb, view_rse->rse_boolean, map));
+
+ if (*boolean)
+ {
+ // The order of the nodes here is important! The
+ // boolean from the view must appear first so that
+ // it gets expanded first in pass1.
+
+ jrd_nod* additional = PAR_make_node(tdbb, 2);
+ additional->nod_type = nod_and;
+ additional->nod_arg[0] = node;
+ additional->nod_arg[1] = *boolean;
+ *boolean = additional;
+ }
+ else
+ *boolean = node;
+ }
+}
+
+void RelationSourceNode::pass2Rse(thread_db* tdbb, CompilerScratch* csb)
+{
+ fb_assert(stream <= MAX_STREAMS);
+ csb->csb_rpt[stream].csb_flags |= csb_active;
+
+ pass2(tdbb, csb);
+}
+
+RecordSource* RelationSourceNode::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)
+{
+ fb_assert(stream <= MAX_UCHAR);
+ fb_assert(beds[0] < MAX_STREAMS && beds[0] < MAX_UCHAR); // debug check
+ //if (beds[0] >= MAX_STREAMS) // all builds check
+ // ERR_post(Arg::Gds(isc_too_many_contexts));
+
+ beds[++beds[0]] = (UCHAR) stream;
+
+ // we have found a base relation; record its stream
+ // number in the streams array as a candidate for
+ // merging into a river
+
+ // TMN: Is the intention really to allow streams[0] to overflow?
+ // I must assume that is indeed not the intention (not to mention
+ // it would make code later on fail), so I added the following fb_assert.
+ fb_assert(streams[0] < MAX_STREAMS && streams[0] < MAX_UCHAR);
+
+ streams[++streams[0]] = (UCHAR) stream;
+
+ if (rse->rse_jointype == blr_left)
+ outerStreams.add(stream);
+
+ // if we have seen any booleans or sort fields, we may be able to
+ // use an index to optimize them; retrieve the current format of
+ // all indices at this time so we can determine if it's possible
+ // AB: if a parent_stack was available and conjunct_count was 0
+ // then no indices where retrieved. Added also OR check on
+ // parent_stack below. SF BUG # [ 508594 ]
+
+ if (conjunct_count || sort || aggregate || parent_stack)
+ {
+ jrd_rel* relation = (jrd_rel*) this->relation;
+
+ if (relation && !relation->rel_file && !relation->isVirtual())
+ {
+ csb->csb_rpt[stream].csb_indices =
+ BTR_all(tdbb, relation, &csb->csb_rpt[stream].csb_idx, relation->getPages(tdbb));
+ sortIndicesBySelectivity(&csb->csb_rpt[stream]);
+ markIndices(&csb->csb_rpt[stream], relation->rel_id);
+ }
+ else
+ csb->csb_rpt[stream].csb_indices = 0;
+
+ const Format* format = CMP_format(tdbb, csb, stream);
+ csb->csb_rpt[stream].csb_cardinality = OPT_getRelationCardinality(tdbb, relation, format);
+ }
+
+ return NULL;
+}
+
+
+//--------------------
+
+
+// Parse an procedural view reference.
+ProcedureSourceNode* ProcedureSourceNode::parse(thread_db* tdbb, CompilerScratch* csb,
+ SSHORT blrOp)
+{
+ SET_TDBB(tdbb);
+
+ jrd_prc* procedure = NULL;
+ string* alias_string = NULL;
+ QualifiedName name;
+
+ switch (blrOp)
+ {
+ case blr_pid:
+ case blr_pid2:
+ {
+ const SSHORT pid = csb->csb_blr_reader.getWord();
+
+ if (blrOp == blr_pid2)
+ {
+ alias_string = FB_NEW(csb->csb_pool) 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 (blrOp == blr_procedure3 || blrOp == blr_procedure4)
+ PAR_name(csb, name.package);
+
+ PAR_name(csb, name.identifier);
+
+ if (blrOp == blr_procedure2 || blrOp == blr_procedure4)
+ {
+ alias_string = FB_NEW(csb->csb_pool) 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));
+ }
+
+ ProcedureSourceNode* node = FB_NEW(*tdbb->getDefaultPool()) ProcedureSourceNode(
+ *tdbb->getDefaultPool());
+
+ node->procedure = procedure->getId();
+ node->stream = PAR_context(csb, &node->context);
+
+ csb->csb_rpt[node->stream].csb_procedure = procedure;
+ csb->csb_rpt[node->stream].csb_alias = alias_string;
+
+ PAR_procedure_parms(tdbb, csb, procedure, node->in_msg.getAddress(),
+ node->inputs.getAddress(), true);
+
+ if (csb->csb_g_flags & csb_get_dependencies)
+ PAR_dependency(tdbb, csb, node->stream, (SSHORT) -1, "");
+
+ return node;
+}
+
+ProcedureSourceNode* ProcedureSourceNode::copy(thread_db* tdbb, NodeCopier& copier)
+{
+ if (!copier.remap)
+ BUGCHECK(221); // msg 221 (CMP) copy: cannot remap
+
+ ProcedureSourceNode* newSource = FB_NEW(*tdbb->getDefaultPool()) ProcedureSourceNode(
+ *tdbb->getDefaultPool());
+
+ // dimitr: See the appropriate code and comment in NodeCopier (in nod_argument).
+ // We must copy the message first and only then use the new pointer to
+ // copy the inputs properly.
+ newSource->in_msg = copier.copy(tdbb, in_msg);
+
+ { // scope
+ AutoSetRestore<jrd_nod*> autoMessage(&copier.message, newSource->in_msg);
+ newSource->inputs = copier.copy(tdbb, inputs);
+ }
+
+ newSource->stream = copier.csb->nextStream();
+ copier.remap[stream] = (UCHAR) newSource->stream;
+ newSource->context = context;
+ newSource->procedure = procedure;
+ newSource->view = view;
+ CompilerScratch::csb_repeat* element = CMP_csb_element(copier.csb, newSource->stream);
+ // SKIDDER: Maybe we need to check if we really found a procedure?
+ element->csb_procedure = MET_lookup_procedure_id(tdbb, newSource->procedure, false, false, 0);
+ element->csb_view = (jrd_rel*) newSource->view;
+ element->csb_view_stream = copier.remap[0];
+
+ copier.csb->csb_rpt[newSource->stream].csb_flags |= copier.csb->csb_rpt[stream].csb_flags & csb_no_dbkey;
+
+ return newSource;
+}
+
+void ProcedureSourceNode::pass1(thread_db* tdbb, CompilerScratch* csb, jrd_rel* view)
+{
+ inputs = CMP_pass1(tdbb, csb, inputs);
+ in_msg = CMP_pass1(tdbb, csb, in_msg);
+}
+
+void ProcedureSourceNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, RseNode* rse,
+ jrd_nod** boolean, RecordSourceNodeStack& stack)
+{
+ stack.push(this); // Assume that the source will be used. Push it on the final stream stack.
+
+ pass1(tdbb, csb, csb->csb_view);
+
+ jrd_prc* const proc = MET_lookup_procedure_id(tdbb, procedure, false, false, 0);
+ CMP_post_procedure_access(tdbb, csb, proc);
+ CMP_post_resource(&csb->csb_resources, proc, Resource::rsc_procedure, proc->getId());
+
+ jrd_rel* const parent_view = csb->csb_view;
+ const USHORT view_stream = csb->csb_view_stream;
+ view = parent_view;
+
+ CompilerScratch::csb_repeat* const element = CMP_csb_element(csb, stream);
+ element->csb_view = parent_view;
+ fb_assert(view_stream <= MAX_STREAMS);
+ element->csb_view_stream = (UCHAR) view_stream;
+
+ // in the case where there is a parent view, find the context name
+
+ if (parent_view)
+ {
+ const ViewContexts& ctx = parent_view->rel_view_contexts;
+ const USHORT key = context;
+ size_t pos;
+
+ if (ctx.find(key, pos))
+ {
+ element->csb_alias = FB_NEW(csb->csb_pool) string(
+ csb->csb_pool, ctx[pos]->vcx_context_name);
+ }
+ }
+}
+
+void ProcedureSourceNode::pass2(thread_db* tdbb, CompilerScratch* csb)
+{
+ CMP_pass2(tdbb, csb, inputs, NULL);
+ CMP_pass2(tdbb, csb, in_msg, NULL);
+}
+
+void ProcedureSourceNode::pass2Rse(thread_db* tdbb, CompilerScratch* csb)
+{
+ fb_assert(stream <= MAX_STREAMS);
+ csb->csb_rpt[stream].csb_flags |= csb_active;
+
+ pass2(tdbb, csb);
+}
+
+RecordSource* ProcedureSourceNode::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)
+{
+ fb_assert(stream <= MAX_UCHAR);
+ fb_assert(beds[0] < MAX_STREAMS && beds[0] < MAX_UCHAR); // debug check
+ //if (beds[0] >= MAX_STREAMS) // all builds check
+ // ERR_post(Arg::Gds(isc_too_many_contexts));
+
+ beds[++beds[0]] = (UCHAR) stream;
+
+ RecordSource* rsb = generate(tdbb, opt);
+ fb_assert(local_streams[0] < MAX_STREAMS && local_streams[0] < MAX_UCHAR);
+ local_streams[++local_streams[0]] = stream;
+
+ return rsb;
+}
+
+// Compile and optimize a record selection expression into a set of record source blocks (rsb's).
+ProcedureScan* ProcedureSourceNode::generate(thread_db* tdbb, OptimizerBlk* opt)
+{
+ DEV_BLKCHK(opt, type_opt);
+ DEV_BLKCHK(node, type_nod);
+ SET_TDBB(tdbb);
+
+ jrd_prc* const proc = MET_lookup_procedure_id(tdbb, procedure, false, false, 0);
+
+ CompilerScratch* const csb = opt->opt_csb;
+ CompilerScratch::csb_repeat* const csb_tail = &csb->csb_rpt[stream];
+ const string alias = OPT_make_alias(tdbb, csb, csb_tail);
+
+ return FB_NEW(*tdbb->getDefaultPool()) ProcedureScan(csb, alias, stream, proc, inputs, in_msg);
+}
+
+bool ProcedureSourceNode::computable(CompilerScratch* csb, SSHORT stream, bool idx_use,
+ bool allowOnlyCurrentStream, jrd_nod* value)
+{
+ 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;
+ }
+ }
+
+ return true;
+}
+
+void ProcedureSourceNode::findDependentFromStreams(const OptimizerRetrieval* optRet,
+ SortedStreamList* streamList)
+{
+ 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++)
+ optRet->findDependentFromStreams(*ptr, streamList);
+ }
+}
+
+
+//--------------------
+
+
+// Parse an aggregate reference.
+AggregateSourceNode* AggregateSourceNode::parse(thread_db* tdbb, CompilerScratch* csb)
+{
+ SET_TDBB(tdbb);
+
+ AggregateSourceNode* node = FB_NEW(*tdbb->getDefaultPool()) AggregateSourceNode(
+ *tdbb->getDefaultPool());
+
+ node->stream = PAR_context(csb, NULL);
+ fb_assert(node->stream <= MAX_STREAMS);
+ node->rse = RseNode::getFrom(PAR_parse_node(tdbb, csb, TYPE_RSE));
+ node->group = PAR_parse_node(tdbb, csb, OTHER);
+ node->map = parseMap(tdbb, csb, node->stream);
+
+ return node;
+}
+
+AggregateSourceNode* AggregateSourceNode::copy(thread_db* tdbb, NodeCopier& copier)
+{
+ if (!copier.remap)
+ BUGCHECK(221); // msg 221 (CMP) copy: cannot remap
+
+ AggregateSourceNode* newSource = FB_NEW(*tdbb->getDefaultPool()) AggregateSourceNode(
+ *tdbb->getDefaultPool());
+
+ fb_assert(stream <= MAX_STREAMS);
+ newSource->stream = copier.csb->nextStream();
+ // fb_assert(newSource->stream <= MAX_UCHAR);
+ copier.remap[stream] = (UCHAR) newSource->stream;
+ CMP_csb_element(copier.csb, newSource->stream);
+
+ copier.csb->csb_rpt[newSource->stream].csb_flags |=
+ copier.csb->csb_rpt[stream].csb_flags & csb_no_dbkey;
+
+ newSource->rse = rse->copy(tdbb, copier);
+ newSource->group = copier.copy(tdbb, group);
+ newSource->map = copier.copy(tdbb, map);
+
+ return newSource;
+}
+
+void AggregateSourceNode::ignoreDbKey(thread_db* tdbb, CompilerScratch* csb, const jrd_rel* view) const
+{
+ rse->ignoreDbKey(tdbb, csb, view);
+}
+
+void AggregateSourceNode::pass1(thread_db* tdbb, CompilerScratch* csb, jrd_rel* view)
+{
+ fb_assert(stream <= MAX_STREAMS);
+ csb->csb_rpt[stream].csb_flags |= csb_no_dbkey;
+ rse->ignoreDbKey(tdbb, csb, view);
+ rse->pass1(tdbb, csb, csb->csb_view);
+ map = CMP_pass1(tdbb, csb, map);
+ group = CMP_pass1(tdbb, csb, group);
+}
+
+void AggregateSourceNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, RseNode* rse,
+ jrd_nod** boolean, RecordSourceNodeStack& stack)
+{
+ stack.push(this); // Assume that the source will be used. Push it on the final stream stack.
+
+ fb_assert(stream <= MAX_STREAMS);
+ pass1(tdbb, csb, csb->csb_view);
+}
+
+void AggregateSourceNode::pass2(thread_db* tdbb, CompilerScratch* csb)
+{
+ rse->pass2Rse(tdbb, csb);
+ CMP_pass2(tdbb, csb, map, NULL);
+ CMP_pass2(tdbb, csb, group, NULL);
+
+ fb_assert(stream <= MAX_STREAMS);
+
+ if (map)
+ {
+ processMap(tdbb, csb, map, &csb->csb_rpt[stream].csb_internal_format);
+ csb->csb_rpt[stream].csb_format = csb->csb_rpt[stream].csb_internal_format;
+ }
+}
+
+void AggregateSourceNode::pass2Rse(thread_db* tdbb, CompilerScratch* csb)
+{
+ fb_assert(stream <= MAX_STREAMS);
+ csb->csb_rpt[stream].csb_flags |= csb_active;
+
+ pass2(tdbb, csb);
+}
+
+bool AggregateSourceNode::containsStream(USHORT checkStream) const
+{
+ // for aggregates, check current RseNode, if not found then check
+ // the sub-rse
+
+ if (checkStream == stream)
+ return true; // do not mark as variant
+
+ if (rse->containsStream(checkStream))
+ return true; // do not mark as variant
+
+ return false;
+}
+
+RecordSource* AggregateSourceNode::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)
+{
+ fb_assert(stream <= MAX_UCHAR);
+ fb_assert(beds[0] < MAX_STREAMS && beds[0] < MAX_UCHAR); // debug check
+ //if (beds[0] >= MAX_STREAMS) // all builds check
+ // ERR_post(Arg::Gds(isc_too_many_contexts));
+
+ beds[++beds[0]] = (UCHAR) stream;
+
+ NodeStack::const_iterator stack_end;
+ if (parent_stack)
+ stack_end = conjunct_stack.merge(*parent_stack);
+
+ RecordSource* rsb = generate(tdbb, opt, &conjunct_stack, stream);
+
+ if (parent_stack)
+ conjunct_stack.split(stack_end, *parent_stack);
+
+ fb_assert(local_streams[0] < MAX_STREAMS && local_streams[0] < MAX_UCHAR);
+ local_streams[++local_streams[0]] = stream;
+
+ return rsb;
+}
+
+// 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* parent_stack, UCHAR shellStream)
+{
+ DEV_BLKCHK(opt, type_opt);
+ DEV_BLKCHK(node, type_nod);
+ SET_TDBB(tdbb);
+
+ CompilerScratch* const csb = opt->opt_csb;
+ rse->rse_sorted = group;
+
+ // AB: Try to distribute items from the HAVING CLAUSE to the WHERE CLAUSE.
+ // 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;
+ genDeliverUnmapped(tdbb, &deliverStack, map, parent_stack, shellStream);
+
+ // try to optimize MAX and MIN to use an index; for now, optimize
+ // only the simplest case, although it is probably possible
+ // to use an index in more complex situations
+ jrd_nod** ptr;
+ AggNode* aggNode = NULL;
+
+ if (map && map->nod_count == 1 && (ptr = map->nod_arg) &&
+ (aggNode = ExprNode::as<AggNode>((*ptr)->nod_arg[e_asgn_from])) &&
+ (aggNode->aggInfo.blr == blr_agg_min || aggNode->aggInfo.blr == blr_agg_max))
+ {
+ // generate a sort block which the optimizer will try to map to an index
+
+ jrd_nod* aggregate = PAR_make_node(tdbb, 3);
+ aggregate->nod_type = nod_sort;
+ aggregate->nod_count = 1;
+ aggregate->nod_arg[0] = aggNode->arg;
+ // in the max case, flag the sort as descending
+ if (aggNode->aggInfo.blr == blr_agg_max)
+ aggregate->nod_arg[1] = (jrd_nod*) TRUE;
+ // 10-Aug-2004. Nickolay Samofatov - Unneeded nulls seem to be skipped somehow.
+ aggregate->nod_arg[2] = (jrd_nod*)(IPTR) rse_nulls_default;
+ rse->rse_aggregate = aggregate;
+ }
+
+ RecordSource* const next_rsb = OPT_compile(tdbb, csb, rse, &deliverStack);
+
+ fb_assert(stream <= MAX_STREAMS);
+ fb_assert(stream <= MAX_UCHAR);
+
+ // allocate and optimize the record source block
+
+ AggregatedStream* const rsb = FB_NEW(*tdbb->getDefaultPool()) AggregatedStream(csb, stream,
+ group, map, next_rsb);
+
+ if (rse->rse_aggregate)
+ {
+ // The rse_aggregate is still set. That means the optimizer
+ // was able to match the field to an index, so flag that fact
+ // so that it can be handled in EVL_group
+ aggNode->indexed = true;
+ }
+
+ OPT_gen_aggregate_distincts(tdbb, csb, map);
+
+ return rsb;
+}
+
+bool AggregateSourceNode::computable(CompilerScratch* csb, SSHORT stream, bool idx_use,
+ bool allowOnlyCurrentStream, jrd_nod* value)
+{
+ rse->rse_sorted = group;
+ return rse->computable(csb, stream, idx_use, allowOnlyCurrentStream, NULL);
+}
+
+void AggregateSourceNode::findDependentFromStreams(const OptimizerRetrieval* optRet,
+ SortedStreamList* streamList)
+{
+ rse->rse_sorted = group;
+ rse->findDependentFromStreams(optRet, streamList);
+}
+
+
+//--------------------
+
+
+// Parse a union reference.
+UnionSourceNode* UnionSourceNode::parse(thread_db* tdbb, CompilerScratch* csb, SSHORT blrOp)
+{
+ SET_TDBB(tdbb);
+
+ // Make the node, parse the context number, get a stream assigned,
+ // and get the number of sub-RseNode's.
+
+ UnionSourceNode* node = FB_NEW(*tdbb->getDefaultPool()) UnionSourceNode(
+ *tdbb->getDefaultPool());
+
+ node->recursive = blrOp == blr_recurse;
+
+ node->stream = PAR_context(csb, NULL);
+ fb_assert(node->stream <= MAX_STREAMS);
+
+ // assign separate context for mapped record if union is recursive
+ USHORT map_stream = node->stream;
+
+ if (node->recursive)
+ {
+ map_stream = PAR_context(csb, 0);
+ node->mapStream = map_stream;
+ }
+
+ SSHORT count = (unsigned int) csb->csb_blr_reader.getByte();
+
+ // Pick up the sub-RseNode's and maps.
+
+ while (--count >= 0)
+ {
+ node->clauses.push(RseNode::getFrom(PAR_parse_node(tdbb, csb, TYPE_RSE)));
+ node->maps.push(parseMap(tdbb, csb, map_stream));
+ }
+
+ return node;
+}
+
+UnionSourceNode* UnionSourceNode::copy(thread_db* tdbb, NodeCopier& copier)
+{
+ if (!copier.remap)
+ BUGCHECK(221); // msg 221 (CMP) copy: cannot remap
+
+ UnionSourceNode* newSource = FB_NEW(*tdbb->getDefaultPool()) UnionSourceNode(
+ *tdbb->getDefaultPool());
+ newSource->recursive = recursive;
+
+ fb_assert(stream <= MAX_STREAMS);
+ newSource->stream = copier.csb->nextStream();
+ copier.remap[stream] = (UCHAR) newSource->stream;
+ CMP_csb_element(copier.csb, newSource->stream);
+
+ USHORT oldStream = stream;
+ USHORT newStream = newSource->stream;
+
+ if (newSource->recursive)
+ {
+ oldStream = mapStream;
+ fb_assert(oldStream <= MAX_STREAMS);
+ newStream = copier.csb->nextStream();
+ newSource->mapStream = newStream;
+ copier.remap[oldStream] = (UCHAR) newStream;
+ CMP_csb_element(copier.csb, newStream);
+ }
+
+ copier.csb->csb_rpt[newStream].csb_flags |=
+ copier.csb->csb_rpt[oldStream].csb_flags & csb_no_dbkey;
+
+ NestConst<RseNode>* ptr = clauses.begin();
+ NestConst<jrd_nod>* ptr2 = maps.begin();
+
+ for (NestConst<RseNode>* const end = clauses.end(); ptr != end; ++ptr, ++ptr2)
+ {
+ newSource->clauses.add((*ptr)->copy(tdbb, copier));
+ newSource->maps.add(copier.copy(tdbb, *ptr2));
+ }
+
+ return newSource;
+}
+
+void UnionSourceNode::ignoreDbKey(thread_db* tdbb, CompilerScratch* csb, const jrd_rel* view) const
+{
+ const NestConst<RseNode>* ptr = clauses.begin();
+
+ for (const NestConst<RseNode>* const end = clauses.end(); ptr != end; ++ptr)
+ (*ptr)->ignoreDbKey(tdbb, csb, view);
+}
+
+void UnionSourceNode::pass1Source(thread_db* tdbb, CompilerScratch* csb, RseNode* rse,
+ jrd_nod** boolean, RecordSourceNodeStack& stack)
+{
+ stack.push(this); // Assume that the source will be used. Push it on the fina...
[truncated message content] |