|
From: <asf...@us...> - 2010-09-17 03:15:41
|
Revision: 51564
http://firebird.svn.sourceforge.net/firebird/?rev=51564&view=rev
Author: asfernandes
Date: 2010-09-17 03:15:32 +0000 (Fri, 17 Sep 2010)
Log Message:
-----------
1) Refactor all types of boolean nodes.
2) Remove the scratch from the nodes.
Modified Paths:
--------------
firebird/trunk/builds/posix/make.shared.variables
firebird/trunk/builds/win32/msvc10/dsql_server.vcxproj
firebird/trunk/builds/win32/msvc10/dsql_server.vcxproj.filters
firebird/trunk/builds/win32/msvc10/dsql_server_classic.vcxproj
firebird/trunk/builds/win32/msvc10/dsql_server_classic.vcxproj.filters
firebird/trunk/builds/win32/msvc9/dsql_server.vcproj
firebird/trunk/builds/win32/msvc9/dsql_server_classic.vcproj
firebird/trunk/src/dsql/AggNodes.cpp
firebird/trunk/src/dsql/AggNodes.h
firebird/trunk/src/dsql/DdlNodes.epp
firebird/trunk/src/dsql/DdlNodes.h
firebird/trunk/src/dsql/DsqlCompilerScratch.cpp
firebird/trunk/src/dsql/DsqlCompilerScratch.h
firebird/trunk/src/dsql/ExprNodes.cpp
firebird/trunk/src/dsql/ExprNodes.h
firebird/trunk/src/dsql/Nodes.h
firebird/trunk/src/dsql/PackageNodes.epp
firebird/trunk/src/dsql/PackageNodes.h
firebird/trunk/src/dsql/Parser.h
firebird/trunk/src/dsql/StmtNodes.cpp
firebird/trunk/src/dsql/StmtNodes.h
firebird/trunk/src/dsql/Visitors.h
firebird/trunk/src/dsql/WinNodes.cpp
firebird/trunk/src/dsql/WinNodes.h
firebird/trunk/src/dsql/btyacc_fb.ske
firebird/trunk/src/dsql/ddl.cpp
firebird/trunk/src/dsql/dsql.cpp
firebird/trunk/src/dsql/dsql.h
firebird/trunk/src/dsql/gen.cpp
firebird/trunk/src/dsql/keywords.cpp
firebird/trunk/src/dsql/make.cpp
firebird/trunk/src/dsql/node.h
firebird/trunk/src/dsql/parse.y
firebird/trunk/src/dsql/pass1.cpp
firebird/trunk/src/dsql/pass1_proto.h
firebird/trunk/src/jrd/Optimizer.cpp
firebird/trunk/src/jrd/Optimizer.h
firebird/trunk/src/jrd/RecordSourceNodes.cpp
firebird/trunk/src/jrd/cmp.cpp
firebird/trunk/src/jrd/cmp_proto.h
firebird/trunk/src/jrd/evl.cpp
firebird/trunk/src/jrd/exe.h
firebird/trunk/src/jrd/nod.h
firebird/trunk/src/jrd/opt.cpp
firebird/trunk/src/jrd/par.cpp
firebird/trunk/src/jrd/recsrc/FilteredStream.cpp
firebird/trunk/src/misc/blrtable.cpp
Added Paths:
-----------
firebird/trunk/src/dsql/BoolNodes.cpp
firebird/trunk/src/dsql/BoolNodes.h
Modified: firebird/trunk/builds/posix/make.shared.variables
===================================================================
--- firebird/trunk/builds/posix/make.shared.variables 2010-09-16 07:29:28 UTC (rev 51563)
+++ firebird/trunk/builds/posix/make.shared.variables 2010-09-17 03:15:32 UTC (rev 51564)
@@ -81,8 +81,8 @@
DSQL_ServerFiles= metd.epp DSqlDataTypeUtil.cpp \
ddl.cpp dsql.cpp errd.cpp gen.cpp hsh.cpp make.cpp \
movd.cpp parse.cpp Parser.cpp pass1.cpp \
- DdlNodes.epp PackageNodes.epp AggNodes.cpp BlrWriter.cpp DsqlCompilerScratch.cpp \
- ExprNodes.cpp StmtNodes.cpp WinNodes.cpp
+ DdlNodes.epp PackageNodes.epp AggNodes.cpp BlrWriter.cpp BoolNodes.cpp \
+ DsqlCompilerScratch.cpp ExprNodes.cpp StmtNodes.cpp WinNodes.cpp
DSQL_Files = $(DSQL_ClientFiles) $(DSQL_ServerFiles)
Modified: firebird/trunk/builds/win32/msvc10/dsql_server.vcxproj
===================================================================
--- firebird/trunk/builds/win32/msvc10/dsql_server.vcxproj 2010-09-16 07:29:28 UTC (rev 51563)
+++ firebird/trunk/builds/win32/msvc10/dsql_server.vcxproj 2010-09-17 03:15:32 UTC (rev 51564)
@@ -140,6 +140,7 @@
<ItemGroup>
<ClCompile Include="..\..\..\src\dsql\AggNodes.cpp" />
<ClCompile Include="..\..\..\src\dsql\BlrWriter.cpp" />
+ <ClCompile Include="..\..\..\src\dsql\BoolNodes.cpp" />
<ClCompile Include="..\..\..\src\dsql\ddl.cpp" />
<ClCompile Include="..\..\..\src\dsql\dsql.cpp" />
<ClCompile Include="..\..\..\src\dsql\DsqlCompilerScratch.cpp" />
@@ -179,6 +180,7 @@
<ClInclude Include="..\..\..\src\dsql\array_proto.h" />
<ClInclude Include="..\..\..\src\dsql\blob_proto.h" />
<ClInclude Include="..\..\..\src\dsql\BlrWriter.h" />
+ <ClInclude Include="..\..\..\src\dsql\BoolNodes.h" />
<ClInclude Include="..\..\..\src\dsql\chars.h" />
<ClInclude Include="..\..\..\src\dsql\ddl_proto.h" />
<ClInclude Include="..\..\..\src\dsql\DdlNodes.h" />
Modified: firebird/trunk/builds/win32/msvc10/dsql_server.vcxproj.filters
===================================================================
--- firebird/trunk/builds/win32/msvc10/dsql_server.vcxproj.filters 2010-09-16 07:29:28 UTC (rev 51563)
+++ firebird/trunk/builds/win32/msvc10/dsql_server.vcxproj.filters 2010-09-17 03:15:32 UTC (rev 51564)
@@ -28,6 +28,9 @@
<ClCompile Include="..\..\..\src\dsql\BlrWriter.cpp">
<Filter>DSQL files</Filter>
</ClCompile>
+ <ClCompile Include="..\..\..\src\dsql\BoolNodes.cpp">
+ <Filter>DSQL files</Filter>
+ </ClCompile>
<ClCompile Include="..\..\..\src\dsql\ddl.cpp">
<Filter>DSQL files</Filter>
</ClCompile>
@@ -135,6 +138,9 @@
<ClInclude Include="..\..\..\src\dsql\BlrWriter.h">
<Filter>Header files</Filter>
</ClInclude>
+ <ClInclude Include="..\..\..\src\dsql\BoolNodes.h">
+ <Filter>Header files</Filter>
+ </ClInclude>
<ClInclude Include="..\..\..\src\dsql\chars.h">
<Filter>Header files</Filter>
</ClInclude>
Modified: firebird/trunk/builds/win32/msvc10/dsql_server_classic.vcxproj
===================================================================
--- firebird/trunk/builds/win32/msvc10/dsql_server_classic.vcxproj 2010-09-16 07:29:28 UTC (rev 51563)
+++ firebird/trunk/builds/win32/msvc10/dsql_server_classic.vcxproj 2010-09-17 03:15:32 UTC (rev 51564)
@@ -140,6 +140,7 @@
<ItemGroup>
<ClCompile Include="..\..\..\src\dsql\AggNodes.cpp" />
<ClCompile Include="..\..\..\src\dsql\BlrWriter.cpp" />
+ <ClCompile Include="..\..\..\src\dsql\BoolNodes.cpp" />
<ClCompile Include="..\..\..\src\dsql\ddl.cpp" />
<ClCompile Include="..\..\..\src\dsql\dsql.cpp" />
<ClCompile Include="..\..\..\src\dsql\DsqlCompilerScratch.cpp" />
@@ -179,6 +180,7 @@
<ClInclude Include="..\..\..\src\dsql\array_proto.h" />
<ClInclude Include="..\..\..\src\dsql\blob_proto.h" />
<ClInclude Include="..\..\..\src\dsql\BlrWriter.h" />
+ <ClInclude Include="..\..\..\src\dsql\BoolNodes.h" />
<ClInclude Include="..\..\..\src\dsql\chars.h" />
<ClInclude Include="..\..\..\src\dsql\ddl_proto.h" />
<ClInclude Include="..\..\..\src\dsql\DdlNodes.h" />
Modified: firebird/trunk/builds/win32/msvc10/dsql_server_classic.vcxproj.filters
===================================================================
--- firebird/trunk/builds/win32/msvc10/dsql_server_classic.vcxproj.filters 2010-09-16 07:29:28 UTC (rev 51563)
+++ firebird/trunk/builds/win32/msvc10/dsql_server_classic.vcxproj.filters 2010-09-17 03:15:32 UTC (rev 51564)
@@ -28,6 +28,9 @@
<ClCompile Include="..\..\..\src\dsql\BlrWriter.cpp">
<Filter>DSQL files</Filter>
</ClCompile>
+ <ClCompile Include="..\..\..\src\dsql\BoolNodes.cpp">
+ <Filter>DSQL files</Filter>
+ </ClCompile>
<ClCompile Include="..\..\..\src\dsql\ddl.cpp">
<Filter>DSQL files</Filter>
</ClCompile>
@@ -135,6 +138,9 @@
<ClInclude Include="..\..\..\src\dsql\BlrWriter.h">
<Filter>Header files</Filter>
</ClInclude>
+ <ClInclude Include="..\..\..\src\dsql\BoolNodes.h">
+ <Filter>Header files</Filter>
+ </ClInclude>
<ClInclude Include="..\..\..\src\dsql\chars.h">
<Filter>Header files</Filter>
</ClInclude>
Modified: firebird/trunk/builds/win32/msvc9/dsql_server.vcproj
===================================================================
--- firebird/trunk/builds/win32/msvc9/dsql_server.vcproj 2010-09-16 07:29:28 UTC (rev 51563)
+++ firebird/trunk/builds/win32/msvc9/dsql_server.vcproj 2010-09-17 03:15:32 UTC (rev 51564)
@@ -275,6 +275,10 @@
>
</File>
<File
+ RelativePath="..\..\..\src\dsql\BoolNodes.cpp"
+ >
+ </File>
+ <File
RelativePath="..\..\..\src\dsql\ddl.cpp"
>
</File>
@@ -430,6 +434,10 @@
>
</File>
<File
+ RelativePath="..\..\..\src\dsql\BoolNodes.h"
+ >
+ </File>
+ <File
RelativePath="..\..\..\src\dsql\chars.h"
>
</File>
Modified: firebird/trunk/builds/win32/msvc9/dsql_server_classic.vcproj
===================================================================
--- firebird/trunk/builds/win32/msvc9/dsql_server_classic.vcproj 2010-09-16 07:29:28 UTC (rev 51563)
+++ firebird/trunk/builds/win32/msvc9/dsql_server_classic.vcproj 2010-09-17 03:15:32 UTC (rev 51564)
@@ -275,6 +275,10 @@
>
</File>
<File
+ RelativePath="..\..\..\src\dsql\BoolNodes.cpp"
+ >
+ </File>
+ <File
RelativePath="..\..\..\src\dsql\ddl.cpp"
>
</File>
@@ -430,6 +434,10 @@
>
</File>
<File
+ RelativePath="..\..\..\src\dsql\BoolNodes.h"
+ >
+ </File>
+ <File
RelativePath="..\..\..\src\dsql\chars.h"
>
</File>
Modified: firebird/trunk/src/dsql/AggNodes.cpp
===================================================================
--- firebird/trunk/src/dsql/AggNodes.cpp 2010-09-16 07:29:28 UTC (rev 51563)
+++ firebird/trunk/src/dsql/AggNodes.cpp 2010-09-17 03:15:32 UTC (rev 51564)
@@ -53,7 +53,7 @@
AggNode::AggNode(MemoryPool& pool, const AggInfo& aAggInfo, bool aDistinct, bool aDialect1,
dsql_nod* aArg)
- : TypedNode<ExprNode, ExprNode::TYPE_AGGREGATE>(pool),
+ : TypedNode<ValueExprNode, ExprNode::TYPE_AGGREGATE>(pool),
aggInfo(aAggInfo),
distinct(aDistinct),
dialect1(aDialect1),
@@ -65,7 +65,7 @@
addChildNode(dsqlArg, arg);
}
-ExprNode* AggNode::internalDsqlPass()
+AggNode* AggNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
{
if (dsqlScratch->isPsql())
{
@@ -82,10 +82,7 @@
Arg::Gds(isc_dsql_agg_ref_err));
}
- AggNode* node = dsqlCopy();
- node->dsqlScratch = dsqlScratch;
-
- return node;
+ return dsqlCopy(dsqlScratch);
}
void AggNode::print(string& text, Array<dsql_nod*>& nodes) const
@@ -140,7 +137,7 @@
// If the deepestLevel is the same as the current scopeLevel this is an
// aggregate that belongs to the current context.
- if (visitor.deepestLevel == dsqlScratch->scopeLevel)
+ if (visitor.deepestLevel == visitor.dsqlScratch->scopeLevel)
aggregate = true;
else
{
@@ -234,15 +231,15 @@
bool AggNode::dsqlFieldRemapper(FieldRemapper& visitor)
{
- AggregateFinder aggFinder(dsqlScratch, false);
- aggFinder.deepestLevel = dsqlScratch->scopeLevel;
+ AggregateFinder aggFinder(visitor.dsqlScratch, false);
+ aggFinder.deepestLevel = visitor.dsqlScratch->scopeLevel;
aggFinder.currentLevel = visitor.currentLevel;
if (dsqlAggregateFinder(aggFinder))
{
- if (!visitor.window && dsqlScratch->scopeLevel == aggFinder.deepestLevel)
+ if (!visitor.window && visitor.dsqlScratch->scopeLevel == aggFinder.deepestLevel)
{
- visitor.replaceNode(PASS1_post_map(dsqlScratch, visitor.getCurrentNode(),
+ visitor.replaceNode(PASS1_post_map(visitor.dsqlScratch, visitor.getCurrentNode(),
visitor.context, visitor.partitionNode, visitor.orderNode));
return false;
}
@@ -273,7 +270,7 @@
parameter->par_name = parameter->par_alias = aggInfo.name;
}
-void AggNode::genBlr()
+void AggNode::genBlr(DsqlCompilerScratch* dsqlScratch)
{
if (aggInfo.blr) // Is this a standard aggregate function?
dsqlScratch->appendUChar((distinct ? aggInfo.distinctBlr : aggInfo.blr));
@@ -455,7 +452,7 @@
return node;
}
-void AvgAggNode::make(dsc* desc, dsql_nod* nullReplacement)
+void AvgAggNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc, dsql_nod* nullReplacement)
{
MAKE_desc(dsqlScratch, desc, dsqlArg, nullReplacement);
desc->setNullable(true);
@@ -554,7 +551,7 @@
}
}
-ExprNode* AvgAggNode::copy(thread_db* tdbb, NodeCopier& copier)
+ValueExprNode* AvgAggNode::copy(thread_db* tdbb, NodeCopier& copier)
{
AvgAggNode* node = FB_NEW(*tdbb->getDefaultPool()) AvgAggNode(*tdbb->getDefaultPool(),
distinct, dialect1);
@@ -631,7 +628,7 @@
return &impureTemp->vlu_desc;
}
-AggNode* AvgAggNode::dsqlCopy() const
+AggNode* AvgAggNode::dsqlCopy(DsqlCompilerScratch* dsqlScratch) const
{
return FB_NEW(getPool()) AvgAggNode(getPool(), distinct, dialect1,
PASS1_node(dsqlScratch, dsqlArg));
@@ -660,7 +657,7 @@
return node;
}
-void ListAggNode::make(dsc* desc, dsql_nod* nullReplacement)
+void ListAggNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc, dsql_nod* nullReplacement)
{
MAKE_desc(dsqlScratch, desc, dsqlArg, nullReplacement);
desc->makeBlob(desc->getBlobSubType(), desc->getTextType());
@@ -680,7 +677,7 @@
desc->makeBlob(desc->getBlobSubType(), desc->getTextType());
}
-ExprNode* ListAggNode::copy(thread_db* tdbb, NodeCopier& copier)
+ValueExprNode* ListAggNode::copy(thread_db* tdbb, NodeCopier& copier)
{
ListAggNode* node = FB_NEW(*tdbb->getDefaultPool()) ListAggNode(*tdbb->getDefaultPool(),
distinct);
@@ -756,7 +753,7 @@
return &impure->vlu_desc;
}
-AggNode* ListAggNode::dsqlCopy() const
+AggNode* ListAggNode::dsqlCopy(DsqlCompilerScratch* dsqlScratch) const
{
return FB_NEW(getPool()) ListAggNode(getPool(), distinct,
PASS1_node(dsqlScratch, dsqlArg), PASS1_node(dsqlScratch, dsqlDelimiter));
@@ -784,20 +781,20 @@
return node;
}
-void CountAggNode::make(dsc* desc, dsql_nod* /*nullReplacement*/)
+void CountAggNode::make(DsqlCompilerScratch* /*dsqlScratch*/, dsc* desc, dsql_nod* /*nullReplacement*/)
{
desc->makeLong(0);
}
-void CountAggNode::genBlr()
+void CountAggNode::genBlr(DsqlCompilerScratch* dsqlScratch)
{
if (dsqlArg)
- AggNode::genBlr();
+ AggNode::genBlr(dsqlScratch);
else
dsqlScratch->appendUChar(blr_agg_count);
}
-void CountAggNode::getDesc(thread_db* tdbb, CompilerScratch* /*csb*/, dsc* desc)
+void CountAggNode::getDesc(thread_db* /*tdbb*/, CompilerScratch* /*csb*/, dsc* desc)
{
desc->dsc_dtype = dtype_long;
desc->dsc_length = sizeof(SLONG);
@@ -806,7 +803,7 @@
desc->dsc_flags = 0;
}
-ExprNode* CountAggNode::copy(thread_db* tdbb, NodeCopier& copier)
+ValueExprNode* CountAggNode::copy(thread_db* tdbb, NodeCopier& copier)
{
CountAggNode* node = FB_NEW(*tdbb->getDefaultPool()) CountAggNode(*tdbb->getDefaultPool(),
distinct);
@@ -838,7 +835,7 @@
return &impure->vlu_desc;
}
-AggNode* CountAggNode::dsqlCopy() const
+AggNode* CountAggNode::dsqlCopy(DsqlCompilerScratch* dsqlScratch) const
{
return FB_NEW(getPool()) CountAggNode(getPool(), distinct,
PASS1_node(dsqlScratch, dsqlArg));
@@ -865,7 +862,7 @@
return node;
}
-void SumAggNode::make(dsc* desc, dsql_nod* nullReplacement)
+void SumAggNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc, dsql_nod* nullReplacement)
{
MAKE_desc(dsqlScratch, desc, dsqlArg, nullReplacement);
desc->setNullable(true);
@@ -1041,7 +1038,7 @@
ERR_post(Arg::Gds(isc_datype_notsup)); // data type not supported for arithmetic
}
-ExprNode* SumAggNode::copy(thread_db* tdbb, NodeCopier& copier)
+ValueExprNode* SumAggNode::copy(thread_db* tdbb, NodeCopier& copier)
{
SumAggNode* node = FB_NEW(*tdbb->getDefaultPool()) SumAggNode(*tdbb->getDefaultPool(),
distinct, dialect1);
@@ -1086,7 +1083,7 @@
return &impure->vlu_desc;
}
-AggNode* SumAggNode::dsqlCopy() const
+AggNode* SumAggNode::dsqlCopy(DsqlCompilerScratch* dsqlScratch) const
{
return FB_NEW(getPool()) SumAggNode(getPool(), distinct, dialect1,
PASS1_node(dsqlScratch, dsqlArg));
@@ -1113,7 +1110,7 @@
return node;
}
-void MaxMinAggNode::make(dsc* desc, dsql_nod* nullReplacement)
+void MaxMinAggNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc, dsql_nod* nullReplacement)
{
MAKE_desc(dsqlScratch, desc, dsqlArg, nullReplacement);
desc->setNullable(true);
@@ -1124,7 +1121,7 @@
CMP_get_desc(tdbb, csb, arg, desc);
}
-ExprNode* MaxMinAggNode::copy(thread_db* tdbb, NodeCopier& copier)
+ValueExprNode* MaxMinAggNode::copy(thread_db* tdbb, NodeCopier& copier)
{
MaxMinAggNode* node = FB_NEW(*tdbb->getDefaultPool()) MaxMinAggNode(*tdbb->getDefaultPool(),
type);
@@ -1167,7 +1164,7 @@
return &impure->vlu_desc;
}
-AggNode* MaxMinAggNode::dsqlCopy() const
+AggNode* MaxMinAggNode::dsqlCopy(DsqlCompilerScratch* dsqlScratch) const
{
return FB_NEW(getPool()) MaxMinAggNode(getPool(), type, PASS1_node(dsqlScratch, dsqlArg));
}
Modified: firebird/trunk/src/dsql/AggNodes.h
===================================================================
--- firebird/trunk/src/dsql/AggNodes.h 2010-09-16 07:29:28 UTC (rev 51563)
+++ firebird/trunk/src/dsql/AggNodes.h 2010-09-17 03:15:32 UTC (rev 51564)
@@ -37,9 +37,9 @@
static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR blrOp);
- virtual void make(dsc* desc, dsql_nod* nullReplacement);
+ virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc, dsql_nod* nullReplacement);
virtual void getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc);
- virtual ExprNode* copy(thread_db* tdbb, NodeCopier& copier);
+ virtual ValueExprNode* copy(thread_db* tdbb, NodeCopier& copier);
virtual ExprNode* pass2(thread_db* tdbb, CompilerScratch* csb);
virtual void aggInit(thread_db* tdbb, jrd_req* request) const;
@@ -47,7 +47,7 @@
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request) const;
protected:
- virtual AggNode* dsqlCopy() const;
+ virtual AggNode* dsqlCopy(DsqlCompilerScratch* dsqlScratch) const;
private:
USHORT tempImpure;
@@ -61,11 +61,11 @@
static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR blrOp);
- virtual void make(dsc* desc, dsql_nod* nullReplacement);
+ virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc, dsql_nod* nullReplacement);
virtual bool setParameterType(DsqlCompilerScratch* dsqlScratch,
dsql_nod* node, bool forceVarChar) const;
virtual void getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc);
- virtual ExprNode* copy(thread_db* tdbb, NodeCopier& copier);
+ virtual ValueExprNode* copy(thread_db* tdbb, NodeCopier& copier);
virtual void checkOrderedWindowCapable() const
{
@@ -80,7 +80,7 @@
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request) const;
protected:
- virtual AggNode* dsqlCopy() const;
+ virtual AggNode* dsqlCopy(DsqlCompilerScratch* dsqlScratch) const;
private:
dsql_nod* dsqlDelimiter;
@@ -94,17 +94,17 @@
static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR blrOp);
- virtual void make(dsc* desc, dsql_nod* nullReplacement);
- virtual void genBlr();
+ virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc, dsql_nod* nullReplacement);
+ virtual void genBlr(DsqlCompilerScratch* dsqlScratch);
virtual void getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc);
- virtual ExprNode* copy(thread_db* tdbb, NodeCopier& copier);
+ virtual ValueExprNode* copy(thread_db* tdbb, NodeCopier& copier);
virtual void aggInit(thread_db* tdbb, jrd_req* request) const;
virtual void aggPass(thread_db* tdbb, jrd_req* request, dsc* desc) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request) const;
protected:
- virtual AggNode* dsqlCopy() const;
+ virtual AggNode* dsqlCopy(DsqlCompilerScratch* dsqlScratch) const;
};
class SumAggNode : public AggNode
@@ -114,16 +114,16 @@
static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR blrOp);
- virtual void make(dsc* desc, dsql_nod* nullReplacement);
+ virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc, dsql_nod* nullReplacement);
virtual void getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc);
- virtual ExprNode* copy(thread_db* tdbb, NodeCopier& copier);
+ virtual ValueExprNode* copy(thread_db* tdbb, NodeCopier& copier);
virtual void aggInit(thread_db* tdbb, jrd_req* request) const;
virtual void aggPass(thread_db* tdbb, jrd_req* request, dsc* desc) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request) const;
protected:
- virtual AggNode* dsqlCopy() const;
+ virtual AggNode* dsqlCopy(DsqlCompilerScratch* dsqlScratch) const;
};
class MaxMinAggNode : public AggNode
@@ -139,16 +139,16 @@
static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR blrOp);
- virtual void make(dsc* desc, dsql_nod* nullReplacement);
+ virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc, dsql_nod* nullReplacement);
virtual void getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc);
- virtual ExprNode* copy(thread_db* tdbb, NodeCopier& copier);
+ virtual ValueExprNode* copy(thread_db* tdbb, NodeCopier& copier);
virtual void aggInit(thread_db* tdbb, jrd_req* request) const;
virtual void aggPass(thread_db* tdbb, jrd_req* request, dsc* desc) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request) const;
protected:
- virtual AggNode* dsqlCopy() const;
+ virtual AggNode* dsqlCopy(DsqlCompilerScratch* dsqlScratch) const;
public:
const MaxMinType type;
Added: firebird/trunk/src/dsql/BoolNodes.cpp
===================================================================
--- firebird/trunk/src/dsql/BoolNodes.cpp (rev 0)
+++ firebird/trunk/src/dsql/BoolNodes.cpp 2010-09-17 03:15:32 UTC (rev 51564)
@@ -0,0 +1,1842 @@
+/*
+ * 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 - refactored from pass1.cpp, gen.cpp, cmp.cpp, par.cpp and evl.cpp
+ */
+
+#include "firebird.h"
+#include "../jrd/common.h"
+#include "../common/classes/VaryStr.h"
+#include "../dsql/BoolNodes.h"
+#include "../dsql/node.h"
+#include "../jrd/align.h"
+#include "../jrd/blr.h"
+#include "../jrd/quad.h"
+#include "../jrd/tra.h"
+#include "../jrd/recsrc/RecordSource.h"
+#include "../jrd/blb_proto.h"
+#include "../jrd/cmp_proto.h"
+#include "../jrd/evl_proto.h"
+#include "../jrd/intl_proto.h"
+#include "../jrd/mov_proto.h"
+#include "../jrd/par_proto.h"
+#include "../dsql/ddl_proto.h"
+#include "../dsql/errd_proto.h"
+#include "../dsql/gen_proto.h"
+#include "../dsql/make_proto.h"
+#include "../dsql/pass1_proto.h"
+
+using namespace Firebird;
+using namespace Jrd;
+
+#include "gen/blrtable.h"
+
+namespace Jrd {
+
+
+// Maximum members in "IN" list. For eg. SELECT * FROM T WHERE F IN (1, 2, 3, ...)
+// Bug 10061, bsriram - 19-Apr-1999
+static const int MAX_MEMBER_LIST = 1500;
+
+static const int TEMP_LENGTH = 128;
+
+
+//--------------------
+
+
+namespace
+{
+ // Copy sub expressions (including subqueries).
+ class SubExprNodeCopier : public NodeCopier
+ {
+ public:
+ explicit SubExprNodeCopier(CompilerScratch* aCsb)
+ : NodeCopier(aCsb, localMap)
+ {
+ // Initialize the map so all streams initially resolve to the original number. As soon
+ // copy creates new streams, the map are being overwritten.
+ for (unsigned i = 0; i < JrdStatement::MAP_LENGTH; ++i)
+ localMap[i] = i;
+ }
+
+ private:
+ UCHAR localMap[JrdStatement::MAP_LENGTH];
+ };
+} // namespace
+
+
+//--------------------
+
+
+static RegisterNode<BinaryBoolNode> regBinaryBoolNodeAnd(blr_and);
+static RegisterNode<BinaryBoolNode> regBinaryBoolNodeOr(blr_or);
+
+BinaryBoolNode::BinaryBoolNode(MemoryPool& pool, UCHAR aBlrOp, dsql_nod* aArg1, dsql_nod* aArg2)
+ : TypedNode<BoolExprNode, ExprNode::TYPE_BINARY_BOOL>(pool),
+ blrOp(aBlrOp),
+ dsqlArg1(aArg1),
+ dsqlArg2(aArg2),
+ arg1(NULL),
+ arg2(NULL)
+{
+ addChildNode(dsqlArg1, arg1);
+ addChildNode(dsqlArg2, arg2);
+}
+
+DmlNode* BinaryBoolNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR blrOp)
+{
+ BinaryBoolNode* node = FB_NEW(pool) BinaryBoolNode(pool, blrOp);
+ node->arg1 = PAR_parse_node(tdbb, csb, TYPE_BOOL);
+ node->arg2 = PAR_parse_node(tdbb, csb, TYPE_BOOL);
+ return node;
+}
+
+void BinaryBoolNode::print(string& text, Array<dsql_nod*>& nodes) const
+{
+ text.printf("BinaryBoolNode (%d)", blrOp);
+ ExprNode::print(text, nodes);
+}
+
+BoolExprNode* BinaryBoolNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
+{
+ return FB_NEW(getPool()) BinaryBoolNode(getPool(), blrOp,
+ PASS1_node(dsqlScratch, dsqlArg1), PASS1_node(dsqlScratch, dsqlArg2));
+}
+
+void BinaryBoolNode::genBlr(DsqlCompilerScratch* dsqlScratch)
+{
+ dsqlScratch->appendUChar(blrOp);
+ GEN_expr(dsqlScratch, dsqlArg1);
+ GEN_expr(dsqlScratch, dsqlArg2);
+}
+
+bool BinaryBoolNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const
+{
+ if (!BoolExprNode::dsqlMatch(other, ignoreMapCast))
+ return false;
+
+ const BinaryBoolNode* o = other->as<BinaryBoolNode>();
+ fb_assert(o)
+
+ return blrOp == o->blrOp;
+}
+
+BoolExprNode* BinaryBoolNode::copy(thread_db* tdbb, NodeCopier& copier)
+{
+ BinaryBoolNode* node = FB_NEW(*tdbb->getDefaultPool()) BinaryBoolNode(*tdbb->getDefaultPool(),
+ blrOp);
+ node->arg1 = copier.copy(tdbb, arg1);
+ node->arg2 = copier.copy(tdbb, arg2);
+ return node;
+}
+
+bool BinaryBoolNode::execute(thread_db* tdbb, jrd_req* request) const
+{
+ switch (blrOp)
+ {
+ case blr_and:
+ return executeAnd(tdbb, request);
+
+ case blr_or:
+ return executeOr(tdbb, request);
+ }
+
+ fb_assert(false);
+ return false;
+}
+
+bool BinaryBoolNode::executeAnd(thread_db* tdbb, jrd_req* request) const
+{
+ // If either operand is false, then the result is false;
+ // If both are true, the result is true;
+ // Otherwise, the result is NULL.
+ //
+ // op 1 op 2 result
+ // ---- ---- ------
+ // F F F
+ // F T F
+ // F N F
+ // T F F
+ // T T T
+ // T N N
+ // N F F
+ // N T N
+ // N N N
+
+ const bool value1 = EVL_boolean(tdbb, arg1);
+
+ // Save null state and get other operand.
+ const USHORT firstnull = request->req_flags & req_null;
+ request->req_flags &= ~req_null;
+
+ if (!value1 && !firstnull)
+ {
+ // First term is false, why the whole expression is false.
+ // NULL flag is already turned off a few lines above.
+ return false;
+ }
+
+ const bool value2 = EVL_boolean(tdbb, arg2);
+ const USHORT secondnull = request->req_flags & req_null;
+ request->req_flags &= ~req_null;
+
+ if ((!value1 && !firstnull) || (!value2 && !secondnull))
+ return false; // at least one operand was false
+
+ if (value1 && value2)
+ return true; // both true
+
+ // otherwise, return null
+ request->req_flags |= req_null;
+ return false;
+}
+
+bool BinaryBoolNode::executeOr(thread_db* tdbb, jrd_req* request) const
+{
+ // If either operand is true, then the result is true;
+ // If both are false, the result is false;
+ // Otherwise, the result is NULL.
+ //
+ // op 1 op 2 result
+ // ---- ---- ------
+ // F F F
+ // F T T
+ // F N N
+ // T F T
+ // T T T
+ // T N T
+ // N F N
+ // N T T
+ // N N N
+ //
+ // Also, preserve first operand's value and null state, but still
+ // evaluate second operand, since latter field mappings may
+ // depend on the evaluation.
+
+ const bool value1 = EVL_boolean(tdbb, arg1);
+
+ const ULONG flags = request->req_flags;
+ request->req_flags &= ~req_null;
+
+ if (value1)
+ {
+ // First term is true, why the whole expression is true.
+ // NULL flag is already turned off a few lines above.
+ return true;
+ }
+
+ const bool value2 = EVL_boolean(tdbb, arg2);
+
+ if (value1 || value2)
+ {
+ request->req_flags &= ~req_null;
+ return true;
+ }
+
+ // restore saved NULL state
+
+ if (flags & req_null)
+ request->req_flags |= req_null;
+
+ return false;
+}
+
+
+//--------------------
+
+
+static RegisterNode<ComparativeBoolNode> regComparativeBoolNodeEql(blr_eql);
+static RegisterNode<ComparativeBoolNode> regComparativeBoolNodeGeq(blr_geq);
+static RegisterNode<ComparativeBoolNode> regComparativeBoolNodeGtr(blr_gtr);
+static RegisterNode<ComparativeBoolNode> regComparativeBoolNodeLeq(blr_leq);
+static RegisterNode<ComparativeBoolNode> regComparativeBoolNodeLss(blr_lss);
+static RegisterNode<ComparativeBoolNode> regComparativeBoolNodeNeq(blr_neq);
+static RegisterNode<ComparativeBoolNode> regComparativeBoolNodeEquiv(blr_equiv);
+static RegisterNode<ComparativeBoolNode> regComparativeBoolNodeBetween(blr_between);
+static RegisterNode<ComparativeBoolNode> regComparativeBoolNodeLike(blr_like);
+static RegisterNode<ComparativeBoolNode> regComparativeBoolNodeAnsiLike(blr_ansi_like);
+static RegisterNode<ComparativeBoolNode> regComparativeBoolNodeContaining(blr_containing);
+static RegisterNode<ComparativeBoolNode> regComparativeBoolNodeStarting(blr_starting);
+static RegisterNode<ComparativeBoolNode> regComparativeBoolNodeSimilar(blr_similar);
+static RegisterNode<ComparativeBoolNode> regComparativeBoolNodeMatching(blr_matching);
+static RegisterNode<ComparativeBoolNode> regComparativeBoolNodeMatching2(blr_matching2); // sleuth
+
+ComparativeBoolNode::ComparativeBoolNode(MemoryPool& pool, UCHAR aBlrOp,
+ dsql_nod* aArg1, dsql_nod* aArg2, dsql_nod* aArg3)
+ : TypedNode<BoolExprNode, ExprNode::TYPE_COMPARATIVE_BOOL>(pool),
+ blrOp(aBlrOp),
+ dsqlArg1(aArg1),
+ dsqlArg2(aArg2),
+ dsqlArg3(aArg3),
+ dsqlFlag(DFLAG_NONE),
+ arg1(NULL),
+ arg2(NULL),
+ arg3(NULL)
+{
+ addChildNode(dsqlArg1, arg1);
+ addChildNode(dsqlArg2, arg2);
+ addChildNode(dsqlArg3, arg3);
+}
+
+DmlNode* ComparativeBoolNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR blrOp)
+{
+ ComparativeBoolNode* node = FB_NEW(pool) ComparativeBoolNode(pool, blrOp);
+
+ node->arg1 = PAR_parse_node(tdbb, csb, VALUE);
+ node->arg2 = PAR_parse_node(tdbb, csb, VALUE);
+
+ if (blrOp == blr_between || blrOp == blr_ansi_like || blrOp == blr_matching2)
+ {
+ if (blrOp == blr_ansi_like)
+ blrOp = blr_like;
+
+ node->arg3 = PAR_parse_node(tdbb, csb, VALUE);
+ }
+ else if (blrOp == blr_similar)
+ {
+ if (csb->csb_blr_reader.getByte() != 0)
+ node->arg3 = PAR_parse_node(tdbb, csb, VALUE); // escape
+ }
+
+ return node;
+}
+
+void ComparativeBoolNode::print(string& text, Array<dsql_nod*>& nodes) const
+{
+ text.printf("ComparativeBoolNode (%d)", blrOp);
+ ExprNode::print(text, nodes);
+}
+
+BoolExprNode* ComparativeBoolNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
+{
+ switch (blrOp)
+ {
+ case blr_eql:
+ case blr_neq:
+ case blr_gtr:
+ case blr_geq:
+ case blr_lss:
+ case blr_leq:
+ if (dsqlArg2->nod_type == Dsql::nod_list)
+ {
+ int listItemCount = 0;
+ BoolExprNode* resultNode = NULL;
+ dsql_nod** ptr = dsqlArg2->nod_arg;
+
+ for (const dsql_nod* const* const end = ptr + dsqlArg2->nod_count;
+ ptr != end; ++listItemCount, ++ptr)
+ {
+ if (listItemCount >= MAX_MEMBER_LIST)
+ {
+ ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-901) <<
+ Arg::Gds(isc_imp_exc) <<
+ Arg::Gds(isc_dsql_too_many_values) << Arg::Num(MAX_MEMBER_LIST));
+ }
+
+ DEV_BLKCHK(*ptr, dsql_type_nod);
+
+ ComparativeBoolNode* temp = FB_NEW(getPool()) ComparativeBoolNode(getPool(),
+ blrOp, dsqlArg1, *ptr);
+
+ if (resultNode)
+ {
+ dsql_nod* tempNod = MAKE_node(Dsql::nod_class_exprnode, 1);
+ tempNod->nod_arg[0] = reinterpret_cast<dsql_nod*>(temp);
+
+ dsql_nod* resultNod = MAKE_node(Dsql::nod_class_exprnode, 1);
+ resultNod->nod_arg[0] = reinterpret_cast<dsql_nod*>(resultNode);
+
+ BinaryBoolNode* binaryNode = FB_NEW(getPool()) BinaryBoolNode(getPool(),
+ blr_or, resultNod, tempNod);
+
+ resultNode = binaryNode;
+ }
+ else
+ resultNode = temp;
+ }
+
+ return resultNode->dsqlPass(dsqlScratch);
+ }
+
+ if (dsqlArg2->nod_type == Dsql::nod_select_expr &&
+ !(dsqlArg2->nod_flags & NOD_SELECT_EXPR_SINGLETON))
+ {
+ UCHAR newBlrOp = blr_any;
+
+ if (dsqlFlag == DFLAG_ANSI_ANY)
+ newBlrOp = blr_ansi_any;
+ else if (dsqlFlag == DFLAG_ANSI_ALL)
+ newBlrOp = blr_ansi_all;
+
+ return createRseNode(dsqlScratch, newBlrOp);
+ }
+
+ break;
+ }
+
+ ComparativeBoolNode* node = FB_NEW(getPool()) ComparativeBoolNode(getPool(), blrOp,
+ PASS1_node(dsqlScratch, dsqlArg1), PASS1_node(dsqlScratch, dsqlArg2),
+ PASS1_node(dsqlScratch, dsqlArg3));
+
+ switch (blrOp)
+ {
+ case blr_eql:
+ case blr_neq:
+ case blr_gtr:
+ case blr_geq:
+ case blr_lss:
+ case blr_leq:
+ case blr_equiv:
+ case blr_between:
+ // Try to force arg1 to be same type as arg2 eg: ? = FIELD case
+ PASS1_set_parameter_type(dsqlScratch, node->dsqlArg1, node->dsqlArg2, false);
+
+ // Try to force arg2 to be same type as arg1 eg: FIELD = ? case
+ // Try even when the above call succeeded, because "arg2" may
+ // have arg-expressions that should be resolved.
+ PASS1_set_parameter_type(dsqlScratch, node->dsqlArg2, node->dsqlArg1, false);
+
+ // X BETWEEN Y AND ? case
+ if (!PASS1_set_parameter_type(dsqlScratch, node->dsqlArg3, node->dsqlArg1, false))
+ {
+ // ? BETWEEN Y AND ? case
+ PASS1_set_parameter_type(dsqlScratch, node->dsqlArg3, node->dsqlArg2, false);
+ }
+ break;
+
+ case blr_containing:
+ case blr_like:
+ case blr_similar:
+ case blr_starting:
+ // Try to force arg1 to be same type as arg2 eg: ? LIKE FIELD case
+ PASS1_set_parameter_type(dsqlScratch, node->dsqlArg1, node->dsqlArg2, true);
+
+ // Try to force arg2 same type as arg 1 eg: FIELD LIKE ? case
+ // Try even when the above call succeeded, because "arg2" may
+ // have arg-expressions that should be resolved.
+ PASS1_set_parameter_type(dsqlScratch, node->dsqlArg2, node->dsqlArg1, true);
+
+ // X LIKE Y ESCAPE ? case
+ PASS1_set_parameter_type(dsqlScratch, node->dsqlArg3, node->dsqlArg2, true);
+ }
+
+ return node;
+}
+
+void ComparativeBoolNode::genBlr(DsqlCompilerScratch* dsqlScratch)
+{
+ dsqlScratch->appendUChar(blrOp == blr_like && dsqlArg3 ? blr_ansi_like : blrOp);
+
+ GEN_expr(dsqlScratch, dsqlArg1);
+ GEN_expr(dsqlScratch, dsqlArg2);
+
+ if (blrOp == blr_similar)
+ dsqlScratch->appendUChar(dsqlArg3 ? 1 : 0);
+
+ if (dsqlArg3)
+ GEN_expr(dsqlScratch, dsqlArg3);
+}
+
+bool ComparativeBoolNode::dsqlMatch(const ExprNode* other, bool ignoreMapCast) const
+{
+ if (!BoolExprNode::dsqlMatch(other, ignoreMapCast))
+ return false;
+
+ const ComparativeBoolNode* o = other->as<ComparativeBoolNode>();
+ fb_assert(o)
+
+ return dsqlFlag == o->dsqlFlag && blrOp == o->blrOp;
+}
+
+BoolExprNode* ComparativeBoolNode::copy(thread_db* tdbb, NodeCopier& copier)
+{
+ ComparativeBoolNode* node = FB_NEW(*tdbb->getDefaultPool()) ComparativeBoolNode(
+ *tdbb->getDefaultPool(), blrOp);
+ node->arg1 = copier.copy(tdbb, arg1);
+ node->arg2 = copier.copy(tdbb, arg2);
+
+ if (arg3)
+ node->arg3 = copier.copy(tdbb, arg3);
+
+ return node;
+}
+
+ExprNode* ComparativeBoolNode::pass1(thread_db* tdbb, CompilerScratch* csb)
+{
+ bool invariantCheck = false;
+
+ switch (blrOp)
+ {
+ case blr_eql:
+ case blr_equiv:
+ case blr_gtr:
+ case blr_geq:
+ case blr_lss:
+ case blr_leq:
+ case blr_neq:
+ case blr_between:
+ node->nod_flags |= nod_comparison;
+ break;
+
+ case blr_like:
+ case blr_similar:
+ case blr_containing:
+ case blr_starting:
+ invariantCheck = true;
+ break;
+ }
+
+ arg1 = CMP_pass1(tdbb, csb, arg1);
+
+ if (invariantCheck)
+ {
+ // We need to take care of invariantness expressions to be able to pre-compile the pattern.
+ node->nod_flags |= nod_invariant;
+ csb->csb_current_nodes.push(node.getObject());
+ }
+
+ arg2 = CMP_pass1(tdbb, csb, arg2);
+
+ if (arg3)
+ arg3 = CMP_pass1(tdbb, csb, arg3);
+
+ if (invariantCheck)
+ {
+ csb->csb_current_nodes.pop();
+
+ // If there is no top-level RSE present and patterns are not constant, unmark node as invariant
+ // because it may be dependent on data or variables.
+ if ((node->nod_flags & nod_invariant) &&
+ (arg2->nod_type != nod_literal || (arg3 && arg3->nod_type != nod_literal)))
+ {
+ const LegacyNodeOrRseNode* ctx_node, *end;
+ for (ctx_node = csb->csb_current_nodes.begin(), end = csb->csb_current_nodes.end();
+ ctx_node != end; ++ctx_node)
+ {
+ if (ctx_node->rseNode)
+ break;
+ }
+
+ if (ctx_node >= end)
+ node->nod_flags &= ~nod_invariant;
+ }
+ }
+
+ return this;
+}
+
+ExprNode* ComparativeBoolNode::pass2(thread_db* tdbb, CompilerScratch* csb)
+{
+ if (node->nod_flags & nod_invariant)
+ csb->csb_invariants.push(node);
+
+ ExprNode::pass2(tdbb, csb);
+
+ if (arg3)
+ {
+ if (arg3->nod_flags & nod_agg_dbkey)
+ ERR_post(Arg::Gds(isc_bad_dbkey));
+
+ dsc descriptor_c;
+ CMP_get_desc(tdbb, csb, arg1, &descriptor_c);
+
+ if (DTYPE_IS_DATE(descriptor_c.dsc_dtype))
+ {
+ arg1->nod_flags |= nod_date;
+ arg2->nod_flags |= nod_date;
+ }
+ }
+
+ if ((arg1->nod_flags & nod_agg_dbkey) || (arg2->nod_flags & nod_agg_dbkey))
+ ERR_post(Arg::Gds(isc_bad_dbkey));
+
+ dsc descriptor_a, descriptor_b;
+ CMP_get_desc(tdbb, csb, arg1, &descriptor_a);
+ CMP_get_desc(tdbb, csb, arg2, &descriptor_b);
+
+ if (DTYPE_IS_DATE(descriptor_a.dsc_dtype))
+ arg2->nod_flags |= nod_date;
+ else if (DTYPE_IS_DATE(descriptor_b.dsc_dtype))
+ arg1->nod_flags |= nod_date;
+
+ if (node->nod_flags & nod_invariant)
+ {
+ // This may currently happen for nod_like, nod_contains and nod_similar
+ csb->csb_impure += sizeof(impure_value);
+ }
+
+ return this;
+}
+
+bool ComparativeBoolNode::execute(thread_db* tdbb, jrd_req* request) const
+{
+ dsc* desc[2] = {NULL, NULL};
+ SSHORT comparison;
+ bool computed_invariant = false;
+
+ request->req_flags &= ~req_same_tx_upd;
+ SSHORT force_equal = 0;
+
+ // Evaluate arguments. If either is null, result is null, but in
+ // any case, evaluate both, since some expressions may later depend
+ // on mappings which are developed here
+
+ const jrd_nod* rec_version = arg1;
+ desc[0] = EVL_expr(tdbb, arg1);
+ const ULONG flags = request->req_flags;
+ request->req_flags &= ~req_null;
+ force_equal |= request->req_flags & req_same_tx_upd;
+
+ // Currently only nod_like, nod_contains, nod_starts and nod_similar may be marked invariant
+ if (node->nod_flags & nod_invariant)
+ {
+ impure_value* impure = request->getImpure<impure_value>(node->nod_impure);
+
+ // Check that data type of operand is still the same.
+ // It may change due to multiple formats present in stream
+ // System tables are the good example of such streams -
+ // data coming from ini.epp has ASCII ttype, user data is UNICODE_FSS
+ //
+ // Note that value descriptor may be NULL pointer if value is SQL NULL
+ if ((impure->vlu_flags & VLU_computed) && desc[0] &&
+ (impure->vlu_desc.dsc_dtype != desc[0]->dsc_dtype ||
+ impure->vlu_desc.dsc_sub_type != desc[0]->dsc_sub_type ||
+ impure->vlu_desc.dsc_scale != desc[0]->dsc_scale))
+ {
+ impure->vlu_flags &= ~VLU_computed;
+ }
+
+ if (impure->vlu_flags & VLU_computed)
+ {
+ if (impure->vlu_flags & VLU_null)
+ request->req_flags |= req_null;
+ else
+ computed_invariant = true;
+ }
+ else
+ {
+ desc[1] = EVL_expr(tdbb, arg2);
+
+ if (request->req_flags & req_null)
+ {
+ impure->vlu_flags |= VLU_computed;
+ impure->vlu_flags |= VLU_null;
+ }
+ else
+ {
+ impure->vlu_flags &= ~VLU_null;
+
+ // Search object depends on operand data type.
+ // Thus save data type which we use to compute invariant
+ if (desc[0])
+ {
+ impure->vlu_desc.dsc_dtype = desc[0]->dsc_dtype;
+ impure->vlu_desc.dsc_sub_type = desc[0]->dsc_sub_type;
+ impure->vlu_desc.dsc_scale = desc[0]->dsc_scale;
+ }
+ else
+ {
+ // Indicate we do not know type of expression.
+ // This code will force pattern recompile for the next non-null value
+ impure->vlu_desc.dsc_dtype = 0;
+ impure->vlu_desc.dsc_sub_type = 0;
+ impure->vlu_desc.dsc_scale = 0;
+ }
+ }
+ }
+ }
+ else
+ desc[1] = EVL_expr(tdbb, arg2);
+
+ // An equivalence operator evaluates to true when both operands
+ // are NULL and behaves like an equality operator otherwise.
+ // Note that this operator never sets req_null flag
+
+ if (blrOp == blr_equiv)
+ {
+ if ((flags & req_null) && (request->req_flags & req_null))
+ {
+ request->req_flags &= ~req_null;
+ return true;
+ }
+
+ if ((flags & req_null) || (request->req_flags & req_null))
+ {
+ request->req_flags &= ~req_null;
+ return false;
+ }
+ }
+
+ // If either of expressions above returned NULL set req_null flag
+ // and return false
+
+ if (flags & req_null)
+ request->req_flags |= req_null;
+
+ if (request->req_flags & req_null)
+ return false;
+
+ force_equal |= request->req_flags & req_same_tx_upd;
+
+ if (node->nod_flags & nod_comparison)
+ comparison = MOV_compare(desc[0], desc[1]);
+
+ // If we are checking equality of record_version
+ // and same transaction updated the record, force equality.
+
+ if (rec_version->nod_type == nod_rec_version && force_equal)
+ comparison = 0;
+
+ request->req_flags &= ~(req_null | req_same_tx_upd);
+
+ switch (blrOp)
+ {
+ case blr_eql:
+ case blr_equiv:
+ return comparison == 0;
+
+ case blr_gtr:
+ return comparison > 0;
+
+ case blr_geq:
+ return comparison >= 0;
+
+ case blr_lss:
+ return comparison < 0;
+
+ case blr_leq:
+ return comparison <= 0;
+
+ case blr_neq:
+ return comparison != 0;
+
+ case blr_between:
+ desc[1] = EVL_expr(tdbb, arg3);
+ if (request->req_flags & req_null)
+ return false;
+ return comparison >= 0 && MOV_compare(desc[0], desc[1]) <= 0;
+
+ case blr_containing:
+ case blr_starting:
+ case blr_matching:
+ case blr_like:
+ case blr_similar:
+ return stringBoolean(tdbb, request, desc[0], desc[1], computed_invariant);
+
+ case blr_matching2:
+ return sleuth(tdbb, request, desc[0], desc[1]);
+ }
+
+ return false;
+}
+
+// Perform one of the complex string functions CONTAINING, MATCHES, or STARTS WITH.
+bool ComparativeBoolNode::stringBoolean(thread_db* tdbb, jrd_req* request, dsc* desc1,
+ dsc* desc2, bool computed_invariant) const
+{
+ UCHAR* p1 = NULL;
+ UCHAR* p2 = NULL;
+ SLONG l2 = 0;
+ USHORT type1;
+ MoveBuffer match_str;
+
+ SET_TDBB(tdbb);
+
+ if (!desc1->isBlob())
+ {
+ // Source is not a blob, do a simple search
+
+ // Get text type of data string
+
+ type1 = INTL_TEXT_TYPE(*desc1);
+
+ // Get address and length of search string - convert to datatype of data
+
+ if (!computed_invariant)
+ l2 = MOV_make_string2(tdbb, desc2, type1, &p2, match_str);
+
+ VaryStr<256> temp1;
+ USHORT xtype1;
+ const USHORT l1 = MOV_get_string_ptr(desc1, &xtype1, &p1, &temp1, sizeof(temp1));
+
+ fb_assert(xtype1 == type1);
+
+ return stringFunction(tdbb, request, l1, p1, l2, p2, type1, computed_invariant);
+ }
+
+ // Source string is a blob, things get interesting
+
+ HalfStaticArray<UCHAR, BUFFER_SMALL> buffer;
+
+ if (desc1->dsc_sub_type == isc_blob_text)
+ type1 = desc1->dsc_blob_ttype(); // pick up character set and collation of blob
+ else
+ type1 = ttype_none; // Do byte matching
+
+ Collation* obj = INTL_texttype_lookup(tdbb, type1);
+ CharSet* charset = obj->getCharSet();
+
+ // Get address and length of search string - make it string if necessary
+ // but don't transliterate character set if the source blob is binary
+ VaryStr<256> temp2;
+ if (!computed_invariant)
+ {
+ if (type1 == ttype_none)
+ l2 = MOV_get_string(desc2, &p2, &temp2, sizeof(temp2));
+ else
+ l2 = MOV_make_string2(tdbb, desc2, type1, &p2, match_str);
+ }
+
+ blb* blob = BLB_open(tdbb, request->req_transaction, reinterpret_cast<bid*>(desc1->dsc_address));
+
+ if (charset->isMultiByte() &&
+ (blrOp != blr_starting || !(obj->getFlags() & TEXTTYPE_DIRECT_MATCH)))
+ {
+ buffer.getBuffer(blob->blb_length); // alloc space to put entire blob in memory
+ }
+
+ // Performs the string_function on each segment of the blob until
+ // a positive result is obtained
+
+ bool ret_val = false;
+
+ switch (blrOp)
+ {
+ case blr_like:
+ case blr_similar:
+ {
+ VaryStr<TEMP_LENGTH> temp3;
+ const UCHAR* escape_str = NULL;
+ USHORT escape_length = 0;
+
+ // ensure 3rd argument (escape char) is in operation text type
+ if (arg3 && !computed_invariant)
+ {
+ // Convert ESCAPE to operation character set
+ dsc* desc = EVL_expr(tdbb, arg3);
+
+ if (request->req_flags & req_null)
+ {
+ if (node->nod_flags & nod_invariant)
+ {
+ impure_value* impure = request->getImpure<impure_value>(node->nod_impure);
+ impure->vlu_flags |= VLU_computed;
+ impure->vlu_flags |= VLU_null;
+ }
+ ret_val = false;
+ break;
+ }
+
+ escape_length = MOV_make_string(desc, type1,
+ reinterpret_cast<const char**>(&escape_str), &temp3, sizeof(temp3));
+
+ if (!escape_length || charset->length(escape_length, escape_str, true) != 1)
+ {
+ // If characters left, or null byte character, return error
+ BLB_close(tdbb, blob);
+ ERR_post(Arg::Gds(isc_escape_invalid));
+ }
+
+ USHORT escape[2] = {0, 0};
+
+ charset->getConvToUnicode().convert(escape_length, escape_str, sizeof(escape), escape);
+ if (!escape[0])
+ {
+ // If or null byte character, return error
+ BLB_close(tdbb, blob);
+ ERR_post(Arg::Gds(isc_escape_invalid));
+ }
+ }
+
+ PatternMatcher* evaluator;
+
+ if (node->nod_flags & nod_invariant)
+ {
+ impure_value* impure = request->getImpure<impure_value>(node->nod_impure);
+
+ if (!(impure->vlu_flags & VLU_computed))
+ {
+ delete impure->vlu_misc.vlu_invariant;
+ impure->vlu_flags |= VLU_computed;
+
+ if (blrOp == blr_like)
+ {
+ impure->vlu_misc.vlu_invariant = evaluator = obj->createLikeMatcher(
+ *tdbb->getDefaultPool(), p2, l2, escape_str, escape_length);
+ }
+ else // nod_similar
+ {
+ impure->vlu_misc.vlu_invariant = evaluator = obj->createSimilarToMatcher(
+ *tdbb->getDefaultPool(), p2, l2, escape_str, escape_length, false);
+ }
+ }
+ else
+ {
+ evaluator = impure->vlu_misc.vlu_invariant;
+ evaluator->reset();
+ }
+ }
+ else if (blrOp == blr_like)
+ {
+ evaluator = obj->createLikeMatcher(*tdbb->getDefaultPool(),
+ p2, l2, escape_str, escape_length);
+ }
+ else // nod_similar
+ {
+ evaluator = obj->createSimilarToMatcher(*tdbb->getDefaultPool(),
+ p2, l2, escape_str, escape_length, false);
+ }
+
+ while (!(blob->blb_flags & BLB_eof))
+ {
+ const SLONG l1 = BLB_get_data(tdbb, blob, buffer.begin(), buffer.getCapacity(), false);
+ if (!evaluator->process(buffer.begin(), l1))
+ break;
+ }
+
+ ret_val = evaluator->result();
+
+ if (!(node->nod_flags & nod_invariant))
+ delete evaluator;
+
+ break;
+ }
+
+ case blr_containing:
+ case blr_starting:
+ {
+ PatternMatcher* evaluator;
+
+ if (node->nod_flags & nod_invariant)
+ {
+ impure_value* impure = request->getImpure<impure_value>(node->nod_impure);
+ if (!(impure->vlu_flags & VLU_computed))
+ {
+ delete impure->vlu_misc.vlu_invariant;
+
+ if (blrOp == blr_containing)
+ {
+ impure->vlu_misc.vlu_invariant = evaluator =
+ obj->createContainsMatcher(*tdbb->getDefaultPool(), p2, l2);
+ }
+ else // nod_starts
+ {
+ impure->vlu_misc.vlu_invariant = evaluator =
+ obj->createStartsMatcher(*tdbb->getDefaultPool(), p2, l2);
+ }
+
+ impure->vlu_flags |= VLU_computed;
+ }
+ else
+ {
+ evaluator = impure->vlu_misc.vlu_invariant;
+ evaluator->reset();
+ }
+ }
+ else
+ {
+ if (blrOp == blr_containing)
+ evaluator = obj->createContainsMatcher(*tdbb->getDefaultPool(), p2, l2);
+ else // nod_starts
+ evaluator = obj->createStartsMatcher(*tdbb->getDefaultPool(), p2, l2);
+ }
+
+ while (!(blob->blb_flags & BLB_eof))
+ {
+ const SLONG l1 = BLB_get_data(tdbb, blob, buffer.begin(), buffer.getCapacity(), false);
+ if (!evaluator->process(buffer.begin(), l1))
+ break;
+ }
+
+ ret_val = evaluator->result();
+
+ if (!(node->nod_flags & nod_invariant))
+ delete evaluator;
+
+ break;
+ }
+ }
+
+ BLB_close(tdbb, blob);
+
+ return ret_val;
+}
+
+// Perform one of the pattern matching string functions.
+bool ComparativeBoolNode::stringFunction(thread_db* tdbb, jrd_req* request,
+ SLONG l1, const UCHAR* p1, SLONG l2, const UCHAR* p2, USHORT ttype,
+ bool computed_invariant) const
+{
+ SET_TDBB(tdbb);
+
+ Collation* obj = INTL_texttype_lookup(tdbb, ttype);
+ CharSet* charset = obj->getCharSet();
+
+ // Handle contains and starts
+ if (blrOp == blr_containing || blrOp == blr_starting)
+ {
+ if (node->nod_flags & nod_invariant)
+ {
+ impure_value* impure = request->getImpure<impure_value>(node->nod_impure);
+ PatternMatcher* evaluator;
+ if (!(impure->vlu_flags & VLU_computed))
+ {
+ delete impure->vlu_misc.vlu_invariant;
+
+ if (blrOp == blr_containing)
+ {
+ impure->vlu_misc.vlu_invariant = evaluator =
+ obj->createContainsMatcher(*tdbb->getDefaultPool(), p2, l2);
+ }
+ else
+ {
+ // nod_starts
+ impure->vlu_misc.vlu_invariant = evaluator =
+ obj->createStartsMatcher(*tdbb->getDefaultPool(), p2, l2);
+ }
+
+ impure->vlu_flags |= VLU_computed;
+ }
+ else
+ {
+ evaluator = impure->vlu_misc.vlu_invariant;
+ evaluator->reset();
+ }
+
+ evaluator->process(p1, l1);
+ return evaluator->result();
+ }
+
+ if (blrOp == blr_containing)
+ return obj->contains(*tdbb->getDefaultPool(), p1, l1, p2, l2);
+
+ // nod_starts
+ return obj->starts(*tdbb->getDefaultPool(), p1, l1, p2, l2);
+ }
+
+ // Handle LIKE and SIMILAR
+ if (blrOp == blr_like || blrOp == blr_similar)
+ {
+ VaryStr<TEMP_LENGTH> temp3;
+ const UCHAR* escape_str = NULL;
+ USHORT escape_length = 0;
+ // ensure 3rd argument (escape char) is in operation text type
+ if (arg3 && !computed_invariant)
+ {
+ // Convert ESCAPE to operation character set
+ dsc* desc = EVL_expr(tdbb, arg3);
+ if (request->req_flags & req_null)
+ {
+ if (node->nod_flags & nod_invariant)
+ {
+ impure_value* impure = request->getImpure<impure_value>(node->nod_impure);
+ impure->vlu_flags |= VLU_computed;
+ impure->vlu_flags |= VLU_null;
+ }
+ return false;
+ }
+
+ escape_length = MOV_make_string(desc, ttype,
+ reinterpret_cast<const char**>(&escape_str), &temp3, sizeof(temp3));
+
+ if (!escape_length || charset->length(escape_length, escape_str, true) != 1)
+ {
+ // If characters left, or null byte character, return error
+ ERR_post(Arg::Gds(isc_escape_invalid));
+ }
+
+ USHORT escape[2] = {0, 0};
+
+ charset->getConvToUnicode().convert(escape_length, escape_str, sizeof(escape), escape);
+
+ if (!escape[0])
+ {
+ // If or null byte character, return error
+ ERR_post(Arg::Gds(isc_escape_invalid));
+ }
+ }
+
+ if (node->nod_flags & nod_invariant)
+ {
+ impure_value* impure = request->getImpure<impure_value>(node->nod_impure);
+ PatternMatcher* evaluator;
+
+ if (!(impure->vlu_flags & VLU_computed))
+ {
+ delete impure->vlu_misc.vlu_invariant;
+ impure->vlu_flags |= VLU_computed;
+
+ if (blrOp == blr_like)
+ {
+ impure->vlu_misc.vlu_invariant = evaluator = obj->createLikeMatcher(
+ *tdbb->getDefaultPool(), p2, l2, escape_str, escape_length);
+ }
+ else // nod_similar
+ {
+ impure->vlu_misc.vlu_invariant = evaluator = obj->createSimilarToMatcher(
+ *tdbb->getDefaultPool(), p2, l2, escape_str, escape_length, false);
+ }
+ }
+ else
+ {
+ evaluator = impure->vlu_misc.vlu_invariant;
+ evaluator->reset();
+ }
+
+ evaluator->process(p1, l1);
+
+ return evaluator->result();
+ }
+
+ if (blrOp == blr_like)
+ return obj->like(*tdbb->getDefaultPool(), p1, l1, p2, l2, escape_str, escape_length);
+
+ // nod_similar
+ return obj->similarTo(*tdbb->getDefaultPool(), p1, l1, p2, l2, escape_str,
+ escape_length, false);
+ }
+
+ // Handle MATCHES
+ return obj->matches(*tdbb->getDefaultPool(), p1, l1, p2, l2);
+}
+
+// Execute SLEUTH operator.
+bool ComparativeBoolNode::sleuth(thread_db* tdbb, jrd_req* request, const dsc* desc1,
+ const dsc* desc2) const
+{
+ SET_TDBB(tdbb);
+
+ // Choose interpretation for the operation
+
+ USHORT ttype;
+ if (desc1->isBlob())
+ {
+ if (desc1->dsc_sub_type == isc_blob_text)
+ ttype = desc1->dsc_blob_ttype(); // Load blob character set and collation
+ else
+ ttype = INTL_TTYPE(desc2);
+ }
+ else
+ ttype = INTL_TTYPE(desc1);
+
+ Collation* obj = INTL_texttype_lookup(tdbb, ttype);
+
+ // Get operator definition string (control string)
+
+ dsc* desc3 = EVL_expr(tdbb, arg3);
+
+ UCHAR* p1;
+ MoveBuffer sleuth_str;
+ USHORT l1 = MOV_make_string2(tdbb, desc3, ttype, &p1, sleuth_str);
+ // Get address and length of search string
+ UCHAR* p2;
+ MoveBuffer match_str;
+ USHORT l2 = MOV_make_string2(tdbb, desc2, ttype, &p2, match_str);
+
+ // Merge search and control strings
+ UCHAR control[BUFFER_SMALL];
+ SLONG control_length = obj->sleuthMerge(*tdbb->getDefaultPool(), p2, l2, p1, l1, control); //, BUFFER_SMALL);
+
+ // Note: resulting string from sleuthMerge is either USHORT or UCHAR
+ // and never Multibyte (see note in EVL_mb_sleuthCheck)
+ bool ret_val;
+ MoveBuffer data_str;
+ if (!desc1->isBlob())
+ {
+ // Source is not a blob, do a simple search
+
+ l1 = MOV_make_string2(tdbb, desc1, ttype, &p1, data_str);
+ ret_val = obj->sleuthCheck(*tdbb->getDefaultPool(), 0, p1, l1, control, control_length);
+ }
+ else
+ {
+ // Source string is a blob, things get interesting
+
+ blb* blob = BLB_open(tdbb, request->req_transaction,
+ reinterpret_cast<bid*>(desc1->dsc_address));
+
+ UCHAR buffer[BUFFER_LARGE];
+ ret_val = false;
+
+ while (!(blob->blb_flags & BLB_eof))
+ {
+ l1 = BLB_get_segment(tdbb, blob, buffer, sizeof(buffer));
+ if (obj->sleuthCheck(*tdbb->getDefaultPool(), 0, buffer, l1, control, control_length))
+ {
+ ret_val = true;
+ break;
+ }
+ }
+
+ BLB_close(tdbb, blob);
+ }
+
+ return ret_val;
+}
+
+BoolExprNode* ComparativeBoolNode::createRseNode(DsqlCompilerScratch* dsqlScratch, UCHAR rseBlrOp)
+{
+ PASS1_set_parameter_type(dsqlScratch, dsqlArg1, dsqlArg2, false);
+
+ // create a derived table representing our subquery
+ dsql_nod* dt = MAKE_node(Dsql::nod_derived_table, Dsql::e_derived_table_count);
+ // Ignore validation for columnames that must exist for "user" derived tables.
+ dt->nod_flags |= NOD_DT_IGNORE_COLUMN_CHECK;
+ dt->nod_arg[Dsql::e_derived_table_rse] = dsqlArg2;
+ dsql_nod* from = MAKE_node(Dsql::nod_list, 1);
+ from->nod_arg[0] = dt;
+ dsql_nod* query_spec = MAKE_node(Dsql::nod_query_spec, Dsql::e_qry_count);
+ query_spec->nod_arg[Dsql::e_qry_from] = from;
+ dsql_nod* select_expr = MAKE_node(Dsql::nod_select_expr, Dsql::e_sel_count);
+ select_expr->nod_arg[Dsql::e_sel_query_spec] = query_spec;
+
+ const DsqlContextStack::iterator base(*dsqlScratch->context);
+ const DsqlContextStack::iterator baseDT(dsqlScratch->derivedContext);
+ const DsqlContextStack::iterator baseUnion(dsqlScratch->unionContext);
+
+ dsql_nod* rse = PASS1_rse(dsqlScratch, select_expr, NULL);
+
+ // create a conjunct to be injected
+
+ ComparativeBoolNode* cmpNode = FB_NEW(getPool()) ComparativeBoolNode(getPool(), blrOp,
+ PASS1_node_psql(dsqlScratch, dsqlArg1, false), rse->nod_arg[Dsql::e_rse_items]->nod_arg[0]);
+
+ dsql_nod* temp = MAKE_node(Dsql::nod_class_exprnode, 1);
+ temp->nod_arg[0] = reinterpret_cast<dsql_nod*>(cmpNode);
+ rse->nod_arg[Dsql::e_rse_boolean] = temp;
+
+ // create output node
+
+ RseBoolNode* rseNode = FB_NEW(getPool()) RseBoolNode(getPool(), rseBlrOp, rse);
+
+ // Finish off by cleaning up contexts
+ dsqlScratch->unionContext.clear(baseUnion);
+ dsqlScratch->derivedContext.clear(baseDT);
+ dsqlScratch->context->clear(base);
+
+ return rseNode;
+}
+
+
+//--------------------
+
+
+static RegisterNode<MissingBoolNode> regMissingBoolNode(blr_missing);
+
+MissingBoolNode::MissingBoolNode(MemoryPool& pool, dsql_nod* aArg)
+ : TypedNode<BoolExprNode, ExprNode::TYPE_MISSING_BOOL>(pool),
+ dsqlArg(aArg),
+ arg(NULL)
+{
+ addChildNode(dsqlArg, arg);
+}
+
+DmlNode* MissingBoolNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR /*blrOp*/)
+{
+ MissingBoolNode* node = FB_NEW(pool) MissingBoolNode(pool);
+ node->arg = PAR_parse_node(tdbb, csb, TYPE_BOOL);
+ return node;
+}
+
+void MissingBoolNode::print(string& text, Array<dsql_nod*>& nodes) const
+{
+ text = "MissingBoolNode";
+ ExprNode::print(text, nodes);
+}
+
+BoolExprNode* MissingBoolNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
+{
+ MissingBoolNode* node = FB_NEW(getPool()) MissingBoolNode(getPool(),
+ PASS1_node(dsqlScratch, dsqlArg));
+
+ PASS1_set_parameter_type(dsqlScratch, node->dsqlArg, NULL, false);
+
+ return node;
+}
+
+void MissingBoolNode::genBlr(DsqlCompilerScratch* dsqlScratch)
+{
+ dsqlScratch->appendUChar(blr_missing);
+ GEN_expr(dsqlScratch, dsqlArg);
+}
+
+BoolExprNode* MissingBoolNode::copy(thread_db* tdbb, NodeCopier& copier)
+{
+ MissingBoolNode* node = FB_NEW(*tdbb->getDefaultPool()) MissingBoolNode(
+ *tdbb->getDefaultPool());
+ node->arg = copier.copy(tdbb, arg);
+ return node;
+}
+
+ExprNode* MissingBoolNode::pass1(thread_db* tdbb, CompilerScratch* csb)
+{
+ return BoolExprNode::pass1(tdbb, csb);
+}
+
+ExprNode* MissingBoolNode::pass2(thread_db* tdbb, CompilerScratch* csb)
+{
+ if (arg->nod_flags & nod_agg_dbkey)
+ ERR_post(Arg::Gds(isc_bad_dbkey));
+
+ // check for syntax errors in the calculation
+ dsc descriptor_a;
+ CMP_get_desc(tdbb, csb, arg, &descriptor_a);
+
+ return BoolExprNode::pass2(tdbb, csb);
+}
+
+bool MissingBoolNode::execute(thread_db* tdbb, jrd_req* request) const
+{
+ EVL_expr(tdbb, arg);
+
+ if (request->req_flags & req_null)
+ {
+ request->req_flags &= ~req_null;
+ return true;
+ }
+ else
+ return false;
+}
+
+
+//--------------------
+
+
+static RegisterNode<NotBoolNode> regNotBoolNode(blr_not);
+
+NotBoolNode::NotBoolNode(MemoryPool& pool, dsql_nod* aArg)
+ : TypedNode<BoolExprNode, ExprNode::TYPE_NOT_BOOL>(pool),
+ dsqlArg(aArg),
+ arg(NULL)
+{
+ addChildNode(dsqlArg, arg);
+}
+
+DmlNode* NotBoolNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, UCHAR /*blrOp*/)
+{
+ NotBoolNode* node = FB_NEW(pool) NotBoolNode(pool);
+ node->arg = PAR_parse_node(tdbb, csb, TYPE_BOOL);
+ return node;
+}
+
+void NotBoolNode::print(string& text, Array<dsql_nod*>& nodes) const
+{
+ text = "NotBoolNode";
+ ExprNode::print(text, nodes);
+}
+
+BoolExprNode* NotBoolNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
+{
+ return process(dsqlScratch, true);
+}
+
+void NotBoolNode::genBlr(DsqlCompilerScratch* dsqlScratch)
+{
+ dsqlScratch->appendUChar(blr_not);
+ GEN_expr(dsqlScratch, dsqlArg);
+}
+
+BoolExprNode* NotBoolNode::copy(thread_db* tdbb, NodeCopier& copier)
+{
+ NotBoolNode* node = FB_NEW(*tdbb->getDefaultPool()) NotBoolNode(*tdbb->getDefaultPool());
+ node->arg = copier.copy(tdbb, arg);
+ return node;
+}
+
+ExprNode* NotBoolNode::pass1(thread_db* tdbb, CompilerScratch* csb)
+{
+ RseBoolNode* rseBoolean = ExprNode::as<RseBoolNode>(arg.getObject());
+
+ if (rseBoolean && rseBoolean->getNode())
+ {
+ if (rseBoolean->blrOp == blr_ansi_any)
+ rseBoolean->getNode()->nod_flags |= nod_deoptimize;
+ if (rseBoolean->blrOp == blr_ansi_any || rseBoolean->blrOp == blr_ansi_all)
+ rseBoolean->getNode()->nod_flags |= nod_ansi_not;
+ }
+
+ return BoolExprNode::pass1(tdbb, csb);
+}
+
+bool NotBoolNode::execute(thread_db* tdbb, jrd_req* request) const
+{
+ bool value = EVL_boolean(tdbb, arg);
+
+ if (request->req_flags & req_null)
+ return false;
+
+ return !value;
+}
+
+// Replace NOT with an appropriately inverted condition, if possible.
+// Get rid of redundant nested NOT predicates.
+BoolExprNode* NotBoolNode::process(DsqlCo...
[truncated message content] |