|
From: <asf...@us...> - 2010-08-27 02:18:09
|
Revision: 51488
http://firebird.svn.sourceforge.net/firebird/?rev=51488&view=rev
Author: asfernandes
Date: 2010-08-27 02:18:00 +0000 (Fri, 27 Aug 2010)
Log Message:
-----------
1) Separate DsqlCompilerScratch in its own files.
2) Move BlockNode functionality to it.
3) Move some related CTE functions to it.
Modified Paths:
--------------
firebird/trunk/builds/posix/make.shared.variables
firebird/trunk/src/dsql/DSqlDataTypeUtil.cpp
firebird/trunk/src/dsql/DdlNodes.epp
firebird/trunk/src/dsql/DdlNodes.h
firebird/trunk/src/dsql/Nodes.h
firebird/trunk/src/dsql/StmtNodes.cpp
firebird/trunk/src/dsql/StmtNodes.h
firebird/trunk/src/dsql/dsql.h
firebird/trunk/src/dsql/gen.cpp
firebird/trunk/src/dsql/misc_func.cpp
firebird/trunk/src/dsql/pass1.cpp
firebird/trunk/src/dsql/pass1_proto.h
Added Paths:
-----------
firebird/trunk/src/dsql/DsqlCompilerScratch.cpp
firebird/trunk/src/dsql/DsqlCompilerScratch.h
Modified: firebird/trunk/builds/posix/make.shared.variables
===================================================================
--- firebird/trunk/builds/posix/make.shared.variables 2010-08-26 15:40:51 UTC (rev 51487)
+++ firebird/trunk/builds/posix/make.shared.variables 2010-08-27 02:18:00 UTC (rev 51488)
@@ -81,7 +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 misc_func.cpp \
- DdlNodes.epp PackageNodes.epp AggNodes.cpp BlrWriter.cpp ExprNodes.cpp StmtNodes.cpp WinNodes.cpp
+ DdlNodes.epp PackageNodes.epp AggNodes.cpp BlrWriter.cpp DsqlCompilerScratch.cpp \
+ ExprNodes.cpp StmtNodes.cpp WinNodes.cpp
DSQL_Files = $(DSQL_ClientFiles) $(DSQL_ServerFiles)
Modified: firebird/trunk/src/dsql/DSqlDataTypeUtil.cpp
===================================================================
--- firebird/trunk/src/dsql/DSqlDataTypeUtil.cpp 2010-08-26 15:40:51 UTC (rev 51487)
+++ firebird/trunk/src/dsql/DSqlDataTypeUtil.cpp 2010-08-27 02:18:00 UTC (rev 51488)
@@ -24,7 +24,7 @@
#include "firebird.h"
#include "../dsql/DSqlDataTypeUtil.h"
-#include "../dsql/dsql.h"
+#include "../dsql/DsqlCompilerScratch.h"
#include "../dsql/metd_proto.h"
UCHAR Jrd::DSqlDataTypeUtil::maxBytesPerChar(UCHAR charSet)
Modified: firebird/trunk/src/dsql/DdlNodes.epp
===================================================================
--- firebird/trunk/src/dsql/DdlNodes.epp 2010-08-26 15:40:51 UTC (rev 51487)
+++ firebird/trunk/src/dsql/DdlNodes.epp 2010-08-27 02:18:00 UTC (rev 51488)
@@ -1157,8 +1157,6 @@
DdlNode* CreateAlterFunctionNode::internalDsqlPass()
{
- DsqlCompiledStatement* const statement = dsqlScratch->getStatement();
- statement->setBlockNode(this);
dsqlScratch->flags |= (DsqlCompilerScratch::FLAG_BLOCK | DsqlCompilerScratch::FLAG_FUNCTION);
const dsql_nod* variables = localDeclList;
@@ -1488,7 +1486,6 @@
unsigned pos, const ParameterClause& parameter)
{
Attachment* attachment = transaction->getAttachment();
- DsqlCompiledStatement* statement = dsqlScratch->getStatement();
AutoCacheRequest requestHandle(tdbb, drq_s_func_args2, DYN_REQUESTS);
@@ -1591,7 +1588,7 @@
dsqlScratch->getBlrData().clear();
- if (statement->getFlags() & DsqlCompiledStatement::FLAG_BLR_VERSION4)
+ if (dsqlScratch->isVersion4())
dsqlScratch->appendUChar(blr_version4);
else
dsqlScratch->appendUChar(blr_version5);
@@ -1618,14 +1615,12 @@
compiled = true;
invalid = true;
- DsqlCompiledStatement* statement = dsqlScratch->getStatement();
-
if (body)
{
dsqlScratch->beginDebug();
dsqlScratch->getBlrData().clear();
- if (statement->getFlags() & DsqlCompiledStatement::FLAG_BLR_VERSION4)
+ if (dsqlScratch->isVersion4())
dsqlScratch->appendUChar(blr_version4);
else
dsqlScratch->appendUChar(blr_version5);
@@ -1650,7 +1645,7 @@
dsqlScratch->appendUChar(blr_short);
dsqlScratch->appendUChar(0);
- variables.add(MAKE_variable(parameter.legacyField,
+ dsqlScratch->variables.add(MAKE_variable(parameter.legacyField,
parameter.name.c_str(), VAR_input, 0, (USHORT) (2 * i), 0));
}
}
@@ -1667,8 +1662,8 @@
dsqlScratch->appendUChar(0);
dsql_nod* const var = MAKE_variable(returnType.legacyField, "", VAR_output, 1, 0, 0);
- variables.add(var);
- outputVariables.add(var);
+ dsqlScratch->variables.add(var);
+ dsqlScratch->outputVariables.add(var);
if (parameters.getCount() != 0)
{
@@ -1695,14 +1690,15 @@
}
}
- dsql_var* const variable = (dsql_var*) outputVariables[0]->nod_arg[Dsql::e_var_variable];
- putLocalVariable(dsqlScratch, variable, 0, NULL);
+ dsql_var* const variable =
+ (dsql_var*) dsqlScratch->outputVariables[0]->nod_arg[Dsql::e_var_variable];
+ dsqlScratch->putLocalVariable(variable, 0, NULL);
// ASF: This is here to not change the old logic (proc_flag)
// of previous calls to PASS1_node and PASS1_statement.
dsqlScratch->setPsql(true);
- putLocalVariables(dsqlScratch, localDeclList, 1);
+ dsqlScratch->putLocalVariables(localDeclList, 1);
dsqlScratch->appendUChar(blr_stall);
// put a label before body of procedure,
@@ -1714,10 +1710,9 @@
GEN_statement(dsqlScratch, PASS1_statement(dsqlScratch, body));
- statement->setType(DsqlCompiledStatement::TYPE_DDL);
+ dsqlScratch->getStatement()->setType(DsqlCompiledStatement::TYPE_DDL);
dsqlScratch->appendUChar(blr_end);
- genReturn(dsqlScratch, false);
-
+ dsqlScratch->genReturn(false);
dsqlScratch->appendUChar(blr_end);
dsqlScratch->appendUChar(blr_eoc);
@@ -1902,8 +1897,6 @@
DdlNode* CreateAlterProcedureNode::internalDsqlPass()
{
- DsqlCompiledStatement* statement = dsqlScratch->getStatement();
- statement->setBlockNode(this);
dsqlScratch->flags |= (DsqlCompilerScratch::FLAG_BLOCK | DsqlCompilerScratch::FLAG_PROCEDURE);
const dsql_nod* variables = localDeclList;
@@ -2340,11 +2333,9 @@
string defaultSource = string(defaultString->str_data, defaultString->str_length);
attachment->storeMetaDataBlob(tdbb, transaction, &PRM.RDB$DEFAULT_SOURCE, defaultSource);
- DsqlCompiledStatement* statement = dsqlScratch->getStatement();
-
dsqlScratch->getBlrData().clear();
- if (statement->getFlags() & DsqlCompiledStatement::FLAG_BLR_VERSION4)
+ if (dsqlScratch->isVersion4())
dsqlScratch->appendUChar(blr_version4);
else
dsqlScratch->appendUChar(blr_version5);
@@ -2375,12 +2366,10 @@
invalid = true;
- DsqlCompiledStatement* statement = dsqlScratch->getStatement();
-
dsqlScratch->beginDebug();
dsqlScratch->getBlrData().clear();
- if (statement->getFlags() & DsqlCompiledStatement::FLAG_BLR_VERSION4)
+ if (dsqlScratch->isVersion4())
dsqlScratch->appendUChar(blr_version4);
else
dsqlScratch->appendUChar(blr_version5);
@@ -2404,7 +2393,7 @@
dsqlScratch->appendUChar(blr_short);
dsqlScratch->appendUChar(0);
- variables.add(MAKE_variable(parameter.legacyField,
+ dsqlScratch->variables.add(MAKE_variable(parameter.legacyField,
parameter.name.c_str(), VAR_input, 0, (USHORT) (2 * i), 0));
}
}
@@ -2429,8 +2418,8 @@
dsql_nod* const var = MAKE_variable(parameter.legacyField,
parameter.name.c_str(), VAR_output, 1, (USHORT) (2 * i), i);
- variables.add(var);
- outputVariables.add(var);
+ dsqlScratch->variables.add(var);
+ dsqlScratch->outputVariables.add(var);
}
}
@@ -2463,18 +2452,20 @@
}
}
- for (Array<dsql_nod*>::const_iterator i = outputVariables.begin(); i != outputVariables.end(); ++i)
+ for (Array<dsql_nod*>::const_iterator i = dsqlScratch->outputVariables.begin();
+ i != dsqlScratch->outputVariables.end();
+ ++i)
{
dsql_nod* parameter = *i;
dsql_var* const variable = (dsql_var*) parameter->nod_arg[Dsql::e_var_variable];
- putLocalVariable(dsqlScratch, variable, 0, NULL);
+ dsqlScratch->putLocalVariable(variable, 0, NULL);
}
// ASF: This is here to not change the old logic (proc_flag)
// of previous calls to PASS1_node and PASS1_statement.
dsqlScratch->setPsql(true);
- putLocalVariables(dsqlScratch, localDeclList, returns.getCount());
+ dsqlScratch->putLocalVariables(localDeclList, returns.getCount());
dsqlScratch->appendUChar(blr_stall);
// put a label before body of procedure,
@@ -2486,10 +2477,9 @@
GEN_statement(dsqlScratch, PASS1_statement(dsqlScratch, body));
- statement->setType(DsqlCompiledStatement::TYPE_DDL);
+ dsqlScratch->getStatement()->setType(DsqlCompiledStatement::TYPE_DDL);
dsqlScratch->appendUChar(blr_end);
- genReturn(dsqlScratch, true);
-
+ dsqlScratch->genReturn(true);
dsqlScratch->appendUChar(blr_end);
dsqlScratch->appendUChar(blr_eoc);
@@ -2779,8 +2769,6 @@
DdlNode* CreateAlterTriggerNode::internalDsqlPass()
{
- DsqlCompiledStatement* statement = dsqlScratch->getStatement();
- statement->setBlockNode(this);
dsqlScratch->flags |= (DsqlCompilerScratch::FLAG_BLOCK | DsqlCompilerScratch::FLAG_TRIGGER);
if (type.specified)
@@ -2876,8 +2864,6 @@
if (body)
{
- DsqlCompiledStatement* statement = dsqlScratch->getStatement();
-
dsqlScratch->beginDebug();
dsqlScratch->getBlrData().clear();
@@ -2921,7 +2907,7 @@
// generate the trigger blr
- if (statement->getFlags() & DsqlCompiledStatement::FLAG_BLR_VERSION4)
+ if (dsqlScratch->isVersion4())
dsqlScratch->appendUChar(blr_version4);
else
dsqlScratch->appendUChar(blr_version5);
@@ -2929,9 +2915,8 @@
dsqlScratch->appendUChar(blr_begin);
dsqlScratch->setPsql(true);
+ dsqlScratch->putLocalVariables(localDeclList, 0);
- putLocalVariables(dsqlScratch, localDeclList, 0);
-
dsqlScratch->scopeLevel++;
// dimitr: I see no reason to deny EXIT command in triggers,
// hence I've added zero label at the beginning.
@@ -2954,7 +2939,7 @@
// The statement type may have been set incorrectly when parsing
// the trigger actions, so reset it to reflect the fact that this
// is a data definition statement; also reset the ddl node.
- statement->setType(DsqlCompiledStatement::TYPE_DDL);
+ dsqlScratch->getStatement()->setType(DsqlCompiledStatement::TYPE_DDL);
}
invalid = false;
Modified: firebird/trunk/src/dsql/DdlNodes.h
===================================================================
--- firebird/trunk/src/dsql/DdlNodes.h 2010-08-26 15:40:51 UTC (rev 51487)
+++ firebird/trunk/src/dsql/DdlNodes.h 2010-08-27 02:18:00 UTC (rev 51488)
@@ -229,12 +229,11 @@
};
-class CreateAlterFunctionNode : public DdlNode, public BlockNode
+class CreateAlterFunctionNode : public DdlNode
{
public:
CreateAlterFunctionNode(MemoryPool& pool, const Firebird::MetaName& aName)
: DdlNode(pool),
- BlockNode(pool, false),
name(pool, aName),
create(true),
alter(false),
@@ -334,12 +333,11 @@
RecreateFunctionNode;
-class CreateAlterProcedureNode : public DdlNode, public BlockNode
+class CreateAlterProcedureNode : public DdlNode
{
public:
CreateAlterProcedureNode(MemoryPool& pool, const Firebird::MetaName& aName)
: DdlNode(pool),
- BlockNode(pool, true),
name(pool, aName),
create(true),
alter(false),
@@ -476,12 +474,11 @@
};
-class CreateAlterTriggerNode : public DdlNode, public BlockNode, public TriggerDefinition
+class CreateAlterTriggerNode : public DdlNode, public TriggerDefinition
{
public:
CreateAlterTriggerNode(MemoryPool& p, const Firebird::MetaName& aName)
: DdlNode(p),
- BlockNode(p, false),
TriggerDefinition(p),
create(true),
alter(false),
Added: firebird/trunk/src/dsql/DsqlCompilerScratch.cpp
===================================================================
--- firebird/trunk/src/dsql/DsqlCompilerScratch.cpp (rev 0)
+++ firebird/trunk/src/dsql/DsqlCompilerScratch.cpp 2010-08-27 02:18:00 UTC (rev 51488)
@@ -0,0 +1,761 @@
+/*
+ * The contents of this file are subject to the Interbase Public
+ * License Version 1.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy
+ * of the License at http://www.Inprise.com/IPL.html
+ *
+ * Software distributed under the License is distributed on an
+ * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
+ * or implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code was created by Inprise Corporation
+ * and its predecessors. Portions created by Inprise Corporation are
+ * Copyright (C) Inprise Corporation.
+ *
+ * All Rights Reserved.
+ * Contributor(s): ______________________________________.
+ * Adriano dos Santos Fernandes
+ */
+
+#include "firebird.h"
+#include "../jrd/common.h"
+#include "../dsql/DsqlCompilerScratch.h"
+#include "../jrd/jrd.h"
+#include "../jrd/blr.h"
+#include "../dsql/node.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 Dsql;
+using namespace Jrd;
+
+
+// Write out field data type.
+// Taking special care to declare international text.
+void DsqlCompilerScratch::putDtype(const dsql_fld* field, bool useSubType)
+{
+#ifdef DEV_BUILD
+ // Check if the field describes a known datatype
+
+ if (field->fld_dtype > FB_NELEM(blr_dtypes) || !blr_dtypes[field->fld_dtype])
+ {
+ SCHAR buffer[100];
+
+ sprintf(buffer, "Invalid dtype %d in BlockNode::putDtype", field->fld_dtype);
+ ERRD_bugcheck(buffer);
+ }
+#endif
+
+ if (field->fld_not_nullable)
+ appendUChar(blr_not_nullable);
+
+ if (field->fld_type_of_name.hasData())
+ {
+ if (field->fld_type_of_table)
+ {
+ if (field->fld_explicit_collation)
+ {
+ appendUChar(blr_column_name2);
+ appendUChar(field->fld_full_domain ? blr_domain_full : blr_domain_type_of);
+ appendMetaString(field->fld_type_of_table->str_data);
+ appendMetaString(field->fld_type_of_name.c_str());
+ appendUShort(field->fld_ttype);
+ }
+ else
+ {
+ appendUChar(blr_column_name);
+ appendUChar(field->fld_full_domain ? blr_domain_full : blr_domain_type_of);
+ appendMetaString(field->fld_type_of_table->str_data);
+ appendMetaString(field->fld_type_of_name.c_str());
+ }
+ }
+ else
+ {
+ if (field->fld_explicit_collation)
+ {
+ appendUChar(blr_domain_name2);
+ appendUChar(field->fld_full_domain ? blr_domain_full : blr_domain_type_of);
+ appendMetaString(field->fld_type_of_name.c_str());
+ appendUShort(field->fld_ttype);
+ }
+ else
+ {
+ appendUChar(blr_domain_name);
+ appendUChar(field->fld_full_domain ? blr_domain_full : blr_domain_type_of);
+ appendMetaString(field->fld_type_of_name.c_str());
+ }
+ }
+
+ return;
+ }
+
+ switch (field->fld_dtype)
+ {
+ case dtype_cstring:
+ case dtype_text:
+ case dtype_varying:
+ case dtype_blob:
+ if (!useSubType)
+ appendUChar(blr_dtypes[field->fld_dtype]);
+ else if (field->fld_dtype == dtype_varying)
+ {
+ appendUChar(blr_varying2);
+ appendUShort(field->fld_ttype);
+ }
+ else if (field->fld_dtype == dtype_cstring)
+ {
+ appendUChar(blr_cstring2);
+ appendUShort(field->fld_ttype);
+ }
+ else if (field->fld_dtype == dtype_blob)
+ {
+ appendUChar(blr_blob2);
+ appendUShort(field->fld_sub_type);
+ appendUShort(field->fld_ttype);
+ }
+ else
+ {
+ appendUChar(blr_text2);
+ appendUShort(field->fld_ttype);
+ }
+
+ if (field->fld_dtype == dtype_varying)
+ appendUShort(field->fld_length - sizeof(USHORT));
+ else if (field->fld_dtype != dtype_blob)
+ appendUShort(field->fld_length);
+ break;
+
+ default:
+ appendUChar(blr_dtypes[field->fld_dtype]);
+ if (DTYPE_IS_EXACT(field->fld_dtype) || (dtype_quad == field->fld_dtype))
+ appendUChar(field->fld_scale);
+ break;
+ }
+}
+
+// Emit dyn for the local variables declared in a procedure or trigger.
+void DsqlCompilerScratch::putLocalVariables(const dsql_nod* parameters, SSHORT locals)
+{
+ if (!parameters)
+ return;
+
+ dsql_nod* const* ptr = parameters->nod_arg;
+
+ for (const dsql_nod* const* const end = ptr + parameters->nod_count; ptr < end; ptr++)
+ {
+ dsql_nod* parameter = *ptr;
+
+ putDebugSrcInfo(parameter->nod_line, parameter->nod_column);
+
+ if (parameter->nod_type == Dsql::nod_def_field)
+ {
+ dsql_fld* field = (dsql_fld*) parameter->nod_arg[Dsql::e_dfl_field];
+ const dsql_nod* const* rest = ptr;
+
+ while (++rest != end)
+ {
+ if ((*rest)->nod_type == Dsql::nod_def_field)
+ {
+ const dsql_fld* rest_field = (dsql_fld*) (*rest)->nod_arg[Dsql::e_dfl_field];
+ if (field->fld_name == rest_field->fld_name)
+ {
+ ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-637) <<
+ Arg::Gds(isc_dsql_duplicate_spec) << Arg::Str(field->fld_name));
+ }
+ }
+ }
+
+ dsql_nod* varNode = MAKE_variable(field, field->fld_name.c_str(), VAR_local, 0, 0, locals);
+ variables.add(varNode);
+
+ dsql_var* variable = (dsql_var*) varNode->nod_arg[Dsql::e_var_variable];
+ putLocalVariable(variable, parameter,
+ reinterpret_cast<const dsql_str*>(parameter->nod_arg[Dsql::e_dfl_collate]));
+
+ // Some field attributes are calculated inside
+ // putLocalVariable(), so we reinitialize the
+ // descriptor
+ MAKE_desc_from_field(&varNode->nod_desc, field);
+
+ ++locals;
+ }
+ else if (parameter->nod_type == Dsql::nod_cursor)
+ {
+ PASS1_statement(this, parameter);
+ GEN_statement(this, parameter);
+ }
+ }
+}
+
+// Write out local variable field data type.
+void DsqlCompilerScratch::putLocalVariable(dsql_var* variable, dsql_nod* hostParam,
+ const dsql_str* collationName)
+{
+ dsql_fld* field = variable->var_field;
+
+ appendUChar(blr_dcl_variable);
+ appendUShort(variable->var_variable_number);
+ DDL_resolve_intl_type(this, field, collationName);
+
+ //const USHORT dtype = field->fld_dtype;
+
+ putDtype(field, true);
+ //field->fld_dtype = dtype;
+
+ // Check for a default value, borrowed from define_domain
+ dsql_nod* node = hostParam ? hostParam->nod_arg[Dsql::e_dfl_default] : NULL;
+
+ if (node || (!field->fld_full_domain && !field->fld_not_nullable))
+ {
+ appendUChar(blr_assignment);
+
+ if (node)
+ {
+ fb_assert(node->nod_type == Dsql::nod_def_default);
+ PsqlChanger psqlChanger(this, false);
+ node = PASS1_node(this, node->nod_arg[Dsql::e_dft_default]);
+ GEN_expr(this, node);
+ }
+ else
+ appendUChar(blr_null); // Initialize variable to NULL
+
+ appendUChar(blr_variable);
+ appendUShort(variable->var_variable_number);
+ }
+ else
+ {
+ appendUChar(blr_init_variable);
+ appendUShort(variable->var_variable_number);
+ }
+
+ if (variable->var_name[0]) // Not a function return value
+ putDebugVariable(variable->var_variable_number, variable->var_name);
+
+ ++hiddenVarsNumber;
+}
+
+// Try to resolve variable name against parameters and local variables.
+dsql_nod* DsqlCompilerScratch::resolveVariable(const dsql_str* varName)
+{
+ for (dsql_nod* const* i = variables.begin(); i != variables.end(); ++i)
+ {
+ dsql_nod* varNode = *i;
+ fb_assert(varNode->nod_type == Dsql::nod_variable);
+
+ if (varNode->nod_type == Dsql::nod_variable)
+ {
+ const dsql_var* variable = (dsql_var*) varNode->nod_arg[Dsql::e_var_variable];
+ DEV_BLKCHK(variable, dsql_type_var);
+
+ if (!strcmp(varName->str_data, variable->var_name))
+ return varNode;
+ }
+ }
+
+ return NULL;
+}
+
+// Generate BLR for a return.
+void DsqlCompilerScratch::genReturn(bool eosFlag)
+{
+ const bool hasEos = !(flags & (FLAG_TRIGGER | FLAG_FUNCTION));
+
+ if (hasEos && !eosFlag)
+ appendUChar(blr_begin);
+
+ appendUChar(blr_send);
+ appendUChar(1);
+ appendUChar(blr_begin);
+
+ for (Array<dsql_nod*>::const_iterator i = outputVariables.begin(); i != outputVariables.end(); ++i)
+ {
+ const dsql_nod* parameter = *i;
+ const dsql_var* variable = (dsql_var*) parameter->nod_arg[Dsql::e_var_variable];
+ appendUChar(blr_assignment);
+ appendUChar(blr_variable);
+ appendUShort(variable->var_variable_number);
+ appendUChar(blr_parameter2);
+ appendUChar(variable->var_msg_number);
+ appendUShort(variable->var_msg_item);
+ appendUShort(variable->var_msg_item + 1);
+ }
+
+ if (hasEos)
+ {
+ appendUChar(blr_assignment);
+ appendUChar(blr_literal);
+ appendUChar(blr_short);
+ appendUChar(0);
+ appendUShort((eosFlag ? 0 : 1));
+ appendUChar(blr_parameter);
+ appendUChar(1);
+ appendUShort(USHORT(2 * outputVariables.getCount()));
+ }
+
+ appendUChar(blr_end);
+
+ if (hasEos && !eosFlag)
+ {
+ appendUChar(blr_stall);
+ appendUChar(blr_end);
+ }
+}
+
+void DsqlCompilerScratch::addCTEs(dsql_nod* with)
+{
+ DEV_BLKCHK(with, dsql_type_nod);
+ fb_assert(with->nod_type == Dsql::nod_with);
+
+ if (ctes.getCount())
+ {
+ ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) <<
+ // WITH clause can't be nested
+ Arg::Gds(isc_dsql_cte_nested_with));
+ }
+
+ if (with->nod_flags & NOD_UNION_RECURSIVE)
+ flags |= DsqlCompilerScratch::FLAG_RECURSIVE_CTE;
+
+ const dsql_nod* list = with->nod_arg[0];
+ const dsql_nod* const* end = list->nod_arg + list->nod_count;
+
+ for (dsql_nod* const* cte = list->nod_arg; cte < end; cte++)
+ {
+ fb_assert((*cte)->nod_type == Dsql::nod_derived_table);
+
+ if (with->nod_flags & NOD_UNION_RECURSIVE)
+ {
+ currCtes.push(*cte);
+ PsqlChanger changer(this, false);
+ ctes.add(pass1RecursiveCte(*cte));
+ currCtes.pop();
+
+ // Add CTE name into CTE aliases stack. It allows later to search for
+ // aliases of given CTE.
+ const dsql_str* cteName = (dsql_str*) (*cte)->nod_arg[Dsql::e_derived_table_alias];
+ addCTEAlias(cteName);
+ }
+ else
+ ctes.add(*cte);
+ }
+}
+
+dsql_nod* DsqlCompilerScratch::findCTE(const dsql_str* name)
+{
+ for (size_t i = 0; i < ctes.getCount(); ++i)
+ {
+ dsql_nod* cte = ctes[i];
+ const dsql_str* cteName = (dsql_str*) cte->nod_arg[Dsql::e_derived_table_alias];
+
+ if (name->str_length == cteName->str_length &&
+ strncmp(name->str_data, cteName->str_data, cteName->str_length) == 0)
+ {
+ return cte;
+ }
+ }
+
+ return NULL;
+}
+
+void DsqlCompilerScratch::clearCTEs()
+{
+ flags &= ~DsqlCompilerScratch::FLAG_RECURSIVE_CTE;
+ ctes.clear();
+ cteAliases.clear();
+}
+
+void DsqlCompilerScratch::checkUnusedCTEs() const
+{
+ for (size_t i = 0; i < ctes.getCount(); ++i)
+ {
+ const dsql_nod* cte = ctes[i];
+
+ if (!(cte->nod_flags & NOD_DT_CTE_USED))
+ {
+ const dsql_str* cteName = (dsql_str*) cte->nod_arg[Dsql::e_derived_table_alias];
+
+ ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) <<
+ Arg::Gds(isc_dsql_cte_not_used) << Arg::Str(cteName->str_data));
+ }
+ }
+}
+
+// Process derived table which can be recursive CTE.
+// If it is non-recursive return input node unchanged.
+// If it is recursive return new derived table which is an union of union of anchor (non-recursive)
+// queries and union of recursive queries. Check recursive queries to satisfy various criterias.
+// Note that our parser is right-to-left therefore nested list linked as first node in parent list
+// and second node is always query spec.
+// For example, if we have 4 CTE's where first two is non-recursive and last two is recursive:
+//
+// list union
+// [0] [1] [0] [1]
+// list cte3 ===> anchor recursive
+// [0] [1] [0] [1] [0] [1]
+// list cte3 cte1 cte2 cte3 cte4
+// [0] [1]
+// cte1 cte2
+//
+// Also, we should not change layout of original parse tree to allow it to be parsed again if
+// needed. Therefore recursive part is built using newly allocated list nodes.
+dsql_nod* DsqlCompilerScratch::pass1RecursiveCte(dsql_nod* input)
+{
+ dsql_str* const cte_alias = (dsql_str*) input->nod_arg[Dsql::e_derived_table_alias];
+ dsql_nod* const select_expr = input->nod_arg[Dsql::e_derived_table_rse];
+ dsql_nod* query = select_expr->nod_arg[Dsql::e_sel_query_spec];
+
+ if (query->nod_type != Dsql::nod_list && pass1RseIsRecursive(query))
+ {
+ ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) <<
+ // Recursive CTE (%s) must be an UNION
+ Arg::Gds(isc_dsql_cte_not_a_union) << Arg::Str(cte_alias->str_data));
+ }
+
+ // split queries list on two parts: anchor and recursive
+ dsql_nod* anchorRse = NULL, *recursiveRse = NULL;
+ dsql_nod* qry = query;
+
+ dsql_nod* newQry = MAKE_node(Dsql::nod_list, 2);
+ newQry->nod_flags = query->nod_flags;
+
+ while (true)
+ {
+ dsql_nod* rse = NULL;
+
+ if (qry->nod_type == Dsql::nod_list)
+ rse = qry->nod_arg[1];
+ else
+ rse = qry;
+
+ dsql_nod* newRse = pass1RseIsRecursive(rse);
+
+ if (newRse) // rse is recursive
+ {
+ if (anchorRse)
+ {
+ ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) <<
+ // CTE '%s' defined non-recursive member after recursive
+ Arg::Gds(isc_dsql_cte_nonrecurs_after_recurs) << Arg::Str(cte_alias->str_data));
+ }
+
+ if (newRse->nod_arg[Dsql::e_qry_distinct])
+ {
+ ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) <<
+ // Recursive member of CTE '%s' has %s clause
+ Arg::Gds(isc_dsql_cte_wrong_clause) << Arg::Str(cte_alias->str_data) <<
+ Arg::Str("DISTINCT"));
+ }
+
+ if (newRse->nod_arg[Dsql::e_qry_group])
+ {
+ ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) <<
+ // Recursive member of CTE '%s' has %s clause
+ Arg::Gds(isc_dsql_cte_wrong_clause) << Arg::Str(cte_alias->str_data) <<
+ Arg::Str("GROUP BY"));
+ }
+
+ if (newRse->nod_arg[Dsql::e_qry_having])
+ {
+ ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) <<
+ // Recursive member of CTE '%s' has %s clause
+ Arg::Gds(isc_dsql_cte_wrong_clause) << Arg::Str(cte_alias->str_data) <<
+ Arg::Str("HAVING"));
+ }
+ // hvlad: we need also forbid any aggregate function here
+ // but for now i have no idea how to do it simple
+
+ if ((newQry->nod_type == Dsql::nod_list) && !(newQry->nod_flags & NOD_UNION_ALL))
+ {
+ ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) <<
+ // Recursive members of CTE (%s) must be linked with another members via UNION ALL
+ Arg::Gds(isc_dsql_cte_union_all) << Arg::Str(cte_alias->str_data));
+ }
+
+ if (!recursiveRse)
+ recursiveRse = newQry;
+
+ newRse->nod_flags |= NOD_SELECT_EXPR_RECURSIVE;
+
+ if (qry->nod_type == Dsql::nod_list)
+ newQry->nod_arg[1] = newRse;
+ else
+ newQry->nod_arg[0] = newRse;
+ }
+ else
+ {
+ if (qry->nod_type == Dsql::nod_list)
+ newQry->nod_arg[1] = rse;
+ else
+ newQry->nod_arg[0] = rse;
+
+ if (!anchorRse)
+ {
+ if (qry->nod_type == Dsql::nod_list)
+ anchorRse = newQry;
+ else
+ anchorRse = rse;
+ }
+ }
+
+ if (qry->nod_type != Dsql::nod_list)
+ break;
+
+ qry = qry->nod_arg[0];
+
+ if (qry->nod_type == Dsql::nod_list)
+ {
+ newQry->nod_arg[0] = MAKE_node(Dsql::nod_list, 2);
+ newQry = newQry->nod_arg[0];
+ newQry->nod_flags = qry->nod_flags;
+ }
+ }
+
+ if (!recursiveRse)
+ return input;
+
+ if (!anchorRse)
+ {
+ ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) <<
+ // Non-recursive member is missing in CTE '%s'
+ Arg::Gds(isc_dsql_cte_miss_nonrecursive) << Arg::Str(cte_alias->str_data));
+ }
+
+ qry = recursiveRse;
+ dsql_nod* list = NULL;
+
+ while (qry->nod_arg[0] != anchorRse)
+ {
+ list = qry;
+ qry = qry->nod_arg[0];
+ }
+
+ qry->nod_arg[0] = 0;
+
+ if (list)
+ list->nod_arg[0] = qry->nod_arg[1];
+ else
+ recursiveRse = qry->nod_arg[1];
+
+ dsql_nod* unionNode = MAKE_node(Dsql::nod_list, 2);
+ unionNode->nod_flags = NOD_UNION_ALL | NOD_UNION_RECURSIVE;
+ unionNode->nod_arg[0] = anchorRse;
+ unionNode->nod_arg[1] = recursiveRse;
+
+ dsql_nod* select = MAKE_node(Dsql::nod_select_expr, Dsql::e_sel_count);
+ select->nod_arg[Dsql::e_sel_query_spec] = unionNode;
+ select->nod_arg[Dsql::e_sel_order] = select->nod_arg[Dsql::e_sel_rows] =
+ select->nod_arg[Dsql::e_sel_with_list] = NULL;
+
+ dsql_nod* node = MAKE_node(Dsql::nod_derived_table, Dsql::e_derived_table_count);
+ dsql_str* alias = (dsql_str*) input->nod_arg[Dsql::e_derived_table_alias];
+ node->nod_arg[Dsql::e_derived_table_alias] = (dsql_nod*) alias;
+ node->nod_arg[Dsql::e_derived_table_column_alias] =
+ input->nod_arg[Dsql::e_derived_table_column_alias];
+ node->nod_arg[Dsql::e_derived_table_rse] = select;
+ node->nod_arg[Dsql::e_derived_table_context] = input->nod_arg[Dsql::e_derived_table_context];
+
+ return node;
+}
+
+// Check if rse is recursive. If recursive reference is a table in the FROM list remove it.
+// If recursive reference is a part of join add join boolean (returned by pass1JoinIsRecursive)
+// to the WHERE clause. Punt if more than one recursive reference is found.
+dsql_nod* DsqlCompilerScratch::pass1RseIsRecursive(dsql_nod* input)
+{
+ fb_assert(input->nod_type == Dsql::nod_query_spec);
+
+ dsql_nod* result = MAKE_node(Dsql::nod_query_spec, Dsql::e_qry_count);
+ memcpy(result->nod_arg, input->nod_arg, Dsql::e_qry_count * sizeof(dsql_nod*));
+
+ dsql_nod* srcTables = input->nod_arg[Dsql::e_qry_from];
+ dsql_nod* dstTables = MAKE_node(Dsql::nod_list, srcTables->nod_count);
+ result->nod_arg[Dsql::e_qry_from] = dstTables;
+
+ dsql_nod** pDstTable = dstTables->nod_arg;
+ dsql_nod** pSrcTable = srcTables->nod_arg;
+ dsql_nod** end = srcTables->nod_arg + srcTables->nod_count;
+ bool found = false;
+
+ for (dsql_nod** prev = pDstTable; pSrcTable < end; ++pSrcTable, ++pDstTable)
+ {
+ *prev++ = *pDstTable = *pSrcTable;
+
+ switch ((*pDstTable)->nod_type)
+ {
+ case Dsql::nod_rel_proc_name:
+ case Dsql::nod_relation_name:
+ if (pass1RelProcIsRecursive(*pDstTable))
+ {
+ if (found)
+ {
+ ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) <<
+ // Recursive member of CTE can't reference itself more than once
+ Arg::Gds(isc_dsql_cte_mult_references));
+ }
+ found = true;
+
+ prev--;
+ dstTables->nod_count--;
+ }
+ break;
+
+ case Dsql::nod_join:
+ {
+ *pDstTable = MAKE_node(Dsql::nod_join, Dsql::e_join_count);
+ memcpy((*pDstTable)->nod_arg, (*pSrcTable)->nod_arg,
+ Dsql::e_join_count * sizeof(dsql_nod*));
+
+ dsql_nod* joinBool = pass1JoinIsRecursive(*pDstTable);
+ if (joinBool)
+ {
+ if (found)
+ {
+ ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) <<
+ // Recursive member of CTE can't reference itself more than once
+ Arg::Gds(isc_dsql_cte_mult_references));
+ }
+ found = true;
+
+ result->nod_arg[Dsql::e_qry_where] =
+ PASS1_compose(result->nod_arg[Dsql::e_qry_where], joinBool, Dsql::nod_and);
+ }
+
+ break;
+ }
+
+ case Dsql::nod_derived_table:
+ break;
+
+ default:
+ fb_assert(false);
+ }
+ }
+
+ return found ? result : NULL;
+}
+
+// Check if table reference is recursive i.e. its name is equal to the name of current processing CTE.
+bool DsqlCompilerScratch::pass1RelProcIsRecursive(dsql_nod* input)
+{
+ const dsql_str* relName = NULL;
+ const dsql_str* relAlias = NULL;
+
+ switch (input->nod_type)
+ {
+ case Dsql::nod_rel_proc_name:
+ relName = (dsql_str*) input->nod_arg[Dsql::e_rpn_name];
+ relAlias = (dsql_str*) input->nod_arg[Dsql::e_rpn_alias];
+ break;
+
+ case Dsql::nod_relation_name:
+ relName = (dsql_str*) input->nod_arg[Dsql::e_rln_name];
+ relAlias = (dsql_str*) input->nod_arg[Dsql::e_rln_alias];
+ break;
+
+ default:
+ return false;
+ }
+
+ fb_assert(currCtes.hasData());
+ const dsql_nod* curr_cte = currCtes.object();
+ const dsql_str* cte_name = (dsql_str*) curr_cte->nod_arg[Dsql::e_derived_table_alias];
+
+ const bool recursive = (cte_name->str_length == relName->str_length) &&
+ (strncmp(relName->str_data, cte_name->str_data, cte_name->str_length) == 0);
+
+ if (recursive)
+ addCTEAlias(relAlias ? relAlias : relName);
+
+ return recursive;
+}
+
+// Check if join have recursive members. If found remove this member from join and return its
+// boolean (to be added into WHERE clause).
+// We must remove member only if it is a table reference. Punt if recursive reference is found in
+// outer join or more than one recursive reference is found
+dsql_nod* DsqlCompilerScratch::pass1JoinIsRecursive(dsql_nod*& input)
+{
+ const NOD_TYPE join_type = input->nod_arg[Dsql::e_join_type]->nod_type;
+ bool remove = false;
+
+ bool leftRecursive = false;
+ dsql_nod* leftBool = NULL;
+ dsql_nod** join_table = &input->nod_arg[Dsql::e_join_left_rel];
+
+ if ((*join_table)->nod_type == Dsql::nod_join)
+ {
+ leftBool = pass1JoinIsRecursive(*join_table);
+ leftRecursive = (leftBool != NULL);
+ }
+ else
+ {
+ leftBool = input->nod_arg[Dsql::e_join_boolean];
+ leftRecursive = pass1RelProcIsRecursive(*join_table);
+
+ if (leftRecursive)
+ remove = true;
+ }
+
+ if (leftRecursive && join_type != Dsql::nod_join_inner)
+ {
+ ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) <<
+ // Recursive member of CTE can't be member of an outer join
+ Arg::Gds(isc_dsql_cte_outer_join));
+ }
+
+ bool rightRecursive = false;
+ dsql_nod* rightBool = NULL;
+
+ join_table = &input->nod_arg[Dsql::e_join_rght_rel];
+
+ if ((*join_table)->nod_type == Dsql::nod_join)
+ {
+ rightBool = pass1JoinIsRecursive(*join_table);
+ rightRecursive = (rightBool != NULL);
+ }
+ else
+ {
+ rightBool = input->nod_arg[Dsql::e_join_boolean];
+ rightRecursive = pass1RelProcIsRecursive(*join_table);
+
+ if (rightRecursive)
+ remove = true;
+ }
+
+ if (rightRecursive && join_type != Dsql::nod_join_inner)
+ {
+ ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) <<
+ // Recursive member of CTE can't be member of an outer join
+ Arg::Gds(isc_dsql_cte_outer_join));
+ }
+
+ if (leftRecursive && rightRecursive)
+ {
+ ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) <<
+ // Recursive member of CTE can't reference itself more than once
+ Arg::Gds(isc_dsql_cte_mult_references));
+ }
+
+ if (leftRecursive)
+ {
+ if (remove)
+ input = input->nod_arg[Dsql::e_join_rght_rel];
+
+ return leftBool;
+ }
+
+ if (rightRecursive)
+ {
+ if (remove)
+ input = input->nod_arg[Dsql::e_join_left_rel];
+
+ return rightBool;
+ }
+
+ return NULL;
+}
Property changes on: firebird/trunk/src/dsql/DsqlCompilerScratch.cpp
___________________________________________________________________
Added: svn:mime-type
+ text/plain
Added: svn:eol-style
+ native
Added: firebird/trunk/src/dsql/DsqlCompilerScratch.h
===================================================================
--- firebird/trunk/src/dsql/DsqlCompilerScratch.h (rev 0)
+++ firebird/trunk/src/dsql/DsqlCompilerScratch.h 2010-08-27 02:18:00 UTC (rev 51488)
@@ -0,0 +1,281 @@
+/*
+ *
+ * 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
+ */
+
+#ifndef DSQL_COMPILER_SCRATCH_H
+#define DSQL_COMPILER_SCRATCH_H
+
+#include "../jrd/common.h"
+#include "../dsql/dsql.h"
+#include "../dsql/BlrWriter.h"
+#include "../common/classes/array.h"
+#include "../common/classes/MetaName.h"
+#include "../common/classes/stack.h"
+#include "../common/classes/alloc.h"
+
+namespace Jrd
+{
+
+// DSQL Compiler scratch block - may be discarded after compilation in the future.
+class DsqlCompilerScratch : public BlrWriter
+{
+public:
+ static const unsigned FLAG_IN_AUTO_TRANS_BLOCK = 0x001;
+ static const unsigned FLAG_RETURNING_INTO = 0x002;
+ static const unsigned FLAG_METADATA_SAVED = 0x004;
+ static const unsigned FLAG_PROCEDURE = 0x008;
+ static const unsigned FLAG_TRIGGER = 0x010;
+ static const unsigned FLAG_BLOCK = 0x020;
+ static const unsigned FLAG_RECURSIVE_CTE = 0x040;
+ static const unsigned FLAG_UPDATE_OR_INSERT = 0x080;
+ static const unsigned FLAG_MERGE = 0x100;
+ static const unsigned FLAG_FUNCTION = 0x200;
+
+public:
+ DsqlCompilerScratch(MemoryPool& p, dsql_dbb* aDbb, jrd_tra* aTransaction,
+ DsqlCompiledStatement* aStatement)
+ : BlrWriter(p),
+ dbb(aDbb),
+ transaction(aTransaction),
+ statement(aStatement),
+ flags(0),
+ ports(p),
+ relation(NULL),
+ procedure(NULL),
+ mainContext(p),
+ context(&mainContext),
+ unionContext(p),
+ derivedContext(p),
+ outerAggContext(NULL),
+ contextNumber(0),
+ derivedContextNumber(0),
+ scopeLevel(0),
+ loopLevel(0),
+ labels(p),
+ cursorNumber(0),
+ cursors(p),
+ inSelectList(0),
+ inWhereClause(0),
+ inGroupByClause(0),
+ inHavingClause(0),
+ inOrderByClause(0),
+ errorHandlers(0),
+ clientDialect(0),
+ inOuterJoin(0),
+ aliasRelationPrefix(NULL),
+ hiddenVars(p),
+ hiddenVarsNumber(0),
+ package(p),
+ currCtes(p),
+ recursiveCtx(0),
+ recursiveCtxId(0),
+ processingWindow(false),
+ checkConstraintTrigger(false),
+ variables(p),
+ outputVariables(p),
+ ctes(p),
+ cteAliases(p),
+ currCteAlias(NULL),
+ psql(false)
+ {
+ domainValue.clear();
+ }
+
+protected:
+ // DsqlCompilerScratch should never be destroyed using delete.
+ // It dies together with it's pool in release_request().
+ ~DsqlCompilerScratch()
+ {
+ }
+
+ virtual bool isDdlDyn()
+ {
+ return (statement->getType() == DsqlCompiledStatement::TYPE_DDL || statement->getDdlNode()) &&
+ !(flags & FLAG_BLOCK);
+ }
+
+public:
+ virtual bool isVersion4()
+ {
+ return statement->getFlags() & DsqlCompiledStatement::FLAG_BLR_VERSION4;
+ }
+
+ MemoryPool& getPool()
+ {
+ return PermanentStorage::getPool();
+ }
+
+ dsql_dbb* getAttachment()
+ {
+ return dbb;
+ }
+
+ jrd_tra* getTransaction()
+ {
+ return transaction;
+ }
+
+ void setTransaction(jrd_tra* value)
+ {
+ transaction = value;
+ }
+
+ DsqlCompiledStatement* getStatement()
+ {
+ return statement;
+ }
+
+ DsqlCompiledStatement* getStatement() const
+ {
+ return statement;
+ }
+
+ void putDtype(const dsql_fld* field, bool useSubType);
+ void putLocalVariables(const dsql_nod* parameters, SSHORT locals);
+ void putLocalVariable(dsql_var* variable, dsql_nod* hostParam, const dsql_str* collationName);
+ dsql_nod* resolveVariable(const dsql_str* varName);
+ void genReturn(bool eosFlag = false);
+
+ void addCTEs(dsql_nod* list);
+ dsql_nod* findCTE(const dsql_str* name);
+ void clearCTEs();
+ void checkUnusedCTEs() const;
+
+ // hvlad: each member of recursive CTE can refer to CTE itself (only once) via
+ // CTE name or via alias. We need to substitute this aliases when processing CTE
+ // member to resolve field names. Therefore we store all aliases in order of
+ // occurrence and later use it in backward order (since our parser is right-to-left).
+ // Also we put CTE name after all such aliases to distinguish aliases for
+ // different CTE's.
+ // We also need to repeat this process if main select expression contains union with
+ // recursive CTE
+ void addCTEAlias(const dsql_str* alias)
+ {
+ cteAliases.add(alias);
+ }
+
+ const dsql_str* getNextCTEAlias()
+ {
+ return *(--currCteAlias);
+ }
+
+ void resetCTEAlias(const dsql_str* alias)
+ {
+ const dsql_str* const* begin = cteAliases.begin();
+
+ currCteAlias = cteAliases.end() - 1;
+ fb_assert(currCteAlias >= begin);
+
+ const dsql_str* curr = *(currCteAlias);
+ while (strcmp(curr->str_data, alias->str_data))
+ {
+ currCteAlias--;
+ fb_assert(currCteAlias >= begin);
+
+ curr = *(currCteAlias);
+ }
+ }
+
+ bool isPsql() const { return psql; }
+ void setPsql(bool value) { psql = value; }
+
+private:
+ dsql_nod* pass1RecursiveCte(dsql_nod* input);
+ dsql_nod* pass1RseIsRecursive(dsql_nod* input);
+ bool pass1RelProcIsRecursive(dsql_nod* input);
+ dsql_nod* pass1JoinIsRecursive(dsql_nod*& input);
+
+private:
+ dsql_dbb* dbb; // DSQL attachment
+ jrd_tra* transaction; // Transaction
+ DsqlCompiledStatement* statement; // Compiled statement
+
+public:
+ unsigned flags; // flags
+ Firebird::Array<dsql_msg*> ports; // Port messages
+ dsql_rel* relation; // relation created by this request (for DDL)
+ dsql_prc* procedure; // procedure created by this request (for DDL)
+ DsqlContextStack mainContext;
+ DsqlContextStack* context;
+ DsqlContextStack unionContext; // Save contexts for views of unions
+ DsqlContextStack derivedContext; // Save contexts for views of derived tables
+ dsql_ctx* outerAggContext; // agg context for outer ref
+ USHORT contextNumber; // Next available context number
+ USHORT derivedContextNumber; // Next available context number for derived tables
+ USHORT scopeLevel; // Scope level for parsing aliases in subqueries
+ USHORT loopLevel; // Loop level
+ DsqlStrStack labels; // Loop labels
+ USHORT cursorNumber; // Cursor number
+ DsqlNodStack cursors; // Cursors
+ USHORT inSelectList; // now processing "select list"
+ USHORT inWhereClause; // processing "where clause"
+ USHORT inGroupByClause; // processing "group by clause"
+ USHORT inHavingClause; // processing "having clause"
+ USHORT inOrderByClause; // processing "order by clause"
+ USHORT errorHandlers; // count of active error handlers
+ USHORT clientDialect; // dialect passed into the API call
+ USHORT inOuterJoin; // processing inside outer-join part
+ dsql_str* aliasRelationPrefix; // prefix for every relation-alias.
+ DsqlNodStack hiddenVars; // hidden variables
+ USHORT hiddenVarsNumber; // next hidden variable number
+ Firebird::MetaName package; // package being defined
+ DsqlNodStack currCtes; // current processing CTE's
+ class dsql_ctx* recursiveCtx; // context of recursive CTE
+ USHORT recursiveCtxId; // id of recursive union stream context
+ bool processingWindow; // processing window functions
+ bool checkConstraintTrigger; // compiling a check constraint trigger
+ dsc domainValue; // VALUE in the context of domain's check constraint
+ Firebird::Array<dsql_nod*> variables;
+ Firebird::Array<dsql_nod*> outputVariables;
+
+private:
+ Firebird::HalfStaticArray<dsql_nod*, 4> ctes; // common table expressions
+ Firebird::HalfStaticArray<const dsql_str*, 4> cteAliases; // CTE aliases in recursive members
+ const dsql_str* const* currCteAlias;
+ bool psql;
+};
+
+class PsqlChanger
+{
+public:
+ PsqlChanger(DsqlCompilerScratch* aDsqlScratch, bool value)
+ : dsqlScratch(aDsqlScratch),
+ oldValue(dsqlScratch->isPsql())
+ {
+ dsqlScratch->setPsql(value);
+ }
+
+ ~PsqlChanger()
+ {
+ dsqlScratch->setPsql(oldValue);
+ }
+
+private:
+ // copying is prohibited
+ PsqlChanger(const PsqlChanger&);
+ PsqlChanger& operator =(const PsqlChanger&);
+
+ DsqlCompilerScratch* dsqlScratch;
+ const bool oldValue;
+};
+
+} // namespace Jrd
+
+#endif // DSQL_COMPILER_SCRATCH_H
Property changes on: firebird/trunk/src/dsql/DsqlCompilerScratch.h
___________________________________________________________________
Added: svn:mime-type
+ text/plain
Added: svn:eol-style
+ native
Modified: firebird/trunk/src/dsql/Nodes.h
===================================================================
--- firebird/trunk/src/dsql/Nodes.h 2010-08-26 15:40:51 UTC (rev 51487)
+++ firebird/trunk/src/dsql/Nodes.h 2010-08-27 02:18:00 UTC (rev 51488)
@@ -24,7 +24,7 @@
#define DSQL_NODES_H
#include "../jrd/common.h"
-#include "../dsql/dsql.h"
+#include "../dsql/DsqlCompilerScratch.h"
#include "../dsql/node.h"
#include "../dsql/Visitors.h"
#include "../common/classes/array.h"
@@ -611,39 +611,6 @@
};
-// Common node for all "code blocks" (i.e.: procedures, triggers and execute block)
-class BlockNode
-{
-public:
- explicit BlockNode(MemoryPool& pool, bool aHasEos)
- : hasEos(aHasEos),
- variables(pool),
- outputVariables(pool)
- {
- }
-
- virtual ~BlockNode()
- {
- }
-
- static void putDtype(DsqlCompilerScratch* dsqlScratch, const dsql_fld* field, bool useSubType);
-
- void putLocalVariables(DsqlCompilerScratch* dsqlScratch, const dsql_nod* parameters,
- SSHORT locals);
- void putLocalVariable(DsqlCompilerScratch* dsqlScratch, dsql_var* variable,
- dsql_nod* hostParam, const dsql_str* collationName);
- dsql_nod* resolveVariable(const dsql_str* varName);
- void genReturn(DsqlCompilerScratch* dsqlScratch, bool eosFlag = false);
-
-private:
- bool hasEos;
-
-protected:
- Firebird::Array<dsql_nod*> variables;
- Firebird::Array<dsql_nod*> outputVariables;
-};
-
-
} // namespace
#endif // DSQL_NODES_H
Modified: firebird/trunk/src/dsql/StmtNodes.cpp
===================================================================
--- firebird/trunk/src/dsql/StmtNodes.cpp 2010-08-26 15:40:51 UTC (rev 51487)
+++ firebird/trunk/src/dsql/StmtNodes.cpp 2010-08-27 02:18:00 UTC (rev 51488)
@@ -52,278 +52,6 @@
namespace Jrd {
-// Write out field data type.
-// Taking special care to declare international text.
-void BlockNode::putDtype(DsqlCompilerScratch* dsqlScratch, const dsql_fld* field, bool useSubType)
-{
-#ifdef DEV_BUILD
- // Check if the field describes a known datatype
-
- if (field->fld_dtype > FB_NELEM(blr_dtypes) || !blr_dtypes[field->fld_dtype])
- {
- SCHAR buffer[100];
-
- sprintf(buffer, "Invalid dtype %d in BlockNode::putDtype", field->fld_dtype);
- ERRD_bugcheck(buffer);
- }
-#endif
-
- if (field->fld_not_nullable)
- dsqlScratch->appendUChar(blr_not_nullable);
-
- if (field->fld_type_of_name.hasData())
- {
- if (field->fld_type_of_table)
- {
- if (field->fld_explicit_collation)
- {
- dsqlScratch->appendUChar(blr_column_name2);
- dsqlScratch->appendUChar(field->fld_full_domain ? blr_domain_full : blr_domain_type_of);
- dsqlScratch->appendMetaString(field->fld_type_of_table->str_data);
- dsqlScratch->appendMetaString(field->fld_type_of_name.c_str());
- dsqlScratch->appendUShort(field->fld_ttype);
- }
- else
- {
- dsqlScratch->appendUChar(blr_column_name);
- dsqlScratch->appendUChar(field->fld_full_domain ? blr_domain_full : blr_domain_type_of);
- dsqlScratch->appendMetaString(field->fld_type_of_table->str_data);
- dsqlScratch->appendMetaString(field->fld_type_of_name.c_str());
- }
- }
- else
- {
- if (field->fld_explicit_collation)
- {
- dsqlScratch->appendUChar(blr_domain_name2);
- dsqlScratch->appendUChar(field->fld_full_domain ? blr_domain_full : blr_domain_type_of);
- dsqlScratch->appendMetaString(field->fld_type_of_name.c_str());
- dsqlScratch->appendUShort(field->fld_ttype);
- }
- else
- {
- dsqlScratch->appendUChar(blr_domain_name);
- dsqlScratch->appendUChar(field->fld_full_domain ? blr_domain_full : blr_domain_type_of);
- dsqlScratch->appendMetaString(field->fld_type_of_name.c_str());
- }
- }
-
- return;
- }
-
- switch (field->fld_dtype)
- {
- case dtype_cstring:
- case dtype_text:
- case dtype_varying:
- case dtype_blob:
- if (!useSubType)
- dsqlScratch->appendUChar(blr_dtypes[field->fld_dtype]);
- else if (field->fld_dtype == dtype_varying)
- {
- dsqlScratch->appendUChar(blr_varying2);
- dsqlScratch->appendUShort(field->fld_ttype);
- }
- else if (field->fld_dtype == dtype_cstring)
- {
- dsqlScratch->appendUChar(blr_cstring2);
- dsqlScratch->appendUShort(field->fld_ttype);
- }
- else if (field->fld_dtype == dtype_blob)
- {
- dsqlScratch->appendUChar(blr_blob2);
- dsqlScratch->appendUShort(field->fld_sub_type);
- dsqlScratch->appendUShort(field->fld_ttype);
- }
- else
- {
- dsqlScratch->appendUChar(blr_text2);
- dsqlScratch->appendUShort(field->fld_ttype);
- }
-
- if (field->fld_dtype == dtype_varying)
- dsqlScratch->appendUShort(field->fld_length - sizeof(USHORT));
- else if (field->fld_dtype != dtype_blob)
- dsqlScratch->appendUShort(field->fld_length);
- break;
-
- default:
- dsqlScratch->appendUChar(blr_dtypes[field->fld_dtype]);
- if (DTYPE_IS_EXACT(field->fld_dtype) || (dtype_quad == field->fld_dtype))
- dsqlScratch->appendUChar(field->fld_scale);
- break;
- }
-}
-
-// Emit dyn for the local variables declared in a procedure or trigger.
-void BlockNode::putLocalVariables(DsqlCompilerScratch* dsqlScratch, const dsql_nod* parameters,
- SSHORT locals)
-{
- if (!parameters)
- return;
-
- dsql_nod* const* ptr = parameters->nod_arg;
- for (const dsql_nod* const* const end = ptr + parameters->nod_count; ptr < end; ptr++)
- {
- dsql_nod* parameter = *ptr;
-
- dsqlScratch->putDebugSrcInfo(parameter->nod_line, parameter->nod_column);
-
- if (parameter->nod_type == Dsql::nod_def_field)
- {
- dsql_fld* field = (dsql_fld*) parameter->nod_arg[Dsql::e_dfl_field];
- const dsql_nod* const* rest = ptr;
- while (++rest != end)
- {
- if ((*rest)->nod_type == Dsql::nod_def_field)
- {
- const dsql_fld* rest_field = (dsql_fld*) (*rest)->nod_arg[Dsql::e_dfl_field];
- if (field->fld_name == rest_field->fld_name)
- {
- ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-637) <<
- Arg::Gds(isc_dsql_duplicate_spec) << Arg::Str(field->fld_name));
- }
- }
- }
-
- dsql_nod* var_node = MAKE_variable(field, field->fld_name.c_str(), VAR_local, 0, 0, locals);
- variables.add(var_node);
-
- dsql_var* variable = (dsql_var*) var_node->nod_arg[Dsql::e_var_variable];
- putLocalVariable(dsqlScratch, variable, parameter,
- reinterpret_cast<const dsql_str*>(parameter->nod_arg[Dsql::e_dfl_collate]));
-
- // Some field attributes are calculated inside
- // putLocalVariable(), so we reinitialize the
- // descriptor
- MAKE_desc_from_field(&var_node->nod_desc, field);
-
- locals++;
- }
- else if (parameter->nod_type == Dsql::nod_cursor)
- {
- PASS1_statement(dsqlScratch, parameter);
- GEN_statement(dsqlScratch, parameter);
- }
- }
-}
-
-// Write out local variable field data type.
-void BlockNode::putLocalVariable(DsqlCompilerScratch* dsqlScratch, dsql_var* variable,
- dsql_nod* hostParam, const dsql_str* collationName)
-{
- dsql_fld* field = variable->var_field;
-
- dsqlScratch->appendUChar(blr_dcl_variable);
- dsqlScratch->appendUShort(variable->var_variable_number);
- DDL_resolve_intl_type(dsqlScratch, field, collationName);
-
- //const USHORT dtype = field->fld_dtype;
-
- putDtype(dsqlScratch, field, true);
- //field->fld_dtype = dtype;
-
- // Check for a default value, borrowed from define_domain
- dsql_nod* node = hostParam ? hostParam->nod_arg[Dsql::e_dfl_default] : NULL;
-
- if (node || (!field->fld_full_domain && !field->fld_not_nullable))
- {
- dsqlScratch->appendUChar(blr_assignment);
-
- if (node)
- {
- fb_assert(node->nod_type == Dsql::nod_def_default);
- PsqlChanger psqlChanger(dsqlScratch, false);
- node = PASS1_node(dsqlScratch, node->nod_arg[Dsql::e_dft_default]);
- GEN_expr(dsqlScratch, node);
- }
- else
- dsqlScratch->appendUChar(blr_null); // Initialize variable to NULL
-
- dsqlScratch->appendUChar(blr_variable);
- dsqlScratch->appendUShort(variable->var_variable_number);
- }
- else
- {
- dsqlScratch->appendUChar(blr_init_variable);
- dsqlScratch->appendUShort(variable->var_variable_number);
- }
-
- if (variable->var_name[0]) // Not a function return value
- dsqlScratch->putDebugVariable(variable->var_variable_number, variable->var_name);
-
- ++dsqlScratch->hiddenVarsNumber;
-}
-
-// Try to resolve variable name against parameters and local variables.
-dsql_nod* BlockNode::resolveVariable(const dsql_str* varName)
-{
- for (dsql_nod* const* i = variables.begin(); i != variables.end(); ++i)
- {
- dsql_nod* var_node = *i;
- fb_assert(var_node->nod_type == Dsql::nod_variable);
-
- if (var_node->nod_type == Dsql::nod_variable)
- {
- const dsql_var* variable = (dsql_var*) var_node->nod_arg[Dsql::e_var_variable];
- DEV_BLKCHK(variable, dsql_type_var);
-
- if (!strcmp(varName->str_data, variable->var_name))
- return var_node;
- }
- }
-
- return NULL;
-}
-
-// Generate BLR for a return.
-void BlockNode::genReturn(DsqlCompilerScratch* dsqlScratch, bool eosFlag)
-{
- if (hasEos && !eosFlag)
- dsqlScratch->appendUChar(blr_begin);
-
- dsqlScratch->appendUChar(blr_send);
- dsqlScratch->appendUChar(1);
- dsqlScratch->appendUChar(blr_begin);
-
- for (Array<dsql_nod*>::const_iterator i = outputVariables.begin(); i != outputVariables.end(); ++i)
- {
- const dsql_nod* parameter = *i;
- const dsql_var* variable = (dsql_var*) parameter->nod_arg[Dsql::e_var_variable];
- dsqlScratch->appendUChar(blr_assignment);
- dsqlScratch->appendUChar(blr_variable);
- dsqlScratch->appendUShort(variable->var_variable_number);
- dsqlScratch->appendUChar(blr_parameter2);
- dsqlScratch->appendUChar(variable->var_msg_number);
- dsqlScratch->appendUShort(variable->var_msg_item);
- dsqlScratch->appendUShort(variable->var_msg_item + 1);
- }
-
- if (hasEos)
- {
- dsqlScratch->appendUChar(blr_assignment);
- dsqlScratch->appendUChar(blr_literal);
- dsqlScratch->appendUChar(blr_short);
- dsqlScratch->appendUChar(0);
- dsqlScratch->appendUShort((eosFlag ? 0 : 1));
- dsqlScratch->appendUChar(blr_parameter);
- dsqlScratch->appendUChar(1);
- dsqlScratch->appendUShort(USHORT(2 * outputVariables.getCount()));
- }
-
- dsqlScratch->appendUChar(blr_end);
-
- if (hasEos && !eosFlag)
- {
- dsqlScratch->appendUChar(blr_stall);
- dsqlScratch->appendUChar(blr_end);
- }
-}
-
-
-//--------------------
-
-
DmlNode* DmlNode::pass1(thread_db* tdbb, CompilerScratch* csb, jrd_nod* aNode)
{
node = aNode;
@@ -678,8 +406,6 @@
{
DsqlCompiledStatement* statement = dsqlScratch->getStatement();
- statement->setBlockNode(this);
-
if (returns.hasData())
statement->setType(DsqlCompiledStatement::TYPE_SELECT_BLOCK);
else
@@ -793,11 +519,6 @@
void ExecBlockNode::genBlr()
{
- DsqlCompiledStatement* statement = dsqlScratch->getStatement();
-
- // Update blockNode, because we have a reference to the original unprocessed node.
- statement->setBlockNode(this);
-
dsqlScratch->beginDebug();
// now do the input parameters
@@ -808,10 +529,10 @@
dsql_nod* var = MAKE_variable(parameter.legacyField,
parameter.name.c_str(), VAR_input, 0, (USHORT) (2 * i), 0);
- variables.add(var);
+ dsqlScratch->variables.add(var);
}
- const unsigned returnsPos = variables.getCount();
+ const unsigned returnsPos = dsqlScratch->variables.getCount();
// now do the output parameters
for (size_t i = 0; i < returns.getCount(); ++i)
@@ -821,10 +542,12 @@
dsql_nod* var = MAKE_variable(parameter.legacyField,
parameter.name.c_str(), VAR_output, 1, (USHORT) (2 * i), i);
- variables.add(var);
- outputVariables.add(var);
+ dsqlScratch->variables.add(var);
+ dsqlScratch->outputVariables.add(var);
}
+ DsqlCompiledStatement* statement = dsqlScratch->getStatement();
+
dsqlScratch->appendUChar(blr_begin);
if (parameters.hasData())
@@ -835,10 +558,12 @@
else
statement->setSendMsg(NULL);
- for (Array<dsql_nod*>::const_iterator i = outputVariables.begin(); i != outputVariables.end(); ++i)
+ for (Array<dsql_nod*>::const_iterator i = dsqlScratch->outputVariables.begin();
+ i != dsqlScratch->outputVariables.end();
+ ++i)
{
dsql_par* param = MAKE_parameter(statement->getReceiveMsg(), true, true,
- (i - outputVariables.begin()) + 1, *i);
+ (i - dsqlScratch->outputVariables.begin()) + 1, *i);
param->par_node = *i;
MAKE_desc(dsqlScratch, ¶m->par_desc, *i, NULL);
param->par_desc.dsc_flags |= DSC_nullable;
@@ -864,7 +589,7 @@
for (unsigned i = 0; i < returnsPos; ++i)
{
- const dsql_nod* parameter = variables[i];
+ const dsql_nod* parameter = dsqlScratch->variables[i];
const dsql_var* variable = (dsql_var*) parameter->nod_arg[Dsql::e_var_variable];
const dsql_fld* field = variable->var_field;
@@ -875,7 +600,7 @@
// connection charset influence. So to validate, we cast them and assign to null.
dsqlScratch->appendUChar(blr_assignment);
dsqlScratch->appendUChar(blr_cast);
- BlockNode::putDtype(dsqlScratch, field, true);
+ dsqlScratch->putDtype(field, true);
dsqlScratch->appendUChar(blr_parameter2);
dsqlScratch->appendUChar(0);
dsqlScratch->appendUShort(variable->var_msg_item);
@@ -884,16 +609,18 @@
}
}
- for (Array<dsql_nod*>::const_iterator i = outputVariables.begin(); i != outputVariables.end(); ++i)
+ for (Array<dsql_nod*>::const_iterator i = dsqlScratch->outputVariables.begin();
+ i != dsqlScratch->outputVariables.end();
+ ++i)
{
dsql_nod* parameter = *i;
dsql_var* variable = (dsql_var*) parameter->nod_arg[Dsql::e_var_variable];
- putLocalVariable(dsqlScratch, variable, 0, NULL);
+ dsqlScratch->putLocalVariable(variable, 0, NULL);
}
dsqlScratch->setPsql(true);
- putLocalVariables(dsqlScratch, localDeclList, USHORT(returns.getCount()));
+ dsqlScratch->putLocalVariables(localDeclList, USHORT(returns.getCount()));
dsqlScratch->loopLevel = 0;
@@ -912,7 +639,7 @@
statement->setType(DsqlCompiledStatement::TYPE_EXEC_BLOCK);
dsqlScratch->appendUChar(blr_end);
- genReturn(dsqlScratch, true);
+ dsqlScratch->genReturn(true);
dsqlScratch->appendUChar(blr_end);
dsqlScratch->endDebug();
@@ -1799,8 +1526,6 @@
statement->addFlags(DsqlCompiledStatement::FLAG_SELECTABLE);
- blockNode = statement->getBlockNode();
-
return this;
}
@@ -1813,8 +1538,7 @@
void SuspendNode::genBlr()
{
- if (blockNode)
- blockNode->genReturn(dsqlScratch);
+ dsqlScratch->genReturn();
}
@@ -1879,7 +1603,6 @@
ReturnNode* node = FB_NEW(getPool()) ReturnNode(getPool());
node->dsqlScratch = dsqlScratch;
- node->blockNode = statement->getBlockNode();
node->value = PASS1_node(dsqlScratch, value);
return node;
@@ -1899,9 +1622,7 @@
GEN_expr(dsqlScratch, value);
dsqlScratch->appendUChar(blr_variable);
dsqlScratch->appendUShort(0);
-
- blockNode->genReturn(dsqlScratch);
-
+ dsqlScratch->genReturn();
dsqlScratch->appendUChar(blr_leave);
dsqlScratch->appendUChar(0);
}
Modified: firebird/trunk/src/dsql/StmtNodes.h
===================================================================
--- firebird/trunk/src/dsql/StmtNodes.h 2010-08-26 15:40:51 UTC (rev 51487)
+++ firebird/trunk/src/dsql/StmtNodes.h 2010-08-27 02:18:00 UTC (rev 51488)
@@ -103,12 +103,11 @@
};
-class ExecBlockNode : public DsqlOnlyStmtNode, public BlockNode
+class ExecBlockNode : public DsqlOnlyStmtNode
{
public:
explicit ExecBlockNode(MemoryPool& pool)
: DsqlOnlyStmtNode(pool),
- BlockNode(pool, true),
parameters(pool),
returns(pool),
localDeclList(NULL),
@@ -319,7 +318,6 @@
public:
explicit SuspendNode(MemoryPool& pool)
: StmtNode(pool),
- blockNode(NULL),
message(NULL),
statement(NULL)
{
@@ -339,7 +337,6 @@
virtual const jrd_nod* execute(thread_db* tdbb, jrd_req* request) const;
public:
- BlockNode* blockNode;
NestConst<jrd_nod> message;
NestConst<jrd_nod> statement;
};
@@ -361,7 +358,6 @@
virtual void genBlr();
public:
- BlockNode* blockNode;
dsql_nod* value;
};
Modified: firebird/trunk/src/dsql/dsql.h
===================================================================
--- firebird/trunk/src/dsql/dsql.h 2010-08-26 15:40:51 UTC (rev 51487)
+++ firebird/trunk/src/dsql/dsql.h 2010-08-27 02:18:00 UTC (rev 51488)
@@ -66,14 +66,14 @@
namespace Jrd
{
- class Database;
class Attachment;
+ class Database;
+ class DsqlCompilerScratch;
class jrd_tra;
class jrd_req;
class blb;
struct bid;
- class BlockNode;
class dsql_blb;
class dsql_ctx;
class dsql_msg;
@@ -103,8 +103,6 @@
namespace Jrd {
-class DsqlCompilerScratch;
-
//! generic data type used to store strings
class dsql_str : public pool_alloc_rpt<char, dsql_type_str>
{
@@ -416,7 +414,6 @@
type(TYPE_SELECT),
flags(0),
ddlData(p),
- blockNode(NULL),
ddlNode(NULL),
blob(NULL),
sendMsg(NULL),
@@ -448,10 +445,6 @@
const Firebird::HalfStaticArray<UCHAR, 1024>& getDdlData() const { return ddlData; }
void setDdlData(Firebird::HalfStaticArray<UCHAR, 1024>& value) { ddlData = value; }
- BlockNode* getBlockNode() { return blockNode; }
- const BlockNode* getBlockNode() const { return blockNode; }
- void setBlockNode(BlockNode* value) { blockNode = value; }
-
dsql_nod* getDdlNode() { return ddlNode; }
const dsql_nod* getDdlNode() const { return ddlNode; }
void setDdlNode(dsql_nod* value) { ddlNode = value; }
@@ -496,7 +489,6 @@
ULONG flags; // generic flag
Firebird::RefStrPtr sqlText;
Firebird::HalfStaticA...
[truncated message content] |