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] |