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

Improvement CORE-5380 - Allow subroutines to call others subroutines and themself recursively.

This commit is contained in:
Adriano dos Santos Fernandes 2017-07-11 13:01:38 +00:00
parent f350cccf85
commit 4be766b8c8
24 changed files with 807 additions and 359 deletions

View File

@ -58,6 +58,10 @@
Reference(s): [doc/sql.extensions/README.identity_columns](https://github.com/FirebirdSQL/firebird/raw/master/doc/sql.extensions/README.identity_columns.txt)
Contributor(s): Adriano dos Santos Fernandes
* [CORE-5380](http://tracker.firebirdsql.org/browse/CORE-5380): Allow subroutines to call others subroutines and themself recursively
Reference(s): [doc/sql.extensions/README.subroutines.txt](https://github.com/FirebirdSQL/firebird/raw/master/doc/sql.extensions/README.subroutines.txt)
Contributor(s): Adriano dos Santos Fernandes
* [CORE-5119](http://tracker.firebirdsql.org/browse/CORE-5119): Support autocommit mode in SET TRANSACTION statement
Contributor(s): Dmitry Yemanov

View File

@ -7,7 +7,7 @@ Author:
Description:
Support for PSQL subroutines (functions and procedures) inside functions, procedures, triggers
and EXECUTE BLOCK. Subroutines are declared in the main routine and may be used from there.
and EXECUTE BLOCK. Subroutines are declared in the main routine and may be used from there or others subroutines.
Syntax:
<declaration item> ::=
@ -15,7 +15,21 @@ Syntax:
|
DECLARE [VARIABLE] CURSOR <cursor name> FOR (<query>);
|
DECLARE FUNCTION <function name> RETURNS <data type>
<subroutine declaration>
|
<subroutine implementation>
<subroutine declaration> ::=
DECLARE FUNCTION <function name> [ (<input parameters>) ]
RETURNS <data type>
[ [ NOT ] DETERMINISTIC ] ;
|
DECLARE PROCEDURE <procedure name> [ (<input parameters>) ] [ RETURNS (<output parameters>) ] ;
<subroutine implementation> ::=
DECLARE FUNCTION <function name> [ (<input parameters>) ]
RETURNS <data type>
[ [ NOT ] DETERMINISTIC ]
AS
...
BEGIN
@ -32,8 +46,11 @@ Syntax:
Limitations:
1) Subroutines may not be nested in another subroutine. They are only supported in the main
routine.
2) Currently, a subroutine may not directly access or use variables, cursors or another
subroutines of the main statements. This may be allowed in the future.
2) Currently, a subroutine may not directly access or use variables or cursors of the
main statements. This may be allowed in the future.
Notes:
1) Starting in FB 4, subroutines may be recursive or call others subroutines.
Examples:
set term !;
@ -89,3 +106,57 @@ Examples:
end!
select func1(5, 6) from rdb$database!
-- 3) Recursive sub-function in EXECUTE BLOCK.
execute block returns (i integer, o integer)
as
-- Recursive function without forward declaration.
declare function fibonacci(n integer) returns integer
as
begin
if (n = 0 or n = 1) then
return n;
else
return fibonacci(n - 1) + fibonacci(n - 2);
end
begin
i = 0;
while (i < 10)
do
begin
o = fibonacci(i);
suspend;
i = i + 1;
end
end!
-- 4) Example with forward declaration and parameter with default values.
execute block returns (o integer)
as
-- Forward declaration of P1.
declare procedure p1(i integer = 1) returns (o integer);
-- Forward declaration of P2.
declare procedure p2(i integer) returns (o integer);
-- Implementation of P1 should not re-declare parameter default value.
declare procedure p1(i integer) returns (o integer)
as
begin
execute procedure p2(i) returning_values o;
end
declare procedure p2(i integer) returns (o integer)
as
begin
o = i;
end
begin
execute procedure p1 returning_values o;
suspend;
end!

View File

@ -1698,6 +1698,22 @@ C --
PARAMETER (GDS__decfloat_overflow = 335545142)
INTEGER*4 GDS__decfloat_underflow
PARAMETER (GDS__decfloat_underflow = 335545143)
INTEGER*4 GDS__subfunc_notdef
PARAMETER (GDS__subfunc_notdef = 335545144)
INTEGER*4 GDS__subproc_notdef
PARAMETER (GDS__subproc_notdef = 335545145)
INTEGER*4 GDS__subfunc_signat
PARAMETER (GDS__subfunc_signat = 335545146)
INTEGER*4 GDS__subproc_signat
PARAMETER (GDS__subproc_signat = 335545147)
INTEGER*4 GDS__subfunc_defvaldecl
PARAMETER (GDS__subfunc_defvaldecl = 335545148)
INTEGER*4 GDS__subproc_defvaldecl
PARAMETER (GDS__subproc_defvaldecl = 335545149)
INTEGER*4 GDS__subfunc_not_impl
PARAMETER (GDS__subfunc_not_impl = 335545150)
INTEGER*4 GDS__subproc_not_impl
PARAMETER (GDS__subproc_not_impl = 335545151)
INTEGER*4 GDS__gfix_db_name
PARAMETER (GDS__gfix_db_name = 335740929)
INTEGER*4 GDS__gfix_invalid_sw

View File

@ -1693,6 +1693,22 @@ const
gds_decfloat_overflow = 335545142;
isc_decfloat_underflow = 335545143;
gds_decfloat_underflow = 335545143;
isc_subfunc_notdef = 335545144;
gds_subfunc_notdef = 335545144;
isc_subproc_notdef = 335545145;
gds_subproc_notdef = 335545145;
isc_subfunc_signat = 335545146;
gds_subfunc_signat = 335545146;
isc_subproc_signat = 335545147;
gds_subproc_signat = 335545147;
isc_subfunc_defvaldecl = 335545148;
gds_subfunc_defvaldecl = 335545148;
isc_subproc_defvaldecl = 335545149;
gds_subproc_defvaldecl = 335545149;
isc_subfunc_not_impl = 335545150;
gds_subfunc_not_impl = 335545150;
isc_subproc_not_impl = 335545151;
gds_subproc_not_impl = 335545151;
isc_gfix_db_name = 335740929;
gds_gfix_db_name = 335740929;
isc_gfix_invalid_sw = 335740930;

View File

@ -320,6 +320,37 @@ void DsqlCompilerScratch::putLocalVariables(CompoundStmtNode* parameters, USHORT
else
fb_assert(false);
}
if (!(flags & DsqlCompilerScratch::FLAG_SUB_ROUTINE))
{
// Check not implemented sub-functions.
GenericMap<Left<MetaName, DeclareSubFuncNode*> >::ConstAccessor funcAccessor(&subFunctions);
for (bool found = funcAccessor.getFirst(); found; found = funcAccessor.getNext())
{
if (!funcAccessor.current()->second->dsqlBlock)
{
status_exception::raise(
Arg::Gds(isc_subfunc_not_impl) <<
funcAccessor.current()->first.c_str());
}
}
// Check not implemented sub-procedures.
GenericMap<Left<MetaName, DeclareSubProcNode*> >::ConstAccessor procAccessor(&subProcedures);
for (bool found = procAccessor.getFirst(); found; found = procAccessor.getNext())
{
if (!procAccessor.current()->second->dsqlBlock)
{
status_exception::raise(
Arg::Gds(isc_subproc_not_impl) <<
procAccessor.current()->first.c_str());
}
}
}
}
// Write out local variable field data type.
@ -586,6 +617,50 @@ void DsqlCompilerScratch::checkUnusedCTEs() const
}
}
DeclareSubFuncNode* DsqlCompilerScratch::getSubFunction(const Firebird::MetaName& name)
{
DeclareSubFuncNode* subFunc = NULL;
subFunctions.get(name, subFunc);
if (!subFunc && mainScratch)
subFunc = mainScratch->getSubFunction(name);
return subFunc;
}
void DsqlCompilerScratch::putSubFunction(DeclareSubFuncNode* subFunc, bool replace)
{
if (!replace && subFunctions.exist(subFunc->name))
{
status_exception::raise(
Arg::Gds(isc_dsql_duplicate_spec) << subFunc->name);
}
subFunctions.put(subFunc->name, subFunc);
}
DeclareSubProcNode* DsqlCompilerScratch::getSubProcedure(const Firebird::MetaName& name)
{
DeclareSubProcNode* subProc = NULL;
subProcedures.get(name, subProc);
if (!subProc && mainScratch)
subProc = mainScratch->getSubProcedure(name);
return subProc;
}
void DsqlCompilerScratch::putSubProcedure(DeclareSubProcNode* subProc, bool replace)
{
if (!replace && subProcedures.exist(subProc->name))
{
status_exception::raise(
Arg::Gds(isc_dsql_duplicate_spec) << subProc->name);
}
subProcedures.put(subProc->name, subProc);
}
// 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)

View File

@ -70,7 +70,7 @@ public:
public:
DsqlCompilerScratch(MemoryPool& p, dsql_dbb* aDbb, jrd_tra* aTransaction,
DsqlCompiledStatement* aStatement)
DsqlCompiledStatement* aStatement, DsqlCompilerScratch* aMainScratch = NULL)
: BlrDebugWriter(p),
dbb(aDbb),
transaction(aTransaction),
@ -79,7 +79,6 @@ public:
nestingLevel(0),
ports(p),
relation(NULL),
procedure(NULL),
mainContext(p),
context(&mainContext),
unionContext(p),
@ -115,6 +114,7 @@ public:
ctes(p),
cteAliases(p),
psql(false),
mainScratch(aMainScratch),
subFunctions(p),
subProcedures(p)
{
@ -247,43 +247,11 @@ public:
bool isPsql() const { return psql; }
void setPsql(bool value) { psql = value; }
dsql_udf* getSubFunction(const Firebird::MetaName& name)
{
dsql_udf* subFunc = NULL;
subFunctions.get(name, subFunc);
return subFunc;
}
DeclareSubFuncNode* getSubFunction(const Firebird::MetaName& name);
void putSubFunction(DeclareSubFuncNode* subFunc, bool replace = false);
void putSubFunction(dsql_udf* subFunc)
{
if (subFunctions.exist(subFunc->udf_name.identifier))
{
using namespace Firebird;
status_exception::raise(
Arg::Gds(isc_dsql_duplicate_spec) << subFunc->udf_name.identifier);
}
subFunctions.put(subFunc->udf_name.identifier, subFunc);
}
dsql_prc* getSubProcedure(const Firebird::MetaName& name)
{
dsql_prc* subProc = NULL;
subProcedures.get(name, subProc);
return subProc;
}
void putSubProcedure(dsql_prc* subProc)
{
if (subProcedures.exist(subProc->prc_name.identifier))
{
using namespace Firebird;
status_exception::raise(
Arg::Gds(isc_dsql_duplicate_spec) << subProc->prc_name.identifier);
}
subProcedures.put(subProc->prc_name.identifier, subProc);
}
DeclareSubProcNode* getSubProcedure(const Firebird::MetaName& name);
void putSubProcedure(DeclareSubProcNode* subProc, bool replace = false);
private:
SelectExprNode* pass1RecursiveCte(SelectExprNode* input);
@ -300,7 +268,6 @@ public:
unsigned nestingLevel; // begin...end nesting level
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
@ -340,8 +307,9 @@ private:
Firebird::HalfStaticArray<SelectExprNode*, 4> ctes; // common table expressions
Firebird::HalfStaticArray<const Firebird::string*, 4> cteAliases; // CTE aliases in recursive members
bool psql;
Firebird::GenericMap<Firebird::Left<Firebird::MetaName, dsql_udf*> > subFunctions;
Firebird::GenericMap<Firebird::Left<Firebird::MetaName, dsql_prc*> > subProcedures;
DsqlCompilerScratch* mainScratch;
Firebird::GenericMap<Firebird::Left<Firebird::MetaName, DeclareSubFuncNode*> > subFunctions;
Firebird::GenericMap<Firebird::Left<Firebird::MetaName, DeclareSubProcNode*> > subProcedures;
};
class PsqlChanger

View File

@ -11589,8 +11589,12 @@ DmlNode* UdfCallNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch*
if (blrOp == blr_subfunc)
{
DeclareSubFuncNode* declareNode;
if (csb->subFunctions.get(name.identifier, declareNode))
node->function = declareNode->routine;
for (auto curCsb = csb; curCsb && !node->function; curCsb = curCsb->mainCsb)
{
if (curCsb->subFunctions.get(name.identifier, declareNode))
node->function = declareNode->routine;
}
}
Function* function = node->function;
@ -12023,7 +12027,10 @@ ValueExprNode* UdfCallNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
doDsqlPass(dsqlScratch, args));
if (name.package.isEmpty())
node->dsqlFunction = dsqlScratch->getSubFunction(name.identifier);
{
DeclareSubFuncNode* subFunction = dsqlScratch->getSubFunction(name.identifier);
node->dsqlFunction = subFunction ? subFunction->dsqlFunction : NULL;
}
if (!node->dsqlFunction)
node->dsqlFunction = METD_get_function(dsqlScratch->getTransaction(), dsqlScratch, name);

View File

@ -51,164 +51,6 @@ DATABASE DB = STATIC "ODS.RDB";
namespace
{
struct ParameterInfo
{
explicit ParameterInfo(MemoryPool& p)
: type(0),
number(0),
name(p),
fieldSource(p),
fieldName(p),
relationName(p),
mechanism(0)
{
defaultSource.clear();
defaultValue.clear();
}
ParameterInfo(MemoryPool& p, const ParameterInfo& o)
: type(o.type),
number(o.number),
name(p, o.name),
fieldSource(p, o.fieldSource),
fieldName(p, o.fieldName),
relationName(p, o.relationName),
collationId(o.collationId),
nullFlag(o.nullFlag),
mechanism(o.mechanism),
fieldLength(o.fieldLength),
fieldScale(o.fieldScale),
fieldType(o.fieldType),
fieldSubType(o.fieldSubType),
fieldSegmentLength(o.fieldSegmentLength),
fieldNullFlag(o.fieldNullFlag),
fieldCharLength(o.fieldCharLength),
fieldCollationId(o.fieldCollationId),
fieldCharSetId(o.fieldCharSetId),
fieldPrecision(o.fieldPrecision),
defaultSource(o.defaultSource),
defaultValue(o.defaultValue)
{
}
SSHORT type;
SSHORT number;
MetaName name;
MetaName fieldSource;
MetaName fieldName;
MetaName relationName;
Nullable<SSHORT> collationId;
Nullable<SSHORT> nullFlag;
SSHORT mechanism;
Nullable<SSHORT> fieldLength;
Nullable<SSHORT> fieldScale;
Nullable<SSHORT> fieldType;
Nullable<SSHORT> fieldSubType;
Nullable<SSHORT> fieldSegmentLength;
Nullable<SSHORT> fieldNullFlag;
Nullable<SSHORT> fieldCharLength;
Nullable<SSHORT> fieldCollationId;
Nullable<SSHORT> fieldCharSetId;
Nullable<SSHORT> fieldPrecision;
// Not compared
bid defaultSource;
bid defaultValue;
bool operator >(const ParameterInfo& o) const
{
return type > o.type || (type == o.type && number > o.number);
}
bool operator ==(const ParameterInfo& o) const
{
return type == o.type && number == o.number && name == o.name &&
(fieldSource == o.fieldSource ||
(fb_utils::implicit_domain(fieldSource.c_str()) &&
fb_utils::implicit_domain(o.fieldSource.c_str()))) &&
fieldName == o.fieldName && relationName == o.relationName &&
collationId == o.collationId && nullFlag == o.nullFlag &&
mechanism == o.mechanism && fieldLength == o.fieldLength &&
fieldScale == o.fieldScale && fieldType == o.fieldType &&
fieldSubType == o.fieldSubType && fieldSegmentLength == o.fieldSegmentLength &&
fieldNullFlag == o.fieldNullFlag && fieldCharLength == o.fieldCharLength &&
fieldCollationId == o.fieldCollationId && fieldCharSetId == o.fieldCharSetId &&
fieldPrecision == o.fieldPrecision;
}
bool operator !=(const ParameterInfo& o) const
{
return !(*this == o);
}
};
struct Signature
{
Signature(MemoryPool& p, const MetaName& aName)
: name(p, aName),
parameters(p),
defined(false)
{
}
explicit Signature(const MetaName& aName)
: name(aName),
parameters(*getDefaultMemoryPool()),
defined(false)
{
}
explicit Signature(MemoryPool& p)
: name(p),
parameters(p),
defined(false)
{
}
Signature(MemoryPool& p, const Signature& o)
: name(p, o.name),
parameters(p),
defined(o.defined)
{
for (SortedObjectsArray<ParameterInfo>::const_iterator i = o.parameters.begin();
i != o.parameters.end(); ++i)
{
parameters.add(*i);
}
}
bool operator >(const Signature& o) const
{
return name > o.name;
}
bool operator ==(const Signature& o) const
{
if (name != o.name || parameters.getCount() != o.parameters.getCount())
return false;
for (SortedObjectsArray<ParameterInfo>::const_iterator i = parameters.begin(),
j = o.parameters.begin();
i != parameters.end(); ++i, ++j)
{
if (*i != *j)
return false;
}
return true;
}
bool operator !=(const Signature& o) const
{
return !(*this == o);
}
MetaName name;
SortedObjectsArray<ParameterInfo> parameters;
bool defined;
};
// Return function and procedure names (in the user charset) and optionally its details for a
// given package.
void collectPackagedItems(thread_db* tdbb, jrd_tra* transaction, const MetaName& metaName,
@ -234,7 +76,7 @@ namespace
ARG.RDB$FUNCTION_NAME EQ FUN.RDB$FUNCTION_NAME AND
FLD.RDB$FIELD_NAME EQ ARG.RDB$FIELD_SOURCE
{
ParameterInfo parameter(*getDefaultMemoryPool());
SignatureParameter parameter(*getDefaultMemoryPool());
parameter.number = ARG.RDB$ARGUMENT_POSITION;
parameter.name = ARG.RDB$ARGUMENT_NAME;
@ -271,11 +113,6 @@ namespace
if (!FLD.RDB$FIELD_PRECISION.NULL)
parameter.fieldPrecision = FLD.RDB$FIELD_PRECISION;
if (!ARG.RDB$DEFAULT_SOURCE.NULL)
parameter.defaultSource = ARG.RDB$DEFAULT_SOURCE;
if (!ARG.RDB$DEFAULT_VALUE.NULL)
parameter.defaultValue = ARG.RDB$DEFAULT_VALUE;
function.parameters.add(parameter);
}
END_FOR
@ -304,7 +141,7 @@ namespace
PRM.RDB$PROCEDURE_NAME EQ PRC.RDB$PROCEDURE_NAME AND
FLD.RDB$FIELD_NAME EQ PRM.RDB$FIELD_SOURCE
{
ParameterInfo parameter(*getDefaultMemoryPool());
SignatureParameter parameter(*getDefaultMemoryPool());
parameter.type = PRM.RDB$PARAMETER_TYPE;
parameter.number = PRM.RDB$PARAMETER_NUMBER;
parameter.name = PRM.RDB$PARAMETER_NAME;
@ -341,11 +178,6 @@ namespace
if (!FLD.RDB$FIELD_PRECISION.NULL)
parameter.fieldPrecision = FLD.RDB$FIELD_PRECISION;
if (!PRM.RDB$DEFAULT_SOURCE.NULL)
parameter.defaultSource = PRM.RDB$DEFAULT_SOURCE;
if (!PRM.RDB$DEFAULT_VALUE.NULL)
parameter.defaultValue = PRM.RDB$DEFAULT_VALUE;
procedure.parameters.add(parameter);
}
END_FOR

View File

@ -1402,7 +1402,8 @@ DmlNode* DeclareSubFuncNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerSc
{ // scope
CompilerScratch* const subCsb = node->subCsb =
FB_NEW_POOL(csb->csb_pool) CompilerScratch(csb->csb_pool);
FB_NEW_POOL(csb->csb_pool) CompilerScratch(csb->csb_pool, csb);
subCsb->csb_g_flags |= csb_subroutine | (csb->csb_g_flags & csb_get_dependencies);
subCsb->csb_blr_reader = csb->csb_blr_reader;
@ -1520,6 +1521,97 @@ DeclareSubFuncNode* DeclareSubFuncNode::dsqlPass(DsqlCompilerScratch* dsqlScratc
if (dsqlScratch->flags & DsqlCompilerScratch::FLAG_SUB_ROUTINE)
ERR_post(Arg::Gds(isc_wish_list) << Arg::Gds(isc_random) << "nested sub function");
DeclareSubFuncNode* prevDecl = dsqlScratch->getSubFunction(name);
bool implemetingForward = prevDecl && !prevDecl->dsqlBlock && dsqlBlock;
dsqlFunction = implemetingForward ? prevDecl->dsqlFunction : FB_NEW_POOL(pool) dsql_udf(pool);
dsqlFunction->udf_flags = UDF_subfunc;
dsqlFunction->udf_name.identifier = name;
fb_assert(dsqlReturns.getCount() == 1);
const TypeClause* returnType = dsqlReturns[0]->type;
dsqlFunction->udf_dtype = returnType->dtype;
dsqlFunction->udf_scale = returnType->scale;
dsqlFunction->udf_sub_type = returnType->subType;
dsqlFunction->udf_length = returnType->length;
dsqlFunction->udf_character_set_id = returnType->charSetId;
if (dsqlDeterministic)
dsqlSignature.flags |= Signature::FLAG_DETERMINISTIC;
SignatureParameter sigRet(pool);
sigRet.type = 1;
sigRet.number = -1;
sigRet.fromType(returnType);
dsqlSignature.parameters.add(sigRet);
Array<NestConst<ParameterClause> >& paramArray = dsqlParameters;
bool defaultFound = false;
for (NestConst<ParameterClause>* i = paramArray.begin(); i != paramArray.end(); ++i)
{
ParameterClause* param = *i;
const unsigned paramIndex = i - paramArray.begin();
SignatureParameter sigParam(pool);
sigParam.type = 0;
sigParam.number = (SSHORT) dsqlSignature.parameters.getCount();
sigParam.name = param->name;
sigParam.fromType(param->type);
dsqlSignature.parameters.add(sigParam);
if (!implemetingForward)
{
// ASF: dsqlFunction->udf_arguments is only checked for its count for now.
dsqlFunction->udf_arguments.add(dsc());
}
if (param->defaultClause)
{
if (prevDecl)
{
status_exception::raise(
Arg::Gds(isc_subfunc_defvaldecl) <<
name.c_str());
}
defaultFound = true;
if (!implemetingForward && dsqlFunction->udf_def_count == 0)
dsqlFunction->udf_def_count = paramArray.end() - i;
}
else
{
if (defaultFound)
{
// Parameter without default value after parameters with default.
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-204) <<
Arg::Gds(isc_bad_default_value) <<
Arg::Gds(isc_invalid_clause) << Arg::Str("defaults must be last"));
}
if (prevDecl && paramIndex < prevDecl->dsqlParameters.getCount())
param->defaultClause = prevDecl->dsqlParameters[paramIndex]->defaultClause;
}
}
if (!implemetingForward)
dsqlScratch->putSubFunction(this);
else if (dsqlSignature != prevDecl->dsqlSignature)
{
status_exception::raise(
Arg::Gds(isc_subfunc_signat) <<
name.c_str());
}
if (!dsqlBlock) // forward decl
return this;
if (prevDecl)
dsqlScratch->putSubFunction(this, true);
DsqlCompiledStatement* statement = FB_NEW_POOL(pool) DsqlCompiledStatement(pool);
if (dsqlScratch->clientDialect > SQL_DIALECT_V5)
@ -1535,58 +1627,23 @@ DeclareSubFuncNode* DeclareSubFuncNode::dsqlPass(DsqlCompilerScratch* dsqlScratc
statement->setType(DsqlCompiledStatement::TYPE_SELECT);
blockScratch = FB_NEW_POOL(pool) DsqlCompilerScratch(pool,
dsqlScratch->getAttachment(), dsqlScratch->getTransaction(), statement);
dsqlScratch->getAttachment(), dsqlScratch->getTransaction(), statement, dsqlScratch);
blockScratch->clientDialect = dsqlScratch->clientDialect;
blockScratch->flags |= DsqlCompilerScratch::FLAG_FUNCTION | DsqlCompilerScratch::FLAG_SUB_ROUTINE;
blockScratch->flags |= dsqlScratch->flags & DsqlCompilerScratch::FLAG_DDL;
blockScratch->flags |=
DsqlCompilerScratch::FLAG_FUNCTION |
DsqlCompilerScratch::FLAG_SUB_ROUTINE |
(dsqlScratch->flags & DsqlCompilerScratch::FLAG_DDL);
dsqlBlock = dsqlBlock->dsqlPass(blockScratch);
dsqlFunction = FB_NEW_POOL(pool) dsql_udf(pool);
dsqlFunction->udf_flags = UDF_subfunc;
dsqlFunction->udf_name.identifier = name;
fb_assert(dsqlBlock->returns.getCount() == 1);
const TypeClause* returnType = dsqlBlock->returns[0]->type;
dsqlFunction->udf_dtype = returnType->dtype;
dsqlFunction->udf_scale = returnType->scale;
dsqlFunction->udf_sub_type = returnType->subType;
dsqlFunction->udf_length = returnType->length;
dsqlFunction->udf_character_set_id = returnType->charSetId;
const Array<NestConst<ParameterClause> >& paramArray = dsqlBlock->parameters;
bool defaultFound = false;
for (const NestConst<ParameterClause>* i = paramArray.begin(); i != paramArray.end(); ++i)
{
// ASF: dsqlFunction->udf_arguments is only checked for its count for now.
dsqlFunction->udf_arguments.add(dsc());
const ParameterClause* param = *i;
if (param->defaultClause)
{
defaultFound = true;
if (dsqlFunction->udf_def_count == 0)
dsqlFunction->udf_def_count = paramArray.end() - i;
}
else if (defaultFound)
{
// Parameter without default value after parameters with default.
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-204) <<
Arg::Gds(isc_bad_default_value) <<
Arg::Gds(isc_invalid_clause) << Arg::Str("defaults must be last"));
}
}
dsqlScratch->putSubFunction(dsqlFunction);
return this;
}
void DeclareSubFuncNode::genBlr(DsqlCompilerScratch* dsqlScratch)
{
if (!dsqlBlock) // forward decl
return;
GEN_request(blockScratch, dsqlBlock);
dsqlScratch->appendUChar(blr_subfunc_decl);
@ -1677,7 +1734,8 @@ DmlNode* DeclareSubProcNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerSc
{ // scope
CompilerScratch* const subCsb = node->subCsb =
FB_NEW_POOL(csb->csb_pool) CompilerScratch(csb->csb_pool);
FB_NEW_POOL(csb->csb_pool) CompilerScratch(csb->csb_pool, csb);
subCsb->csb_g_flags |= csb_subroutine | (csb->csb_g_flags & csb_get_dependencies);
subCsb->csb_blr_reader = csb->csb_blr_reader;
@ -1803,6 +1861,100 @@ DeclareSubProcNode* DeclareSubProcNode::dsqlPass(DsqlCompilerScratch* dsqlScratc
if (dsqlScratch->flags & DsqlCompilerScratch::FLAG_SUB_ROUTINE)
ERR_post(Arg::Gds(isc_wish_list) << Arg::Gds(isc_random) << "nested sub procedure");
DeclareSubProcNode* prevDecl = dsqlScratch->getSubProcedure(name);
bool implemetingForward = prevDecl && !prevDecl->dsqlBlock && dsqlBlock;
dsqlProcedure = implemetingForward ? prevDecl->dsqlProcedure : FB_NEW_POOL(pool) dsql_prc(pool);
dsqlProcedure->prc_flags = PRC_subproc;
dsqlProcedure->prc_name.identifier = name;
dsqlProcedure->prc_in_count = USHORT(dsqlParameters.getCount());
dsqlProcedure->prc_out_count = USHORT(dsqlReturns.getCount());
if (dsqlParameters.hasData())
{
Array<NestConst<ParameterClause> >& paramArray = dsqlParameters;
bool defaultFound = false;
dsqlProcedure->prc_inputs = paramArray.front()->type;
for (NestConst<ParameterClause>* i = paramArray.begin(); i != paramArray.end(); ++i)
{
ParameterClause* param = *i;
const unsigned paramIndex = i - paramArray.begin();
SignatureParameter sigParam(pool);
sigParam.type = 0; // input
sigParam.number = (SSHORT) dsqlSignature.parameters.getCount();
sigParam.name = param->name;
sigParam.fromType(param->type);
dsqlSignature.parameters.add(sigParam);
if (param->defaultClause)
{
if (prevDecl)
{
status_exception::raise(
Arg::Gds(isc_subproc_defvaldecl) <<
name.c_str());
}
defaultFound = true;
if (!implemetingForward && dsqlProcedure->prc_def_count == 0)
dsqlProcedure->prc_def_count = paramArray.end() - i;
}
else
{
if (defaultFound)
{
// Parameter without default value after parameters with default.
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-204) <<
Arg::Gds(isc_bad_default_value) <<
Arg::Gds(isc_invalid_clause) << Arg::Str("defaults must be last"));
}
if (prevDecl && paramIndex < prevDecl->dsqlParameters.getCount())
param->defaultClause = prevDecl->dsqlParameters[paramIndex]->defaultClause;
}
}
}
if (dsqlReturns.hasData())
{
Array<NestConst<ParameterClause> >& paramArray = dsqlReturns;
dsqlProcedure->prc_outputs = paramArray.front()->type;
for (NestConst<ParameterClause>* i = paramArray.begin(); i != paramArray.end(); ++i)
{
ParameterClause* param = *i;
const unsigned paramIndex = i - paramArray.begin();
SignatureParameter sigParam(pool);
sigParam.type = 1; // output
sigParam.number = (SSHORT) dsqlSignature.parameters.getCount();
sigParam.name = param->name;
sigParam.fromType(param->type);
dsqlSignature.parameters.add(sigParam);
}
}
if (!implemetingForward)
dsqlScratch->putSubProcedure(this);
else if (dsqlSignature != prevDecl->dsqlSignature)
{
status_exception::raise(
Arg::Gds(isc_subproc_signat) <<
name.c_str());
}
if (!dsqlBlock) // forward decl
return this;
if (prevDecl)
dsqlScratch->putSubProcedure(this, true);
DsqlCompiledStatement* statement = FB_NEW_POOL(pool) DsqlCompiledStatement(pool);
if (dsqlScratch->clientDialect > SQL_DIALECT_V5)
@ -1818,54 +1970,21 @@ DeclareSubProcNode* DeclareSubProcNode::dsqlPass(DsqlCompilerScratch* dsqlScratc
statement->setType(DsqlCompiledStatement::TYPE_SELECT);
blockScratch = FB_NEW_POOL(pool) DsqlCompilerScratch(pool,
dsqlScratch->getAttachment(), dsqlScratch->getTransaction(), statement);
dsqlScratch->getAttachment(), dsqlScratch->getTransaction(), statement, dsqlScratch);
blockScratch->clientDialect = dsqlScratch->clientDialect;
blockScratch->flags |= DsqlCompilerScratch::FLAG_PROCEDURE | DsqlCompilerScratch::FLAG_SUB_ROUTINE;
blockScratch->flags |= dsqlScratch->flags & DsqlCompilerScratch::FLAG_DDL;
dsqlBlock = dsqlBlock->dsqlPass(blockScratch);
dsqlProcedure = FB_NEW_POOL(pool) dsql_prc(pool);
dsqlProcedure->prc_flags = PRC_subproc;
dsqlProcedure->prc_name.identifier = name;
dsqlProcedure->prc_in_count = USHORT(dsqlBlock->parameters.getCount());
dsqlProcedure->prc_out_count = USHORT(dsqlBlock->returns.getCount());
if (dsqlBlock->parameters.hasData())
{
Array<NestConst<ParameterClause> >& paramArray = dsqlBlock->parameters;
dsqlProcedure->prc_inputs = paramArray.front()->type;
for (const NestConst<ParameterClause>* i = paramArray.begin(); i != paramArray.end(); ++i)
{
const ParameterClause* param = *i;
if (param->defaultClause)
{
if (dsqlProcedure->prc_def_count == 0)
dsqlProcedure->prc_def_count = paramArray.end() - i;
}
else if (dsqlProcedure->prc_def_count != 0)
{
// Parameter without default value after parameters with default.
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-204) <<
Arg::Gds(isc_bad_default_value) <<
Arg::Gds(isc_invalid_clause) << Arg::Str("defaults must be last"));
}
}
}
if (dsqlBlock->returns.hasData())
dsqlProcedure->prc_outputs = dsqlBlock->returns.front()->type;
dsqlScratch->putSubProcedure(dsqlProcedure);
return this;
}
void DeclareSubProcNode::genBlr(DsqlCompilerScratch* dsqlScratch)
{
if (!dsqlBlock) // forward decl
return;
GEN_request(blockScratch, dsqlBlock);
dsqlScratch->appendUChar(blr_subproc_decl);
@ -2636,8 +2755,12 @@ DmlNode* ExecProcedureNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScr
if (blrOp == blr_exec_subproc)
{
DeclareSubProcNode* declareNode;
if (csb->subProcedures.get(name.identifier, declareNode))
procedure = declareNode->routine;
for (auto curCsb = csb; curCsb && !procedure; curCsb = curCsb->mainCsb)
{
if (curCsb->subProcedures.get(name.identifier, declareNode))
procedure = declareNode->routine;
}
}
else
procedure = MET_lookup_procedure(tdbb, name, false);
@ -2669,7 +2792,10 @@ ExecProcedureNode* ExecProcedureNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
dsql_prc* procedure = NULL;
if (dsqlName.package.isEmpty())
procedure = dsqlScratch->getSubProcedure(dsqlName.identifier);
{
DeclareSubProcNode* subProcedure = dsqlScratch->getSubProcedure(dsqlName.identifier);
procedure = subProcedure ? subProcedure->dsqlProcedure : NULL;
}
if (!procedure)
procedure = METD_get_procedure(dsqlScratch->getTransaction(), dsqlScratch, dsqlName);
@ -2683,10 +2809,7 @@ ExecProcedureNode* ExecProcedureNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
}
if (!dsqlScratch->isPsql())
{
dsqlScratch->procedure = procedure;
dsqlScratch->getStatement()->setType(DsqlCompiledStatement::TYPE_EXEC_PROCEDURE);
}
ExecProcedureNode* node = FB_NEW_POOL(getPool()) ExecProcedureNode(getPool(), dsqlName);
node->dsqlProcedure = procedure;
@ -2740,7 +2863,7 @@ ExecProcedureNode* ExecProcedureNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
Arg::Gds(isc_random) << Arg::Str("RETURNING_VALUES"));
}
node->outputSources = explodeOutputs(dsqlScratch, dsqlScratch->procedure);
node->outputSources = explodeOutputs(dsqlScratch, procedure);
}
if (node->outputSources)

View File

@ -420,6 +420,9 @@ public:
: TypedNode<StmtNode, StmtNode::TYPE_DECLARE_SUBFUNC>(pool),
name(pool, aName),
dsqlDeterministic(false),
dsqlParameters(pool),
dsqlReturns(pool),
dsqlSignature(pool, aName),
dsqlBlock(NULL),
blockScratch(NULL),
dsqlFunction(NULL),
@ -451,6 +454,9 @@ private:
public:
Firebird::MetaName name;
bool dsqlDeterministic;
Firebird::Array<NestConst<ParameterClause> > dsqlParameters;
Firebird::Array<NestConst<ParameterClause> > dsqlReturns;
Signature dsqlSignature;
NestConst<ExecBlockNode> dsqlBlock;
DsqlCompilerScratch* blockScratch;
dsql_udf* dsqlFunction;
@ -467,6 +473,9 @@ public:
explicit DeclareSubProcNode(MemoryPool& pool, const Firebird::MetaName& aName)
: TypedNode<StmtNode, StmtNode::TYPE_DECLARE_SUBPROC>(pool),
name(pool, aName),
dsqlParameters(pool),
dsqlReturns(pool),
dsqlSignature(pool, aName),
dsqlBlock(NULL),
blockScratch(NULL),
dsqlProcedure(NULL),
@ -497,6 +506,9 @@ private:
public:
Firebird::MetaName name;
Firebird::Array<NestConst<ParameterClause> > dsqlParameters;
Firebird::Array<NestConst<ParameterClause> > dsqlReturns;
Signature dsqlSignature;
NestConst<ExecBlockNode> dsqlBlock;
DsqlCompilerScratch* blockScratch;
dsql_prc* dsqlProcedure;

View File

@ -1000,6 +1000,196 @@ private:
int scale;
};
struct SignatureParameter
{
explicit SignatureParameter(MemoryPool& p)
: type(0),
number(0),
name(p),
fieldSource(p),
fieldName(p),
relationName(p),
charSetName(p),
collationName(p),
subTypeName(p),
mechanism(0)
{
}
SignatureParameter(MemoryPool& p, const SignatureParameter& o)
: type(o.type),
number(o.number),
name(p, o.name),
fieldSource(p, o.fieldSource),
fieldName(p, o.fieldName),
relationName(p, o.relationName),
charSetName(p, o.charSetName),
collationName(p, o.collationName),
subTypeName(p, o.subTypeName),
collationId(o.collationId),
nullFlag(o.nullFlag),
mechanism(o.mechanism),
fieldLength(o.fieldLength),
fieldScale(o.fieldScale),
fieldType(o.fieldType),
fieldSubType(o.fieldSubType),
fieldSegmentLength(o.fieldSegmentLength),
fieldNullFlag(o.fieldNullFlag),
fieldCharLength(o.fieldCharLength),
fieldCollationId(o.fieldCollationId),
fieldCharSetId(o.fieldCharSetId),
fieldPrecision(o.fieldPrecision)
{
}
void fromType(const TypeClause* type)
{
fieldType = type->dtype;
fieldScale = type->scale;
subTypeName = type->subTypeName;
fieldSubType = type->subType;
fieldLength = type->length;
fieldCharLength = type->charLength;
charSetName = type->charSet;
fieldCharSetId = type->charSetId;
collationName = type->collate;
fieldCollationId = type->collationId;
fieldSource = type->fieldSource;
fieldName = type->typeOfName;
relationName = type->typeOfTable;
fieldSegmentLength = type->segLength;
fieldPrecision = type->precision;
nullFlag = (SSHORT) type->notNull;
mechanism = (SSHORT) type->fullDomain;
}
SSHORT type;
SSHORT number;
Firebird::MetaName name;
Firebird::MetaName fieldSource;
Firebird::MetaName fieldName;
Firebird::MetaName relationName;
Firebird::MetaName charSetName;
Firebird::MetaName collationName;
Firebird::MetaName subTypeName;
Nullable<SSHORT> collationId;
Nullable<SSHORT> nullFlag;
SSHORT mechanism;
Nullable<SSHORT> fieldLength;
Nullable<SSHORT> fieldScale;
Nullable<SSHORT> fieldType;
Nullable<SSHORT> fieldSubType;
Nullable<SSHORT> fieldSegmentLength;
Nullable<SSHORT> fieldNullFlag;
Nullable<SSHORT> fieldCharLength;
Nullable<SSHORT> fieldCollationId;
Nullable<SSHORT> fieldCharSetId;
Nullable<SSHORT> fieldPrecision;
bool operator >(const SignatureParameter& o) const
{
return type > o.type || (type == o.type && number > o.number);
}
bool operator ==(const SignatureParameter& o) const
{
return type == o.type && number == o.number && name == o.name &&
(fieldSource == o.fieldSource ||
(fb_utils::implicit_domain(fieldSource.c_str()) &&
fb_utils::implicit_domain(o.fieldSource.c_str()))) &&
fieldName == o.fieldName && relationName == o.relationName &&
collationId == o.collationId && nullFlag == o.nullFlag &&
mechanism == o.mechanism && fieldLength == o.fieldLength &&
fieldScale == o.fieldScale && fieldType == o.fieldType &&
fieldSubType == o.fieldSubType && fieldSegmentLength == o.fieldSegmentLength &&
fieldNullFlag == o.fieldNullFlag && fieldCharLength == o.fieldCharLength &&
charSetName == o.charSetName && collationName == o.collationName && subTypeName == o.subTypeName &&
fieldCollationId == o.fieldCollationId && fieldCharSetId == o.fieldCharSetId &&
fieldPrecision == o.fieldPrecision;
}
bool operator !=(const SignatureParameter& o) const
{
return !(*this == o);
}
};
struct Signature
{
const static unsigned FLAG_DETERMINISTIC = 0x01;
Signature(MemoryPool& p, const Firebird::MetaName& aName)
: name(p, aName),
parameters(p),
flags(0),
defined(false)
{
}
explicit Signature(const Firebird::MetaName& aName)
: name(aName),
parameters(*getDefaultMemoryPool()),
flags(0),
defined(false)
{
}
explicit Signature(MemoryPool& p)
: name(p),
parameters(p),
flags(0),
defined(false)
{
}
Signature(MemoryPool& p, const Signature& o)
: name(p, o.name),
parameters(p),
flags(0),
defined(o.defined)
{
for (Firebird::SortedObjectsArray<SignatureParameter>::const_iterator i = o.parameters.begin();
i != o.parameters.end();
++i)
{
parameters.add(*i);
}
}
bool operator >(const Signature& o) const
{
return name > o.name;
}
bool operator ==(const Signature& o) const
{
if (name != o.name || flags != o.flags || parameters.getCount() != o.parameters.getCount())
return false;
for (Firebird::SortedObjectsArray<SignatureParameter>::const_iterator i = parameters.begin(),
j = o.parameters.begin();
i != parameters.end();
++i, ++j)
{
if (*i != *j)
return false;
}
return true;
}
bool operator !=(const Signature& o) const
{
return !(*this == o);
}
Firebird::MetaName name;
Firebird::SortedObjectsArray<SignatureParameter> parameters;
unsigned flags;
bool defined;
};
} // namespace
/*! \var unsigned DSQL_debug

View File

@ -1 +1 @@
46 shift/reduce conflicts, 17 reduce/reduce conflicts.
54 shift/reduce conflicts, 17 reduce/reduce conflicts.

View File

@ -2539,7 +2539,7 @@ procedure_clause
%type <createAlterProcedureNode> psql_procedure_clause
psql_procedure_clause
: procedure_clause_start sql_security_clause AS local_declaration_list full_proc_block
: procedure_clause_start sql_security_clause AS local_declarations_opt full_proc_block
{
$$ = $1;
$$->ssDefiner = $2;
@ -2670,7 +2670,7 @@ function_clause
%type <createAlterFunctionNode> psql_function_clause
psql_function_clause
: function_clause_start sql_security_clause AS local_declaration_list full_proc_block
: function_clause_start sql_security_clause AS local_declarations_opt full_proc_block
{
$$ = $1;
$$->ssDefiner = $2;
@ -2869,73 +2869,131 @@ package_body_item
;
%type <compoundStmtNode> local_declaration_list
local_declaration_list
: /* nothing */ { $$ = NULL; }
| local_declarations
%type <compoundStmtNode> local_declarations_opt
local_declarations_opt
: local_forward_declarations_opt local_nonforward_declarations_opt
{
CompoundStmtNode* forward = $1;
CompoundStmtNode* nonForward = $2;
if (!forward)
$$ = nonForward;
else
{
if (nonForward)
forward->statements.add(nonForward->statements.begin(), nonForward->statements.getCount());
$$ = forward;
}
}
;
%type <compoundStmtNode> local_declarations
local_declarations
: local_declaration
%type <compoundStmtNode> local_forward_declarations_opt
local_forward_declarations_opt
: /* nothing */ { $$ = NULL; }
| local_forward_declarations
;
%type <compoundStmtNode> local_forward_declarations
local_forward_declarations
: local_forward_declaration
{
$$ = newNode<CompoundStmtNode>();
$$->statements.add($1);
}
| local_declarations local_declaration
| local_forward_declarations local_forward_declaration
{
$1->statements.add($2);
$$ = $1;
}
;
%type <stmtNode> local_declaration
local_declaration
%type <stmtNode> local_forward_declaration
local_forward_declaration
: local_declaration_subproc_start ';' { $$ = $1; }
| local_declaration_subfunc_start ';' { $$ = $1; }
;
%type <compoundStmtNode> local_nonforward_declarations_opt
local_nonforward_declarations_opt
: /* nothing */ { $$ = NULL; }
| local_nonforward_declarations
;
%type <compoundStmtNode> local_nonforward_declarations
local_nonforward_declarations
: local_nonforward_declaration
{
$$ = newNode<CompoundStmtNode>();
$$->statements.add($1);
}
| local_nonforward_declarations local_nonforward_declaration
{
$1->statements.add($2);
$$ = $1;
}
;
%type <stmtNode> local_nonforward_declaration
local_nonforward_declaration
: DECLARE var_decl_opt local_declaration_item ';'
{
$$ = $3;
$$->line = YYPOSNARG(1).firstLine;
$$->column = YYPOSNARG(1).firstColumn;
}
| DECLARE PROCEDURE symbol_procedure_name
{ $<execBlockNode>$ = newNode<ExecBlockNode>(); }
input_parameters(NOTRIAL(&$<execBlockNode>4->parameters))
output_parameters(NOTRIAL(&$<execBlockNode>4->returns)) AS
local_declaration_list
full_proc_block
| local_declaration_subproc_start AS local_declarations_opt full_proc_block
{
DeclareSubProcNode* node = newNode<DeclareSubProcNode>(*$3);
node->dsqlBlock = $<execBlockNode>4;
node->dsqlBlock->localDeclList = $8;
node->dsqlBlock->body = $9;
DeclareSubProcNode* node = $1;
node->dsqlBlock = newNode<ExecBlockNode>();
node->dsqlBlock->parameters = node->dsqlParameters;
node->dsqlBlock->returns = node->dsqlReturns;
node->dsqlBlock->localDeclList = $3;
node->dsqlBlock->body = $4;
for (FB_SIZE_T i = 0; i < node->dsqlBlock->parameters.getCount(); ++i)
node->dsqlBlock->parameters[i]->parameterExpr = make_parameter();
$$ = node;
}
| DECLARE FUNCTION symbol_UDF_name
{ $<execBlockNode>$ = newNode<ExecBlockNode>(); }
input_parameters(NOTRIAL(&$<execBlockNode>4->parameters))
RETURNS domain_or_non_array_type collate_clause deterministic_opt AS
local_declaration_list
full_proc_block
| local_declaration_subfunc_start AS local_declarations_opt full_proc_block
{
DeclareSubFuncNode* node = newNode<DeclareSubFuncNode>(*$3);
node->dsqlDeterministic = $9;
node->dsqlBlock = $<execBlockNode>4;
node->dsqlBlock->localDeclList = $11;
node->dsqlBlock->body = $12;
DeclareSubFuncNode* node = $1;
node->dsqlBlock = newNode<ExecBlockNode>();
node->dsqlBlock->parameters = node->dsqlParameters;
node->dsqlBlock->returns = node->dsqlReturns;
node->dsqlBlock->localDeclList = $3;
node->dsqlBlock->body = $4;
for (FB_SIZE_T i = 0; i < node->dsqlBlock->parameters.getCount(); ++i)
node->dsqlBlock->parameters[i]->parameterExpr = make_parameter();
node->dsqlBlock->returns.add(newNode<ParameterClause>($<legacyField>7, optName($8)));
$$ = node;
}
;
%type <declareSubProcNode> local_declaration_subproc_start
local_declaration_subproc_start
: DECLARE PROCEDURE symbol_procedure_name
{ $$ = newNode<DeclareSubProcNode>(NOTRIAL(*$3)); }
input_parameters(NOTRIAL(&$4->dsqlParameters))
output_parameters(NOTRIAL(&$4->dsqlReturns))
{ $$ = $4; }
;
%type <declareSubFuncNode> local_declaration_subfunc_start
local_declaration_subfunc_start
: DECLARE FUNCTION symbol_UDF_name
{ $$ = newNode<DeclareSubFuncNode>(NOTRIAL(*$3)); }
input_parameters(NOTRIAL(&$4->dsqlParameters))
RETURNS domain_or_non_array_type collate_clause deterministic_opt
{
$$ = $4;
$$->dsqlReturns.add(newNode<ParameterClause>($<legacyField>7, optName($8)));
$$->dsqlDeterministic = $9;
}
;
%type <stmtNode> local_declaration_item
local_declaration_item
: var_declaration_item
@ -3526,7 +3584,7 @@ exec_block
{ $<execBlockNode>$ = newNode<ExecBlockNode>(); }
block_input_params(NOTRIAL(&$3->parameters))
output_parameters(NOTRIAL(&$3->returns)) AS
local_declaration_list
local_declarations_opt
full_proc_block
{
ExecBlockNode* node = $3;
@ -3597,7 +3655,7 @@ check_opt
%type <createAlterTriggerNode> trigger_clause
trigger_clause
: create_trigger_start trg_sql_security_clause AS local_declaration_list full_proc_block
: create_trigger_start trg_sql_security_clause AS local_declarations_opt full_proc_block
{
$$ = $1;
$$->ssDefiner = $2;
@ -4244,7 +4302,7 @@ crypt_key_clause($alterDatabaseNode)
%type <createAlterTriggerNode> alter_trigger_clause
alter_trigger_clause
: symbol_trigger_name trigger_active trigger_type_opt trigger_position trg_sql_security_clause
AS local_declaration_list full_proc_block
AS local_declarations_opt full_proc_block
{
$$ = newNode<CreateAlterTriggerNode>(*$1);
$$->alter = true;

View File

@ -367,7 +367,10 @@ dsql_ctx* PASS1_make_context(DsqlCompilerScratch* dsqlScratch, RecordSourceNode*
else if (procNode && (procNode->dsqlName.package.hasData() || procNode->sourceList))
{
if (procNode->dsqlName.package.isEmpty())
procedure = dsqlScratch->getSubProcedure(procNode->dsqlName.identifier);
{
DeclareSubProcNode* subProcedure = dsqlScratch->getSubProcedure(procNode->dsqlName.identifier);
procedure = subProcedure ? subProcedure->dsqlProcedure : NULL;
}
if (!procedure)
{
@ -390,7 +393,10 @@ dsql_ctx* PASS1_make_context(DsqlCompilerScratch* dsqlScratch, RecordSourceNode*
else
{
if (procNode && procNode->dsqlName.package.isEmpty())
procedure = dsqlScratch->getSubProcedure(procNode->dsqlName.identifier);
{
DeclareSubProcNode* subProcedure = dsqlScratch->getSubProcedure(procNode->dsqlName.identifier);
procedure = subProcedure ? subProcedure->dsqlProcedure : NULL;
}
if (!procedure)
relation = METD_get_relation(dsqlScratch->getTransaction(), dsqlScratch, relation_name);

View File

@ -845,6 +845,14 @@ static const struct {
{"decfloat_invalid_operation", 335545141},
{"decfloat_overflow", 335545142},
{"decfloat_underflow", 335545143},
{"subfunc_notdef", 335545144},
{"subproc_notdef", 335545145},
{"subfunc_signat", 335545146},
{"subproc_signat", 335545147},
{"subfunc_defvaldecl", 335545148},
{"subproc_defvaldecl", 335545149},
{"subfunc_not_impl", 335545150},
{"subproc_not_impl", 335545151},
{"gfix_db_name", 335740929},
{"gfix_invalid_sw", 335740930},
{"gfix_incmp_sw", 335740932},

View File

@ -879,6 +879,14 @@ const ISC_STATUS isc_decfloat_inexact_result = 335545140L;
const ISC_STATUS isc_decfloat_invalid_operation = 335545141L;
const ISC_STATUS isc_decfloat_overflow = 335545142L;
const ISC_STATUS isc_decfloat_underflow = 335545143L;
const ISC_STATUS isc_subfunc_notdef = 335545144L;
const ISC_STATUS isc_subproc_notdef = 335545145L;
const ISC_STATUS isc_subfunc_signat = 335545146L;
const ISC_STATUS isc_subproc_signat = 335545147L;
const ISC_STATUS isc_subfunc_defvaldecl = 335545148L;
const ISC_STATUS isc_subproc_defvaldecl = 335545149L;
const ISC_STATUS isc_subfunc_not_impl = 335545150L;
const ISC_STATUS isc_subproc_not_impl = 335545151L;
const ISC_STATUS isc_gfix_db_name = 335740929L;
const ISC_STATUS isc_gfix_invalid_sw = 335740930L;
const ISC_STATUS isc_gfix_incmp_sw = 335740932L;
@ -1353,7 +1361,7 @@ const ISC_STATUS isc_trace_switch_user_only = 337182757L;
const ISC_STATUS isc_trace_switch_param_miss = 337182758L;
const ISC_STATUS isc_trace_param_act_notcompat = 337182759L;
const ISC_STATUS isc_trace_mandatory_switch_miss = 337182760L;
const ISC_STATUS isc_err_max = 1297;
const ISC_STATUS isc_err_max = 1305;
#else /* c definitions */
@ -2202,6 +2210,14 @@ const ISC_STATUS isc_err_max = 1297;
#define isc_decfloat_invalid_operation 335545141L
#define isc_decfloat_overflow 335545142L
#define isc_decfloat_underflow 335545143L
#define isc_subfunc_notdef 335545144L
#define isc_subproc_notdef 335545145L
#define isc_subfunc_signat 335545146L
#define isc_subproc_signat 335545147L
#define isc_subfunc_defvaldecl 335545148L
#define isc_subproc_defvaldecl 335545149L
#define isc_subfunc_not_impl 335545150L
#define isc_subproc_not_impl 335545151L
#define isc_gfix_db_name 335740929L
#define isc_gfix_invalid_sw 335740930L
#define isc_gfix_incmp_sw 335740932L
@ -2676,7 +2692,7 @@ const ISC_STATUS isc_err_max = 1297;
#define isc_trace_switch_param_miss 337182758L
#define isc_trace_param_act_notcompat 337182759L
#define isc_trace_mandatory_switch_miss 337182760L
#define isc_err_max 1297
#define isc_err_max 1305
#endif

View File

@ -848,6 +848,14 @@ Data source : @4"}, /* eds_statement */
{335545141, "Decimal float invalid operation. An indeterminant error occurred during an operation."}, /* decfloat_invalid_operation */
{335545142, "Decimal float overflow. The exponent of a result is greater than the magnitude allowed."}, /* decfloat_overflow */
{335545143, "Decimal float underflow. The exponent of a result is less than the magnitude allowed."}, /* decfloat_underflow */
{335545144, "Sub-function @1 has not been defined"}, /* subfunc_notdef */
{335545145, "Sub-procedure @1 has not been defined"}, /* subproc_notdef */
{335545146, "Sub-function @1 has a signature mismatch with its forward declaration"}, /* subfunc_signat */
{335545147, "Sub-procedure @1 has a signature mismatch with its forward declaration"}, /* subproc_signat */
{335545148, "Default values for parameters are not allowed in definition of the previously declared sub-function @1"}, /* subfunc_defvaldecl */
{335545149, "Default values for parameters are not allowed in definition of the previously declared sub-procedure @1"}, /* subproc_defvaldecl */
{335545150, "Sub-function @1 was declared but not implemented"}, /* subfunc_not_impl */
{335545151, "Sub-procedure @1 was declared but not implemented"}, /* subproc_not_impl */
{335740929, "data base file name (@1) already given"}, /* gfix_db_name */
{335740930, "invalid switch @1"}, /* gfix_invalid_sw */
{335740932, "incompatible switch combination"}, /* gfix_incmp_sw */
@ -976,7 +984,7 @@ Data source : @4"}, /* eds_statement */
{336068872, "Procedure @1 has not been defined on the package body @2"}, /* dyn_procnotdef_package */
{336068873, "Function @1 has a signature mismatch on package body @2"}, /* dyn_funcsignat_package */
{336068874, "Procedure @1 has a signature mismatch on package body @2"}, /* dyn_procsignat_package */
{336068875, "Default values for parameters are allowed only in declaration of packaged procedure @1.@2"}, /* dyn_defvaldecl_package_proc */
{336068875, "Default values for parameters are not allowed in the definition of a previously declared packaged procedure @1.@2"}, /* dyn_defvaldecl_package_proc */
{336068877, "Package body @1 already exists"}, /* dyn_package_body_exists */
{336068878, "Invalid DDL statement for function @1"}, /* dyn_invalid_ddl_func */
{336068879, "Cannot alter new style function @1 with ALTER EXTERNAL FUNCTION. Use ALTER FUNCTION instead."}, /* dyn_newfc_oldsyntax */
@ -990,7 +998,7 @@ Data source : @4"}, /* eds_statement */
{336068895, "System @1 @2 cannot be modified"}, /* dyn_cant_modify_sysobj */
{336068896, "INCREMENT BY 0 is an illegal option for sequence @1"}, /* dyn_cant_use_zero_increment */
{336068897, "Can't use @1 in FOREIGN KEY constraint"}, /* dyn_cant_use_in_foreignkey */
{336068898, "Default values for parameters are allowed only in declaration of packaged function @1.@2"}, /* dyn_defvaldecl_package_func */
{336068898, "Default values for parameters are not allowed in the definition of a previously declared packaged function @1.@2"}, /* dyn_defvaldecl_package_func */
{336068904, "INCREMENT BY 0 is an illegal option for identity column @1 of table @2"}, /* dyn_cant_use_zero_inc_ident */
{336330753, "found unknown switch"}, /* gbak_unknown_switch */
{336330754, "page size parameter missing"}, /* gbak_page_size_missing */

View File

@ -844,6 +844,14 @@ static const struct {
{335545141, -901}, /* 821 decfloat_invalid_operation */
{335545142, -901}, /* 822 decfloat_overflow */
{335545143, -901}, /* 823 decfloat_underflow */
{335545144, -901}, /* 824 subfunc_notdef */
{335545145, -901}, /* 825 subproc_notdef */
{335545146, -901}, /* 826 subfunc_signat */
{335545147, -901}, /* 827 subproc_signat */
{335545148, -901}, /* 828 subfunc_defvaldecl */
{335545149, -901}, /* 829 subproc_defvaldecl */
{335545150, -901}, /* 830 subfunc_not_impl */
{335545151, -901}, /* 831 subproc_not_impl */
{335740929, -901}, /* 1 gfix_db_name */
{335740930, -901}, /* 2 gfix_invalid_sw */
{335740932, -901}, /* 4 gfix_incmp_sw */

View File

@ -844,6 +844,14 @@ static const struct {
{335545141, "22000"}, // 821 decfloat_invalid_operation
{335545142, "22003"}, // 822 decfloat_overflow
{335545143, "22003"}, // 823 decfloat_underflow
{335545144, "42000"}, // 824 subfunc_notdef
{335545145, "42000"}, // 825 subproc_notdef
{335545146, "42000"}, // 826 subfunc_signat
{335545147, "42000"}, // 827 subproc_signat
{335545148, "42000"}, // 828 subfunc_defvaldecl
{335545149, "42000"}, // 829 subproc_defvaldecl
{335545150, "42000"}, // 830 subfunc_not_impl
{335545151, "42000"}, // 831 subproc_not_impl
{335740929, "00000"}, // 1 gfix_db_name
{335740930, "00000"}, // 2 gfix_invalid_sw
{335740932, "00000"}, // 4 gfix_incmp_sw

View File

@ -910,9 +910,13 @@ ProcedureSourceNode* ProcedureSourceNode::parse(thread_db* tdbb, CompilerScratch
if (blrOp == blr_subproc)
{
DeclareSubProcNode* node;
if (csb->subProcedures.get(name.identifier, node))
procedure = node->routine;
DeclareSubProcNode* declareNode;
for (auto curCsb = csb; curCsb && !procedure; curCsb = curCsb->mainCsb)
{
if (curCsb->subProcedures.get(name.identifier, declareNode))
procedure = declareNode->routine;
}
}
else
procedure = MET_lookup_procedure(tdbb, name, false);

View File

@ -427,7 +427,7 @@ public:
SLONG subNumber;
};
explicit CompilerScratch(MemoryPool& p)
explicit CompilerScratch(MemoryPool& p, CompilerScratch* aMainCsb = NULL)
: /*csb_node(0),
csb_variables(0),
csb_dependencies(0),
@ -439,6 +439,7 @@ public:
#ifdef CMP_DEBUG
csb_dump(p),
#endif
mainCsb(aMainCsb),
csb_external(p),
csb_access(p),
csb_resources(p),
@ -486,6 +487,7 @@ public:
Firebird::string csb_dump;
#endif
CompilerScratch* mainCsb;
Firebird::BlrReader csb_blr_reader;
DmlNode* csb_node;
ExternalAccessList csb_external; // Access to outside procedures/triggers to be checked

View File

@ -1,7 +1,7 @@
/* MAX_NUMBER is the next number to be used, always one more than the highest message number. */
set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUMBER) VALUES (?, ?, ?, ?);
--
('2017-05-23 16:08:00', 'JRD', 0, 824)
('2017-07-10 12:27:00', 'JRD', 0, 832)
('2015-03-17 18:33:00', 'QLI', 1, 533)
('2015-01-07 18:01:51', 'GFIX', 3, 134)
('1996-11-07 13:39:40', 'GPRE', 4, 1)

View File

@ -931,6 +931,14 @@ Data source : @4', NULL, NULL)
('decfloat_invalid_operation', 'DecimalContext::checkForExceptions', 'DecFloat.cpp', NULL, 0, 821, NULL, 'Decimal float invalid operation. An indeterminant error occurred during an operation.', NULL, NULL);
('decfloat_overflow', 'DecimalContext::checkForExceptions', 'DecFloat.cpp', NULL, 0, 822, NULL, 'Decimal float overflow. The exponent of a result is greater than the magnitude allowed.', NULL, NULL);
('decfloat_underflow', 'DecimalContext::checkForExceptions', 'DecFloat.cpp', NULL, 0, 823, NULL, 'Decimal float underflow. The exponent of a result is less than the magnitude allowed.', NULL, NULL);
('subfunc_notdef', NULL, 'StmtNodes.cpp', NULL, 0, 824, NULL, 'Sub-function @1 has not been defined', NULL, NULL);
('subproc_notdef', NULL, 'StmtNodes.cpp', NULL, 0, 825, NULL, 'Sub-procedure @1 has not been defined', NULL, NULL);
('subfunc_signat', NULL, 'StmtNodes.cpp', NULL, 0, 826, NULL, 'Sub-function @1 has a signature mismatch with its forward declaration', NULL, NULL);
('subproc_signat', NULL, 'StmtNodes.cpp', NULL, 0, 827, NULL, 'Sub-procedure @1 has a signature mismatch with its forward declaration', NULL, NULL);
('subfunc_defvaldecl', NULL, 'StmtNodes.cpp', NULL, 0, 828, NULL, 'Default values for parameters are not allowed in definition of the previously declared sub-function @1', NULL, NULL);
('subproc_defvaldecl', NULL, 'StmtNodes.cpp', NULL, 0, 829, NULL, 'Default values for parameters are not allowed in definition of the previously declared sub-procedure @1', NULL, NULL);
('subfunc_not_impl', NULL, 'StmtNodes.cpp', NULL, 0, 830, NULL, 'Sub-function @1 was declared but not implemented', NULL, NULL);
('subproc_not_impl', NULL, 'StmtNodes.cpp', NULL, 0, 831, NULL, 'Sub-procedure @1 was declared but not implemented', NULL, NULL);
-- QLI
(NULL, NULL, NULL, NULL, 1, 0, NULL, 'expected type', NULL, NULL);
(NULL, NULL, NULL, NULL, 1, 1, NULL, 'bad block type', NULL, NULL);
@ -1981,7 +1989,7 @@ COMMIT WORK;
('dyn_procnotdef_package', 'CreatePackageBodyNode::execute', 'PackageNodes.epp', NULL, 8, 264, NULL, 'Procedure @1 has not been defined on the package body @2', NULL, NULL);
('dyn_funcsignat_package', 'CreatePackageBodyNode::execute', 'PackageNodes.epp', NULL, 8, 265, NULL, 'Function @1 has a signature mismatch on package body @2', NULL, NULL);
('dyn_procsignat_package', 'CreatePackageBodyNode::execute', 'PackageNodes.epp', NULL, 8, 266, NULL, 'Procedure @1 has a signature mismatch on package body @2', NULL, NULL);
('dyn_defvaldecl_package_proc', 'CreatePackageBodyNode::execute', 'PackageNodes.epp', NULL, 8, 267, NULL, 'Default values for parameters are allowed only in declaration of packaged procedure @1.@2', NULL, NULL);
('dyn_defvaldecl_package_proc', 'CreatePackageBodyNode::execute', 'PackageNodes.epp', NULL, 8, 267, NULL, 'Default values for parameters are not allowed in the definition of a previously declared packaged procedure @1.@2', NULL, NULL);
('dyn_dup_function', 'DYN_define_function', 'dyn_def.epp', NULL, 8, 268, NULL, 'Function @1 already exists', NULL, NULL);
('dyn_package_body_exists', NULL, 'DdlNodes.epp/PackageNodes.epp', NULL, 8, 269, NULL, 'Package body @1 already exists', NULL, NULL);
('dyn_invalid_ddl_func', 'CreateAlterFunctionNode::compile', 'DdlNodes.epp', NULL, 8, 270, NULL, 'Invalid DDL statement for function @1', NULL, NULL);
@ -2004,7 +2012,7 @@ COMMIT WORK;
('dyn_cant_modify_sysobj', NULL, 'DdlNodes.epp', NULL, 8, 287, NULL, 'System @1 @2 cannot be modified', NULL, 'Ex: System generator rdb$... cannot be modified');
('dyn_cant_use_zero_increment', NULL, 'DdlNodes.epp', NULL, 8, 288, NULL, 'INCREMENT BY 0 is an illegal option for sequence @1', NULL, NULL);
('dyn_cant_use_in_foreignkey', NULL, 'DdlNodes.epp', NULL, 8, 289, NULL, 'Can''t use @1 in FOREIGN KEY constraint', NULL, NULL);
('dyn_defvaldecl_package_func', 'CreatePackageBodyNode::execute', 'PackageNodes.epp', NULL, 8, 290, NULL, 'Default values for parameters are allowed only in declaration of packaged function @1.@2', NULL, NULL);
('dyn_defvaldecl_package_func', 'CreatePackageBodyNode::execute', 'PackageNodes.epp', NULL, 8, 290, NULL, 'Default values for parameters are not allowed in the definition of a previously declared packaged function @1.@2', NULL, NULL);
('dyn_create_user_no_password', 'CreateAlterUserNode', 'DdlNodes.epp', NULL, 8, 291, NULL, 'Password must be specified when creating user', NULL, NULL);
('dyn_cyclic_role', 'GrantRevokeNode::grantRevoke', 'DdlNodes.epp', NULL, 8, 292, NULL, 'role @1 can not be granted to role @2', NULL, NULL);
(NULL, 'CreateAlterRoleNode::execute', 'DdlNodes.epp', NULL, 8, 293, NULL, 'DROP SYSTEM PRIVILEGES should not be used in CREATE ROLE operator', NULL, NULL);

View File

@ -830,6 +830,14 @@ set bulk_insert INSERT INTO SYSTEM_ERRORS (SQL_CODE, SQL_CLASS, SQL_SUBCLASS, FA
(-901, '22', '000', 0, 821, 'decfloat_invalid_operation', NULL, NULL)
(-901, '22', '003', 0, 822, 'decfloat_overflow', NULL, NULL)
(-901, '22', '003', 0, 823, 'decfloat_underflow', NULL, NULL)
(-901, '42', '000', 0, 824, 'subfunc_notdef', NULL, NULL)
(-901, '42', '000', 0, 825, 'subproc_notdef', NULL, NULL)
(-901, '42', '000', 0, 826, 'subfunc_signat', NULL, NULL)
(-901, '42', '000', 0, 827, 'subproc_signat', NULL, NULL)
(-901, '42', '000', 0, 828, 'subfunc_defvaldecl', NULL, NULL)
(-901, '42', '000', 0, 829, 'subproc_defvaldecl', NULL, NULL)
(-901, '42', '000', 0, 830, 'subfunc_not_impl', NULL, NULL)
(-901, '42', '000', 0, 831, 'subproc_not_impl', NULL, NULL)
-- GFIX
(-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL)
(-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL)