mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 20:43:02 +01:00
This commit is contained in:
parent
986e96fac8
commit
a71ec888e4
68
doc/sql.extensions/README.declare_var_initializer.md
Normal file
68
doc/sql.extensions/README.declare_var_initializer.md
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
# DECLARE VARIABLE initializer enhancements (FB 6.0)
|
||||||
|
|
||||||
|
Up to Firebird 5.0, variables could be declared and initialized in the same statement, however only simple
|
||||||
|
expressions (the same as allowed in a DOMAIN's DEFAULT clause) were allowed as initializers.
|
||||||
|
This limitation has been removed in Firebird 6.0, allowing the use of any value expression as initializer.
|
||||||
|
|
||||||
|
## Syntax
|
||||||
|
|
||||||
|
```
|
||||||
|
DECLARE [VARIABLE] <varname> <type> [{ = | DEFAULT } <value>];
|
||||||
|
```
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
Previously declared variables can be used in the initializer expression of following variables.
|
||||||
|
|
||||||
|
A variable initializer may call subroutines, and these subroutines may read and write previously
|
||||||
|
declared variables.
|
||||||
|
|
||||||
|
A subroutine used in an initializer may also write to variables declared after the one being
|
||||||
|
initialized, but in this case their values will be overwritten when their initializers are
|
||||||
|
executed, even if they don't have explicit initializers.
|
||||||
|
|
||||||
|
```
|
||||||
|
-- This block will return (<null>, 2) as values of v1 and v2 assigned in sf1 will
|
||||||
|
-- be overwritten by their initializer after sf1 is called.
|
||||||
|
execute block returns (o1 integer, o2 integer)
|
||||||
|
as
|
||||||
|
declare function sf1 returns integer;
|
||||||
|
|
||||||
|
declare v0 integer = sf1();
|
||||||
|
declare v1 integer;
|
||||||
|
declare v2 integer = 2;
|
||||||
|
|
||||||
|
declare function sf1 returns integer
|
||||||
|
as
|
||||||
|
begin
|
||||||
|
v1 = 10;
|
||||||
|
v2 = 20;
|
||||||
|
return 0;
|
||||||
|
end
|
||||||
|
begin
|
||||||
|
o1 = v1;
|
||||||
|
o2 = v2;
|
||||||
|
suspend;
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
It's an error if a subroutine reads a variable declared after the one being initialized like in the
|
||||||
|
following example.
|
||||||
|
|
||||||
|
```
|
||||||
|
-- When sf1 is called, v1 is not yet initialized.
|
||||||
|
execute block
|
||||||
|
as
|
||||||
|
declare function sf1 returns integer;
|
||||||
|
|
||||||
|
declare v0 integer = sf1();
|
||||||
|
declare v1 integer;
|
||||||
|
|
||||||
|
declare function sf1 returns integer
|
||||||
|
as
|
||||||
|
begin
|
||||||
|
return v1;
|
||||||
|
end
|
||||||
|
begin
|
||||||
|
end
|
||||||
|
```
|
@ -2323,7 +2323,7 @@ void CreateAlterFunctionNode::compile(thread_db* /*tdbb*/, DsqlCompilerScratch*
|
|||||||
}
|
}
|
||||||
|
|
||||||
dsql_var* const variable = dsqlScratch->outputVariables[0];
|
dsql_var* const variable = dsqlScratch->outputVariables[0];
|
||||||
dsqlScratch->putLocalVariable(variable, 0, NULL);
|
dsqlScratch->putLocalVariable(variable, nullptr, {});
|
||||||
|
|
||||||
// ASF: This is here to not change the old logic (proc_flag)
|
// ASF: This is here to not change the old logic (proc_flag)
|
||||||
// of previous calls to PASS1_node and PASS1_statement.
|
// of previous calls to PASS1_node and PASS1_statement.
|
||||||
@ -3193,7 +3193,7 @@ void CreateAlterProcedureNode::compile(thread_db* /*tdbb*/, DsqlCompilerScratch*
|
|||||||
i != dsqlScratch->outputVariables.end();
|
i != dsqlScratch->outputVariables.end();
|
||||||
++i)
|
++i)
|
||||||
{
|
{
|
||||||
dsqlScratch->putLocalVariable(*i, 0, NULL);
|
dsqlScratch->putLocalVariable(*i, nullptr, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
// ASF: This is here to not change the old logic (proc_flag)
|
// ASF: This is here to not change the old logic (proc_flag)
|
||||||
|
@ -289,26 +289,24 @@ void DsqlCompilerScratch::putLocalVariables(CompoundStmtNode* parameters, USHORT
|
|||||||
if (!parameters)
|
if (!parameters)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
NestConst<StmtNode>* ptr = parameters->statements.begin();
|
Array<dsql_var*> declaredVariables;
|
||||||
|
|
||||||
for (const NestConst<StmtNode>* const end = parameters->statements.end(); ptr != end; ++ptr)
|
const auto end = parameters->statements.end();
|
||||||
|
|
||||||
|
for (auto ptr = parameters->statements.begin(); ptr != end; ++ptr)
|
||||||
{
|
{
|
||||||
StmtNode* parameter = *ptr;
|
auto parameter = *ptr;
|
||||||
|
|
||||||
putDebugSrcInfo(parameter->line, parameter->column);
|
putDebugSrcInfo(parameter->line, parameter->column);
|
||||||
|
|
||||||
DeclareVariableNode* varNode;
|
if (const auto varNode = nodeAs<DeclareVariableNode>(parameter))
|
||||||
|
|
||||||
if ((varNode = nodeAs<DeclareVariableNode>(parameter)))
|
|
||||||
{
|
{
|
||||||
dsql_fld* field = varNode->dsqlDef->type;
|
dsql_fld* field = varNode->dsqlDef->type;
|
||||||
const NestConst<StmtNode>* rest = ptr;
|
const NestConst<StmtNode>* rest = ptr;
|
||||||
|
|
||||||
while (++rest != end)
|
while (++rest != end)
|
||||||
{
|
{
|
||||||
const DeclareVariableNode* varNode2;
|
if (const auto varNode2 = nodeAs<DeclareVariableNode>(*rest))
|
||||||
|
|
||||||
if ((varNode2 = nodeAs<DeclareVariableNode>(*rest)))
|
|
||||||
{
|
{
|
||||||
const dsql_fld* rest_field = varNode2->dsqlDef->type;
|
const dsql_fld* rest_field = varNode2->dsqlDef->type;
|
||||||
|
|
||||||
@ -320,10 +318,10 @@ void DsqlCompilerScratch::putLocalVariables(CompoundStmtNode* parameters, USHORT
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dsql_var* variable = makeVariable(field, field->fld_name.c_str(), dsql_var::TYPE_LOCAL,
|
const auto variable = makeVariable(field, field->fld_name.c_str(), dsql_var::TYPE_LOCAL, 0, 0, locals);
|
||||||
0, 0, locals);
|
declaredVariables.add(variable);
|
||||||
|
|
||||||
putLocalVariable(variable, varNode, varNode->dsqlDef->type->collate);
|
putLocalVariableDecl(variable, varNode, varNode->dsqlDef->type->collate);
|
||||||
|
|
||||||
// Some field attributes are calculated inside putLocalVariable(), so we reinitialize
|
// Some field attributes are calculated inside putLocalVariable(), so we reinitialize
|
||||||
// the descriptor.
|
// the descriptor.
|
||||||
@ -342,6 +340,14 @@ void DsqlCompilerScratch::putLocalVariables(CompoundStmtNode* parameters, USHORT
|
|||||||
fb_assert(false);
|
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))
|
if (!(flags & DsqlCompilerScratch::FLAG_SUB_ROUTINE))
|
||||||
{
|
{
|
||||||
// Check not implemented sub-functions.
|
// Check not implemented sub-functions.
|
||||||
@ -369,22 +375,38 @@ void DsqlCompilerScratch::putLocalVariables(CompoundStmtNode* parameters, USHORT
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write out local variable field data type.
|
// Write out local variable field data type.
|
||||||
void DsqlCompilerScratch::putLocalVariable(dsql_var* variable, const DeclareVariableNode* hostParam,
|
void DsqlCompilerScratch::putLocalVariableDecl(dsql_var* variable, DeclareVariableNode* hostParam,
|
||||||
const MetaName& collationName)
|
const MetaName& collationName)
|
||||||
{
|
{
|
||||||
dsql_fld* field = variable->field;
|
const auto field = variable->field;
|
||||||
|
|
||||||
appendUChar(blr_dcl_variable);
|
appendUChar(blr_dcl_variable);
|
||||||
appendUShort(variable->number);
|
appendUShort(variable->number);
|
||||||
DDL_resolve_intl_type(this, field, collationName);
|
DDL_resolve_intl_type(this, field, collationName);
|
||||||
|
|
||||||
//const USHORT dtype = field->dtype;
|
|
||||||
|
|
||||||
putDtype(field, true);
|
putDtype(field, true);
|
||||||
//field->dtype = dtype;
|
|
||||||
|
if (variable->field->fld_name.hasData()) // Not a function return value
|
||||||
|
putDebugVariable(variable->number, variable->field->fld_name);
|
||||||
|
|
||||||
|
++hiddenVarsNumber;
|
||||||
|
|
||||||
|
if (variable->type != dsql_var::TYPE_INPUT && hostParam && hostParam->dsqlDef->defaultClause)
|
||||||
|
{
|
||||||
|
hostParam->dsqlDef->defaultClause->value =
|
||||||
|
Node::doDsqlPass(this, hostParam->dsqlDef->defaultClause->value, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
variable->initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write out local variable initialization.
|
||||||
|
void DsqlCompilerScratch::putLocalVariableInit(dsql_var* variable, const DeclareVariableNode* hostParam)
|
||||||
|
{
|
||||||
|
const dsql_fld* field = variable->field;
|
||||||
|
|
||||||
// Check for a default value, borrowed from define_domain
|
// Check for a default value, borrowed from define_domain
|
||||||
NestConst<ValueSourceClause> node = hostParam ? hostParam->dsqlDef->defaultClause : NULL;
|
NestConst<ValueSourceClause> node = hostParam ? hostParam->dsqlDef->defaultClause : nullptr;
|
||||||
|
|
||||||
if (variable->type == dsql_var::TYPE_INPUT)
|
if (variable->type == dsql_var::TYPE_INPUT)
|
||||||
{
|
{
|
||||||
@ -405,7 +427,7 @@ void DsqlCompilerScratch::putLocalVariable(dsql_var* variable, const DeclareVari
|
|||||||
appendUChar(blr_assignment);
|
appendUChar(blr_assignment);
|
||||||
|
|
||||||
if (node)
|
if (node)
|
||||||
GEN_expr(this, Node::doDsqlPass(this, node->value, false));
|
GEN_expr(this, node->value);
|
||||||
else
|
else
|
||||||
appendUChar(blr_null); // Initialize variable to NULL
|
appendUChar(blr_null); // Initialize variable to NULL
|
||||||
|
|
||||||
@ -417,11 +439,6 @@ void DsqlCompilerScratch::putLocalVariable(dsql_var* variable, const DeclareVari
|
|||||||
appendUChar(blr_init_variable);
|
appendUChar(blr_init_variable);
|
||||||
appendUShort(variable->number);
|
appendUShort(variable->number);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (variable->field->fld_name.hasData()) // Not a function return value
|
|
||||||
putDebugVariable(variable->number, variable->field->fld_name);
|
|
||||||
|
|
||||||
++hiddenVarsNumber;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put maps in subroutines for outer variables/parameters usage.
|
// Put maps in subroutines for outer variables/parameters usage.
|
||||||
|
@ -181,8 +181,15 @@ public:
|
|||||||
void putDtype(const TypeClause* field, bool useSubType);
|
void putDtype(const TypeClause* field, bool useSubType);
|
||||||
void putType(const TypeClause* type, bool useSubType);
|
void putType(const TypeClause* type, bool useSubType);
|
||||||
void putLocalVariables(CompoundStmtNode* parameters, USHORT locals);
|
void putLocalVariables(CompoundStmtNode* parameters, USHORT locals);
|
||||||
void putLocalVariable(dsql_var* variable, const DeclareVariableNode* hostParam,
|
void putLocalVariableDecl(dsql_var* variable, DeclareVariableNode* hostParam, const MetaName& collationName);
|
||||||
const MetaName& collationName);
|
void putLocalVariableInit(dsql_var* variable, const DeclareVariableNode* hostParam);
|
||||||
|
|
||||||
|
void putLocalVariable(dsql_var* variable, DeclareVariableNode* hostParam, const MetaName& collationName)
|
||||||
|
{
|
||||||
|
putLocalVariableDecl(variable, hostParam, collationName);
|
||||||
|
putLocalVariableInit(variable, hostParam);
|
||||||
|
}
|
||||||
|
|
||||||
void putOuterMaps();
|
void putOuterMaps();
|
||||||
dsql_var* makeVariable(dsql_fld*, const char*, const dsql_var::Type type, USHORT,
|
dsql_var* makeVariable(dsql_fld*, const char*, const dsql_var::Type type, USHORT,
|
||||||
USHORT, USHORT);
|
USHORT, USHORT);
|
||||||
|
@ -13703,8 +13703,11 @@ ValueExprNode* VariableNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!node->dsqlVar)
|
if (!node->dsqlVar ||
|
||||||
|
(node->dsqlVar->type == dsql_var::TYPE_LOCAL && !node->dsqlVar->initialized && !dsqlScratch->mainScratch))
|
||||||
|
{
|
||||||
PASS1_field_unknown(NULL, dsqlName.c_str(), this);
|
PASS1_field_unknown(NULL, dsqlName.c_str(), this);
|
||||||
|
}
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
@ -13844,6 +13847,15 @@ dsc* VariableNode::execute(thread_db* tdbb, Request* request) const
|
|||||||
const auto varRequest = getVarRequest(request);
|
const auto varRequest = getVarRequest(request);
|
||||||
const auto varImpure = varRequest->getImpure<impure_value>(varDecl->impureOffset);
|
const auto varImpure = varRequest->getImpure<impure_value>(varDecl->impureOffset);
|
||||||
|
|
||||||
|
if (!(varImpure->vlu_flags & VLU_initialized))
|
||||||
|
{
|
||||||
|
const Item item(Item::TYPE_VARIABLE, varId);
|
||||||
|
|
||||||
|
//// FIXME: Variable with simple type has no varInfo.
|
||||||
|
const auto s = item.getDescription(request, varInfo);
|
||||||
|
ERR_post(Arg::Gds(isc_uninitialized_var) << s);
|
||||||
|
}
|
||||||
|
|
||||||
request->req_flags &= ~req_null;
|
request->req_flags &= ~req_null;
|
||||||
|
|
||||||
dsc* desc;
|
dsc* desc;
|
||||||
|
@ -4254,9 +4254,11 @@ const StmtNode* InitVariableNode::execute(thread_db* tdbb, Request* request, Exe
|
|||||||
{
|
{
|
||||||
if (request->req_operation == Request::req_evaluate)
|
if (request->req_operation == Request::req_evaluate)
|
||||||
{
|
{
|
||||||
|
const auto varImpure = request->getImpure<impure_value>(varDecl->impureOffset);
|
||||||
|
|
||||||
if (varInfo)
|
if (varInfo)
|
||||||
{
|
{
|
||||||
dsc* toDesc = &request->getImpure<impure_value>(varDecl->impureOffset)->vlu_desc;
|
dsc* toDesc = &varImpure->vlu_desc;
|
||||||
toDesc->dsc_flags |= DSC_null;
|
toDesc->dsc_flags |= DSC_null;
|
||||||
|
|
||||||
MapFieldInfo::ValueType fieldInfo;
|
MapFieldInfo::ValueType fieldInfo;
|
||||||
@ -4275,6 +4277,8 @@ const StmtNode* InitVariableNode::execute(thread_db* tdbb, Request* request, Exe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
varImpure->vlu_flags |= VLU_initialized;
|
||||||
|
|
||||||
request->req_operation = Request::req_return;
|
request->req_operation = Request::req_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4497,10 +4501,10 @@ void ExecBlockNode::genBlr(DsqlCompilerScratch* dsqlScratch)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Array<dsql_var*>& variables = subRoutine ? dsqlScratch->outputVariables : dsqlScratch->variables;
|
const Array<dsql_var*>& variables = subRoutine ? dsqlScratch->outputVariables : dsqlScratch->variables;
|
||||||
|
|
||||||
for (Array<dsql_var*>::const_iterator i = variables.begin(); i != variables.end(); ++i)
|
for (const auto variable : variables)
|
||||||
dsqlScratch->putLocalVariable(*i, 0, NULL);
|
dsqlScratch->putLocalVariable(variable, nullptr, {});
|
||||||
|
|
||||||
dsqlScratch->setPsql(true);
|
dsqlScratch->setPsql(true);
|
||||||
|
|
||||||
|
@ -386,21 +386,17 @@ public:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
explicit dsql_var(MemoryPool& p)
|
explicit dsql_var(MemoryPool& p)
|
||||||
: PermanentStorage(p),
|
: PermanentStorage(p)
|
||||||
field(NULL),
|
|
||||||
type(TYPE_INPUT),
|
|
||||||
msgNumber(0),
|
|
||||||
msgItem(0),
|
|
||||||
number(0)
|
|
||||||
{
|
{
|
||||||
desc.clear();
|
desc.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
dsql_fld* field; // Field on which variable is based
|
dsql_fld* field = nullptr; // Field on which variable is based
|
||||||
Type type; // Input, output, local or hidden variable
|
Type type = TYPE_INPUT; // Input, output, local or hidden variable
|
||||||
USHORT msgNumber; // Message number containing variable
|
USHORT msgNumber = 0; // Message number containing variable
|
||||||
USHORT msgItem; // Item number in message
|
USHORT msgItem = 0; // Item number in message
|
||||||
USHORT number; // Local variable number
|
USHORT number = 0; // Local variable number
|
||||||
|
bool initialized = false; // Is variable initialized?
|
||||||
dsc desc;
|
dsc desc;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3158,7 +3158,7 @@ local_declaration_item
|
|||||||
|
|
||||||
%type <stmtNode> var_declaration_item
|
%type <stmtNode> var_declaration_item
|
||||||
var_declaration_item
|
var_declaration_item
|
||||||
: column_domain_or_non_array_type collate_clause default_par_opt
|
: column_domain_or_non_array_type collate_clause var_declaration_initializer
|
||||||
{
|
{
|
||||||
DeclareVariableNode* node = newNode<DeclareVariableNode>();
|
DeclareVariableNode* node = newNode<DeclareVariableNode>();
|
||||||
node->dsqlDef = newNode<ParameterClause>($1, optName($2), $3);
|
node->dsqlDef = newNode<ParameterClause>($1, optName($2), $3);
|
||||||
@ -3166,6 +3166,26 @@ var_declaration_item
|
|||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
%type <valueSourceClause> var_declaration_initializer
|
||||||
|
var_declaration_initializer
|
||||||
|
: // nothing
|
||||||
|
{ $$ = nullptr; }
|
||||||
|
| DEFAULT value
|
||||||
|
{
|
||||||
|
const auto clause = newNode<ValueSourceClause>();
|
||||||
|
clause->value = $2;
|
||||||
|
clause->source = makeParseStr(YYPOSNARG(1), YYPOSNARG(2));
|
||||||
|
$$ = clause;
|
||||||
|
}
|
||||||
|
| '=' value
|
||||||
|
{
|
||||||
|
const auto clause = newNode<ValueSourceClause>();
|
||||||
|
clause->value = $2;
|
||||||
|
clause->source = makeParseStr(YYPOSNARG(1), YYPOSNARG(2));
|
||||||
|
$$ = clause;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
var_decl_opt
|
var_decl_opt
|
||||||
: // nothing
|
: // nothing
|
||||||
| VARIABLE
|
| VARIABLE
|
||||||
|
@ -968,3 +968,4 @@ FB_IMPL_MSG(JRD, 965, ods_upgrade_err, -901, "HY", "000", "ODS upgrade failed wh
|
|||||||
FB_IMPL_MSG(JRD, 966, bad_par_workers, -924, "HY", "000", "Wrong parallel workers value @1, valid range are from 1 to @2")
|
FB_IMPL_MSG(JRD, 966, bad_par_workers, -924, "HY", "000", "Wrong parallel workers value @1, valid range are from 1 to @2")
|
||||||
FB_IMPL_MSG(JRD, 967, idx_expr_not_found, -902, "42", "000", "Definition of index expression is not found for index @1")
|
FB_IMPL_MSG(JRD, 967, idx_expr_not_found, -902, "42", "000", "Definition of index expression is not found for index @1")
|
||||||
FB_IMPL_MSG(JRD, 968, idx_cond_not_found, -902, "42", "000", "Definition of index condition is not found for index @1")
|
FB_IMPL_MSG(JRD, 968, idx_cond_not_found, -902, "42", "000", "Definition of index condition is not found for index @1")
|
||||||
|
FB_IMPL_MSG(JRD, 969, uninitialized_var, -625, "42", "000", "Variable @1 is not initialized")
|
||||||
|
@ -677,41 +677,8 @@ void EVL_validate(thread_db* tdbb, const Item& item, const ItemInfo* itemInfo, d
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (itemInfo->name.isEmpty())
|
s = item.getDescription(request, itemInfo);
|
||||||
{
|
arg = s.c_str();
|
||||||
int index = item.index + 1;
|
|
||||||
|
|
||||||
status = isc_not_valid_for;
|
|
||||||
|
|
||||||
if (item.type == Item::TYPE_VARIABLE)
|
|
||||||
{
|
|
||||||
const jrd_prc* procedure = request->getStatement()->procedure;
|
|
||||||
|
|
||||||
if (procedure)
|
|
||||||
{
|
|
||||||
if (index <= int(procedure->getOutputFields().getCount()))
|
|
||||||
s.printf("output parameter number %d", index);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
s.printf("variable number %d",
|
|
||||||
index - int(procedure->getOutputFields().getCount()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
s.printf("variable number %d", index);
|
|
||||||
}
|
|
||||||
else if (item.type == Item::TYPE_PARAMETER && item.subType == 0)
|
|
||||||
s.printf("input parameter number %d", (index - 1) / 2 + 1);
|
|
||||||
else if (item.type == Item::TYPE_PARAMETER && item.subType == 1)
|
|
||||||
s.printf("output parameter number %d", index);
|
|
||||||
|
|
||||||
if (s.isEmpty())
|
|
||||||
arg = UNKNOWN_STRING_MARK;
|
|
||||||
else
|
|
||||||
arg = s.c_str();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
arg = itemInfo->name.c_str();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ERR_post(Arg::Gds(status) << Arg::Str(arg) << Arg::Str(value));
|
ERR_post(Arg::Gds(status) << Arg::Str(arg) << Arg::Str(value));
|
||||||
|
@ -115,6 +115,44 @@
|
|||||||
using namespace Jrd;
|
using namespace Jrd;
|
||||||
using namespace Firebird;
|
using namespace Firebird;
|
||||||
|
|
||||||
|
// Item class implementation
|
||||||
|
|
||||||
|
string Item::getDescription(Request* request, const ItemInfo* itemInfo) const
|
||||||
|
{
|
||||||
|
if (itemInfo && itemInfo->name.hasData())
|
||||||
|
return itemInfo->name.c_str();
|
||||||
|
|
||||||
|
int oneBasedIndex = index + 1;
|
||||||
|
string s;
|
||||||
|
|
||||||
|
if (type == Item::TYPE_VARIABLE)
|
||||||
|
{
|
||||||
|
const auto* const procedure = request->getStatement()->procedure;
|
||||||
|
|
||||||
|
if (procedure)
|
||||||
|
{
|
||||||
|
if (oneBasedIndex <= int(procedure->getOutputFields().getCount()))
|
||||||
|
s.printf("[output parameter number %d]", oneBasedIndex);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s.printf("[number %d]",
|
||||||
|
oneBasedIndex - int(procedure->getOutputFields().getCount()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
s.printf("[number %d]", oneBasedIndex);
|
||||||
|
}
|
||||||
|
else if (type == Item::TYPE_PARAMETER && subType == 0)
|
||||||
|
s.printf("[input parameter number %d]", (oneBasedIndex - 1) / 2 + 1);
|
||||||
|
else if (type == Item::TYPE_PARAMETER && subType == 1)
|
||||||
|
s.printf("[output parameter number %d]", oneBasedIndex);
|
||||||
|
|
||||||
|
if (s.isEmpty())
|
||||||
|
s = UNKNOWN_STRING_MARK;
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
// AffectedRows class implementation
|
// AffectedRows class implementation
|
||||||
|
|
||||||
AffectedRows::AffectedRows()
|
AffectedRows::AffectedRows()
|
||||||
@ -327,8 +365,8 @@ void EXE_assignment(thread_db* tdbb, const ValueExprNode* to, dsc* from_desc, bo
|
|||||||
toVar->varDecl->impureOffset)->vlu_flags;
|
toVar->varDecl->impureOffset)->vlu_flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (impure_flags != NULL)
|
if (impure_flags)
|
||||||
*impure_flags |= VLU_checked;
|
*impure_flags |= VLU_initialized | VLU_checked;
|
||||||
|
|
||||||
// If the value is non-missing, move/convert it. Otherwise fill the
|
// If the value is non-missing, move/convert it. Otherwise fill the
|
||||||
// field with appropriate nulls.
|
// field with appropriate nulls.
|
||||||
|
@ -81,6 +81,7 @@ class Cursor;
|
|||||||
class DeclareSubFuncNode;
|
class DeclareSubFuncNode;
|
||||||
class DeclareSubProcNode;
|
class DeclareSubProcNode;
|
||||||
class DeclareVariableNode;
|
class DeclareVariableNode;
|
||||||
|
class ItemInfo;
|
||||||
class MessageNode;
|
class MessageNode;
|
||||||
class PlanNode;
|
class PlanNode;
|
||||||
class RecordSource;
|
class RecordSource;
|
||||||
@ -357,6 +358,8 @@ struct Item
|
|||||||
|
|
||||||
return type > x.type;
|
return type > x.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Firebird::string getDescription(Request* request, const ItemInfo* itemInfo) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FieldInfo
|
struct FieldInfo
|
||||||
|
@ -229,9 +229,10 @@ struct impure_value_ex : public impure_value
|
|||||||
blb* vlu_blob;
|
blb* vlu_blob;
|
||||||
};
|
};
|
||||||
|
|
||||||
const int VLU_computed = 1; // An invariant sub-query has been computed
|
const int VLU_computed = 1; // An invariant sub-query has been computed
|
||||||
const int VLU_null = 2; // An invariant sub-query computed to null
|
const int VLU_null = 2; // An invariant sub-query computed to null
|
||||||
const int VLU_checked = 4; // Constraint already checked in first read or assignment to argument/variable
|
const int VLU_checked = 4; // Constraint already checked in first read or assignment to argument/variable
|
||||||
|
const int VLU_initialized = 8; // Variable initialized
|
||||||
|
|
||||||
|
|
||||||
class Format : public pool_alloc<type_fmt>
|
class Format : public pool_alloc<type_fmt>
|
||||||
|
Loading…
Reference in New Issue
Block a user