8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-22 16:03:03 +01:00

Started simplification of local declarations.

This commit is contained in:
Adriano dos Santos Fernandes 2023-09-18 20:27:14 -03:00
parent 2d8f94862b
commit bf72356edb
10 changed files with 224 additions and 237 deletions

View File

@ -1664,26 +1664,7 @@ DdlNode* CreateAlterFunctionNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
{
dsqlScratch->flags |= (DsqlCompilerScratch::FLAG_BLOCK | DsqlCompilerScratch::FLAG_FUNCTION);
// check for duplicated parameters and declaration names
StrArray names;
for (FB_SIZE_T i = 0; i < parameters.getCount(); ++i)
{
const ParameterClause* const parameter = parameters[i];
if (names.exist(parameter->name.c_str()))
{
status_exception::raise(
Arg::Gds(isc_sqlerr) << Arg::Num(-901) <<
Arg::Gds(isc_dsql_duplicate_spec) << Arg::Str(parameter->name));
}
if (parameter->name.hasData()) // legacy UDFs has unnamed parameters
names.add(parameter->name.c_str());
}
PASS1_check_unique_fields_names(names, localDeclList);
LocalDeclarationsNode::checkUniqueFieldsNames(localDeclList, &parameters, nullptr);
source.ltrim("\n\r\t ");
@ -2329,7 +2310,8 @@ void CreateAlterFunctionNode::compile(thread_db* /*tdbb*/, DsqlCompilerScratch*
// of previous calls to PASS1_node and PASS1_statement.
dsqlScratch->setPsql(true);
dsqlScratch->putLocalVariables(localDeclList, 1);
if (localDeclList)
localDeclList->genBlr(dsqlScratch);
dsqlScratch->loopLevel = 0;
dsqlScratch->cursorNumber = 0;
@ -2635,39 +2617,7 @@ DdlNode* CreateAlterProcedureNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
{
dsqlScratch->flags |= (DsqlCompilerScratch::FLAG_BLOCK | DsqlCompilerScratch::FLAG_PROCEDURE);
// check for duplicated parameters and declaration names
StrArray names;
for (FB_SIZE_T i = 0; i < parameters.getCount(); ++i)
{
const ParameterClause* const parameter = parameters[i];
if (names.exist(parameter->name.c_str()))
{
status_exception::raise(
Arg::Gds(isc_sqlerr) << Arg::Num(-901) <<
Arg::Gds(isc_dsql_duplicate_spec) << Arg::Str(parameter->name));
}
names.add(parameter->name.c_str());
}
for (FB_SIZE_T i = 0; i < returns.getCount(); ++i)
{
const ParameterClause* const parameter = returns[i];
if (names.exist(parameter->name.c_str()))
{
status_exception::raise(
Arg::Gds(isc_sqlerr) << Arg::Num(-901) <<
Arg::Gds(isc_dsql_duplicate_spec) << Arg::Str(parameter->name));
}
names.add(parameter->name.c_str());
}
PASS1_check_unique_fields_names(names, localDeclList);
LocalDeclarationsNode::checkUniqueFieldsNames(localDeclList, &parameters, &returns);
source.ltrim("\n\r\t ");
@ -3200,7 +3150,8 @@ void CreateAlterProcedureNode::compile(thread_db* /*tdbb*/, DsqlCompilerScratch*
// of previous calls to PASS1_node and PASS1_statement.
dsqlScratch->setPsql(true);
dsqlScratch->putLocalVariables(localDeclList, returns.getCount());
if (localDeclList)
localDeclList->genBlr(dsqlScratch);
dsqlScratch->loopLevel = 0;
dsqlScratch->cursorNumber = 0;
@ -3717,7 +3668,9 @@ void CreateAlterTriggerNode::compile(thread_db* /*tdbb*/, DsqlCompilerScratch* d
dsqlScratch->appendUChar(blr_begin);
dsqlScratch->setPsql(true);
dsqlScratch->putLocalVariables(localDeclList, 0);
if (localDeclList)
localDeclList->genBlr(dsqlScratch);
dsqlScratch->loopLevel = 0;
dsqlScratch->cursorNumber = 0;

View File

@ -39,7 +39,7 @@
namespace Jrd {
class CompoundStmtNode;
class LocalDeclarationsNode;
class RelationSourceNode;
class ValueListNode;
class SecDbContext;
@ -469,7 +469,7 @@ public:
bool deterministic;
Firebird::Array<NestConst<ParameterClause> > parameters;
NestConst<ParameterClause> returnType;
NestConst<CompoundStmtNode> localDeclList;
NestConst<LocalDeclarationsNode> localDeclList;
Firebird::string source;
NestConst<StmtNode> body;
bool compiled;
@ -605,7 +605,7 @@ public:
Firebird::Array<NestConst<ParameterClause> > parameters;
Firebird::Array<NestConst<ParameterClause> > returns;
Firebird::string source;
NestConst<CompoundStmtNode> localDeclList;
NestConst<LocalDeclarationsNode> localDeclList;
NestConst<StmtNode> body;
bool compiled;
bool invalid;
@ -782,7 +782,7 @@ private:
public:
bool create;
bool alter;
NestConst<CompoundStmtNode> localDeclList;
NestConst<LocalDeclarationsNode> localDeclList;
NestConst<StmtNode> body;
bool compiled;
bool invalid;

View File

@ -283,97 +283,6 @@ void DsqlCompilerScratch::putType(const TypeClause* type, bool useSubType)
}
}
// Emit dyn for the local variables declared in a procedure or trigger.
void DsqlCompilerScratch::putLocalVariables(CompoundStmtNode* parameters, USHORT locals)
{
if (!parameters)
return;
Array<dsql_var*> declaredVariables;
const auto end = parameters->statements.end();
for (auto ptr = parameters->statements.begin(); ptr != end; ++ptr)
{
auto parameter = *ptr;
putDebugSrcInfo(parameter->line, parameter->column);
if (const auto varNode = nodeAs<DeclareVariableNode>(parameter))
{
dsql_fld* field = varNode->dsqlDef->type;
const NestConst<StmtNode>* rest = ptr;
while (++rest != end)
{
if (const auto varNode2 = nodeAs<DeclareVariableNode>(*rest))
{
const dsql_fld* rest_field = varNode2->dsqlDef->type;
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));
}
}
}
const auto variable = makeVariable(field, field->fld_name.c_str(), dsql_var::TYPE_LOCAL, 0, 0, locals);
declaredVariables.add(variable);
putLocalVariableDecl(variable, varNode, varNode->dsqlDef->type->collate);
// Some field attributes are calculated inside putLocalVariable(), so we reinitialize
// the descriptor.
DsqlDescMaker::fromField(&variable->desc, field);
++locals;
}
else if (nodeIs<DeclareCursorNode>(parameter) ||
nodeIs<DeclareSubProcNode>(parameter) ||
nodeIs<DeclareSubFuncNode>(parameter))
{
parameter->dsqlPass(this);
parameter->genBlr(this);
}
else
fb_assert(false);
}
auto declVarIt = declaredVariables.begin();
for (const auto parameter : parameters->statements)
{
if (const auto varNode = nodeAs<DeclareVariableNode>(parameter))
putLocalVariableInit(*declVarIt++, varNode);
}
if (!(flags & DsqlCompilerScratch::FLAG_SUB_ROUTINE))
{
// Check not implemented sub-functions.
for (const auto& [name, subFunc] : subFunctions)
{
if (subFunc->isForwardDecl())
{
status_exception::raise(
Arg::Gds(isc_subfunc_not_impl) <<
name.c_str());
}
}
// Check not implemented sub-procedures.
for (const auto& [name, subProc] : subProcedures)
{
if (subProc->isForwardDecl())
{
status_exception::raise(
Arg::Gds(isc_subproc_not_impl) <<
name.c_str());
}
}
}
}
// Write out local variable field data type.
void DsqlCompilerScratch::putLocalVariableDecl(dsql_var* variable, DeclareVariableNode* hostParam,
const MetaName& collationName)

View File

@ -35,7 +35,7 @@ namespace Jrd
{
class BinaryBoolNode;
class CompoundStmtNode;
class LocalDeclarationsNode;
class DeclareCursorNode;
class DeclareLocalTableNode;
class DeclareVariableNode;
@ -153,7 +153,6 @@ public:
void putBlrMarkers(ULONG marks);
void putDtype(const TypeClause* field, bool useSubType);
void putType(const TypeClause* type, bool useSubType);
void putLocalVariables(CompoundStmtNode* parameters, USHORT locals);
void putLocalVariableDecl(dsql_var* variable, DeclareVariableNode* hostParam, const MetaName& collationName);
void putLocalVariableInit(dsql_var* variable, const DeclareVariableNode* hostParam);
@ -238,9 +237,19 @@ public:
bool isPsql() const { return psql; }
void setPsql(bool value) { psql = value; }
const auto& getSubFunctions() const
{
return subFunctions;
}
DeclareSubFuncNode* getSubFunction(const MetaName& name);
void putSubFunction(DeclareSubFuncNode* subFunc, bool replace = false);
const auto& getSubProcedures() const
{
return subProcedures;
}
DeclareSubProcNode* getSubProcedure(const MetaName& name);
void putSubProcedure(DeclareSubProcNode* subProc, bool replace = false);

View File

@ -1432,6 +1432,7 @@ public:
TYPE_HANDLER,
TYPE_LABEL,
TYPE_LINE_COLUMN,
TYPE_LOCAL_DECLARATIONS,
TYPE_LOOP,
TYPE_MERGE,
TYPE_MERGE_SEND,

View File

@ -4354,34 +4354,7 @@ ExecBlockNode* ExecBlockNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
node->localDeclList = localDeclList;
node->body = body;
const FB_SIZE_T count = node->parameters.getCount() + node->returns.getCount() +
(node->localDeclList ? node->localDeclList->statements.getCount() : 0);
if (count != 0)
{
StrArray names(*getDefaultMemoryPool(), count);
// Hand-made PASS1_check_unique_fields_names for arrays of ParameterClause
Array<NestConst<ParameterClause> > params(parameters);
params.add(returns.begin(), returns.getCount());
for (FB_SIZE_T i = 0; i < params.getCount(); ++i)
{
ParameterClause* parameter = params[i];
FB_SIZE_T pos;
if (!names.find(parameter->name.c_str(), pos))
names.insert(pos, parameter->name.c_str());
else
{
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-637) <<
Arg::Gds(isc_dsql_duplicate_spec) << Arg::Str(parameter->name));
}
}
PASS1_check_unique_fields_names(names, node->localDeclList);
}
LocalDeclarationsNode::checkUniqueFieldsNames(node->localDeclList, &parameters, &returns);
return node;
}
@ -4507,15 +4480,15 @@ void ExecBlockNode::genBlr(DsqlCompilerScratch* dsqlScratch)
}
}
const Array<dsql_var*>& variables = subRoutine ? dsqlScratch->outputVariables : dsqlScratch->variables;
const auto& variables = subRoutine ? dsqlScratch->outputVariables : dsqlScratch->variables;
for (const auto variable : variables)
dsqlScratch->putLocalVariable(variable, nullptr, {});
dsqlScratch->setPsql(true);
dsqlScratch->putLocalVariables(localDeclList,
USHORT((subRoutine ? 0 : parameters.getCount()) + returns.getCount()));
if (localDeclList)
localDeclList->genBlr(dsqlScratch);
dsqlScratch->loopLevel = 0;
@ -5442,6 +5415,166 @@ void LineColumnNode::genBlr(DsqlCompilerScratch* dsqlScratch)
//--------------------
// Check duplicate fields (params, variables, cursors etc).
void LocalDeclarationsNode::checkUniqueFieldsNames(const LocalDeclarationsNode* node,
const Array<NestConst<ParameterClause>>* inputParameters,
const Array<NestConst<ParameterClause>>* outputParameters)
{
const FB_SIZE_T count = (inputParameters ? inputParameters->getCount() : 0) +
(outputParameters ? outputParameters->getCount() : 0) +
(node ? node->statements.getCount() : 0);
StrArray names(*getDefaultMemoryPool(), count);
for (const auto parameters : {inputParameters, outputParameters})
{
if (parameters)
{
for (const auto parameter : *parameters)
{
if (parameter->name.hasData()) // legacy UDFs has unnamed parameters
{
FB_SIZE_T pos;
if (!names.find(parameter->name.c_str(), pos))
names.insert(pos, parameter->name.c_str());
else
{
ERRD_post(
Arg::Gds(isc_sqlerr) << Arg::Num(-637) <<
Arg::Gds(isc_dsql_duplicate_spec) << Arg::Str(parameter->name));
}
}
}
}
}
if (node)
{
for (const auto statement : node->statements)
{
const char* name = nullptr;
if (auto varNode = nodeAs<DeclareVariableNode>(statement))
name = varNode->dsqlDef->name.c_str();
else if (auto cursorNode = nodeAs<DeclareCursorNode>(statement))
name = cursorNode->dsqlName.c_str();
else if (nodeAs<DeclareSubProcNode>(statement) || nodeAs<DeclareSubFuncNode>(statement))
continue;
fb_assert(name);
FB_SIZE_T pos;
if (!names.find(name, pos))
names.insert(pos, name);
else
{
ERRD_post(
Arg::Gds(isc_sqlerr) << Arg::Num(-637) <<
Arg::Gds(isc_dsql_duplicate_spec) << Arg::Str(name));
}
}
}
}
void LocalDeclarationsNode::genBlr(DsqlCompilerScratch* dsqlScratch)
{
// Sub routine needs a different approach from EXECUTE BLOCK.
// EXECUTE BLOCK needs "ports", which creates DSQL messages using the client charset.
// Sub routine doesn't need ports and should generate BLR as declared in its metadata.
const bool isSubRoutine = dsqlScratch->flags & DsqlCompilerScratch::FLAG_SUB_ROUTINE;
const auto& variables = isSubRoutine ? dsqlScratch->outputVariables : dsqlScratch->variables;
USHORT locals = variables.getCount();
Array<dsql_var*> declaredVariables;
const auto end = statements.end();
for (auto ptr = statements.begin(); ptr != end; ++ptr)
{
auto parameter = *ptr;
dsqlScratch->putDebugSrcInfo(parameter->line, parameter->column);
if (const auto varNode = nodeAs<DeclareVariableNode>(parameter))
{
dsql_fld* field = varNode->dsqlDef->type;
const NestConst<StmtNode>* rest = ptr;
while (++rest != end)
{
if (const auto varNode2 = nodeAs<DeclareVariableNode>(*rest))
{
const dsql_fld* rest_field = varNode2->dsqlDef->type;
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));
}
}
}
const auto variable = dsqlScratch->makeVariable(field, field->fld_name.c_str(),
dsql_var::TYPE_LOCAL, 0, 0, locals);
declaredVariables.add(variable);
dsqlScratch->putLocalVariableDecl(variable, varNode, varNode->dsqlDef->type->collate);
// Some field attributes are calculated inside putLocalVariable(), so we reinitialize
// the descriptor.
DsqlDescMaker::fromField(&variable->desc, field);
++locals;
}
else if (nodeIs<DeclareCursorNode>(parameter) ||
nodeIs<DeclareSubProcNode>(parameter) ||
nodeIs<DeclareSubFuncNode>(parameter))
{
parameter->dsqlPass(dsqlScratch);
parameter->genBlr(dsqlScratch);
}
else
fb_assert(false);
}
auto declVarIt = declaredVariables.begin();
for (const auto parameter : statements)
{
if (const auto varNode = nodeAs<DeclareVariableNode>(parameter))
dsqlScratch->putLocalVariableInit(*declVarIt++, varNode);
}
if (!isSubRoutine)
{
// Check not implemented sub-functions.
for (const auto& [name, subFunc] : dsqlScratch->getSubFunctions())
{
if (subFunc->isForwardDecl())
{
status_exception::raise(
Arg::Gds(isc_subfunc_not_impl) <<
name.c_str());
}
}
// Check not implemented sub-procedures.
for (const auto& [name, subProc] : dsqlScratch->getSubProcedures())
{
if (subProc->isForwardDecl())
{
status_exception::raise(
Arg::Gds(isc_subproc_not_impl) <<
name.c_str());
}
}
}
}
//--------------------
static RegisterNode<LoopNode> regLoopNode({blr_loop});
DmlNode* LoopNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR /*blrOp*/)

View File

@ -791,7 +791,7 @@ private:
public:
Firebird::Array<NestConst<ParameterClause>> parameters;
Firebird::Array<NestConst<ParameterClause>> returns;
NestConst<CompoundStmtNode> localDeclList;
NestConst<LocalDeclarationsNode> localDeclList;
NestConst<StmtNode> body;
};
@ -989,6 +989,28 @@ private:
};
class LocalDeclarationsNode final : public TypedNode<DsqlOnlyStmtNode, StmtNode::TYPE_LOCAL_DECLARATIONS>
{
public:
explicit LocalDeclarationsNode(MemoryPool& pool)
: TypedNode<DsqlOnlyStmtNode, StmtNode::TYPE_LOCAL_DECLARATIONS>(pool),
statements(pool)
{
}
public:
static void checkUniqueFieldsNames(const LocalDeclarationsNode* node,
const Firebird::Array<NestConst<ParameterClause>>* inputParameters,
const Firebird::Array<NestConst<ParameterClause>>* outputParameters);
public:
void genBlr(DsqlCompilerScratch* dsqlScratch) override;
public:
Firebird::Array<NestConst<StmtNode>> statements;
};
class LoopNode final : public TypedNode<StmtNode, StmtNode::TYPE_LOOP>
{
public:

View File

@ -831,6 +831,7 @@ using namespace Firebird;
Jrd::DeclareCursorNode* declCursorNode;
Jrd::ErrorHandlerNode* errorHandlerNode;
Jrd::ExecStatementNode* execStatementNode;
Jrd::LocalDeclarationsNode* localDeclarationsNode;
Jrd::MergeNode* mergeNode;
Jrd::MergeNode::NotMatched* mergeNotMatchedClause;
Jrd::MergeNode::Matched* mergeMatchedClause;
@ -3025,12 +3026,12 @@ package_body_item
;
%type <compoundStmtNode> local_declarations_opt
%type <localDeclarationsNode> local_declarations_opt
local_declarations_opt
: local_forward_declarations_opt local_nonforward_declarations_opt
{
CompoundStmtNode* forward = $1;
CompoundStmtNode* nonForward = $2;
LocalDeclarationsNode* forward = $1;
LocalDeclarationsNode* nonForward = $2;
if (!forward)
$$ = nonForward;
@ -3044,17 +3045,17 @@ local_declarations_opt
}
;
%type <compoundStmtNode> local_forward_declarations_opt
%type <localDeclarationsNode> local_forward_declarations_opt
local_forward_declarations_opt
: /* nothing */ { $$ = NULL; }
: /* nothing */ { $$ = nullptr; }
| local_forward_declarations
;
%type <compoundStmtNode> local_forward_declarations
%type <localDeclarationsNode> local_forward_declarations
local_forward_declarations
: local_forward_declaration
{
$$ = newNode<CompoundStmtNode>();
$$ = newNode<LocalDeclarationsNode>();
$$->statements.add($1);
}
| local_forward_declarations local_forward_declaration
@ -3070,17 +3071,17 @@ local_forward_declaration
| local_declaration_subfunc_start ';' { $$ = $1; }
;
%type <compoundStmtNode> local_nonforward_declarations_opt
%type <localDeclarationsNode> local_nonforward_declarations_opt
local_nonforward_declarations_opt
: /* nothing */ { $$ = NULL; }
: /* nothing */ { $$ = nullptr; }
| local_nonforward_declarations
;
%type <compoundStmtNode> local_nonforward_declarations
%type <localDeclarationsNode> local_nonforward_declarations
local_nonforward_declarations
: local_nonforward_declaration
{
$$ = newNode<CompoundStmtNode>();
$$ = newNode<LocalDeclarationsNode>();
$$->statements.add($1);
}
| local_nonforward_declarations local_nonforward_declaration

View File

@ -672,46 +672,6 @@ void PASS1_ambiguity_check(DsqlCompilerScratch* dsqlScratch,
}
/**
PASS1_check_unique_fields_names
check fields (params, variables, cursors etc) names against
sorted array
if success, add them into array
**/
void PASS1_check_unique_fields_names(StrArray& names, const CompoundStmtNode* fields)
{
if (!fields)
return;
const NestConst<StmtNode>* ptr = fields->statements.begin();
const NestConst<StmtNode>* const end = fields->statements.end();
for (; ptr != end; ++ptr)
{
const char* name = NULL;
if (auto varNode = nodeAs<DeclareVariableNode>(*ptr))
name = varNode->dsqlDef->name.c_str();
else if (auto cursorNode = nodeAs<DeclareCursorNode>(*ptr))
name = cursorNode->dsqlName.c_str();
else if (nodeAs<DeclareSubProcNode>(*ptr) || nodeAs<DeclareSubFuncNode>(*ptr))
continue;
fb_assert(name);
FB_SIZE_T pos;
if (!names.find(name, pos))
names.insert(pos, name);
else
{
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-637) <<
Arg::Gds(isc_dsql_duplicate_spec) << Arg::Str(name));
}
}
}
// Compose two booleans.
BoolExprNode* PASS1_compose(BoolExprNode* expr1, BoolExprNode* expr2, UCHAR blrOp)
{

View File

@ -39,7 +39,6 @@ namespace Jrd
}
void PASS1_ambiguity_check(Jrd::DsqlCompilerScratch*, const Jrd::MetaName&, const Jrd::DsqlContextStack&);
void PASS1_check_unique_fields_names(Jrd::StrArray& names, const Jrd::CompoundStmtNode* fields);
Jrd::BoolExprNode* PASS1_compose(Jrd::BoolExprNode*, Jrd::BoolExprNode*, UCHAR);
Jrd::DeclareCursorNode* PASS1_cursor_name(Jrd::DsqlCompilerScratch*, const Jrd::MetaName&, USHORT, bool);
Jrd::RseNode* PASS1_derived_table(Jrd::DsqlCompilerScratch*, Jrd::SelectExprNode*, const char*,