mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-23 20:03:03 +01:00
Fixed CORE-2041 - update or insert with gen_id() with wrong generator value
This commit is contained in:
parent
28209cb815
commit
5d4084d30c
@ -2640,14 +2640,18 @@ static void define_procedure(CompiledStatement* statement, NOD_TYPE op)
|
||||
|
||||
put_local_variables(statement, procedure_node->nod_arg[e_prc_dcls], locals);
|
||||
|
||||
statement->req_loop_level = 0;
|
||||
statement->req_cursor_number = 0;
|
||||
|
||||
dsql_nod* stmtNode = PASS1_statement(statement, procedure_node->nod_arg[e_prc_body]);
|
||||
GEN_hidden_variables(statement);
|
||||
|
||||
statement->append_uchar(blr_stall);
|
||||
// put a label before body of procedure,
|
||||
// so that any EXIT statement can get out
|
||||
statement->append_uchar(blr_label);
|
||||
statement->append_uchar(0);
|
||||
statement->req_loop_level = 0;
|
||||
statement->req_cursor_number = 0;
|
||||
GEN_statement(statement, PASS1_statement(statement, procedure_node->nod_arg[e_prc_body]));
|
||||
GEN_statement(statement, stmtNode);
|
||||
statement->req_type = REQ_DDL;
|
||||
statement->append_uchar(blr_end);
|
||||
GEN_return(statement, procedure_node->nod_arg[e_prc_outputs], true);
|
||||
@ -2789,13 +2793,17 @@ void DDL_gen_block(CompiledStatement* statement, dsql_nod* node)
|
||||
|
||||
put_local_variables(statement, node->nod_arg[e_exe_blk_dcls], locals);
|
||||
|
||||
statement->req_loop_level = 0;
|
||||
|
||||
dsql_nod* stmtNode = PASS1_statement(statement, node->nod_arg[e_exe_blk_body]);
|
||||
GEN_hidden_variables(statement);
|
||||
|
||||
statement->append_uchar(blr_stall);
|
||||
// Put a label before body of procedure, so that
|
||||
// any exit statement can get out
|
||||
statement->append_uchar(blr_label);
|
||||
statement->append_uchar(0);
|
||||
statement->req_loop_level = 0;
|
||||
GEN_statement(statement, PASS1_statement(statement, node->nod_arg[e_exe_blk_body]));
|
||||
GEN_statement(statement, stmtNode);
|
||||
if (outputs)
|
||||
statement->req_type = REQ_SELECT_BLOCK;
|
||||
else
|
||||
@ -3238,6 +3246,9 @@ static void define_trigger(CompiledStatement* statement, NOD_TYPE op)
|
||||
trigger_node->nod_arg[e_trg_actions]->nod_arg[e_trg_act_dcls], 0);
|
||||
|
||||
statement->req_scope_level++;
|
||||
statement->req_loop_level = 0;
|
||||
statement->req_cursor_number = 0;
|
||||
actions = PASS1_statement(statement, actions);
|
||||
// dimitr: I see no reason to deny EXIT command in triggers,
|
||||
// hence I've added zero label at the beginning.
|
||||
// My first suspicion regarding an obvious conflict
|
||||
@ -3247,9 +3258,8 @@ static void define_trigger(CompiledStatement* statement, NOD_TYPE op)
|
||||
// Hopefully, system triggers are never recompiled.
|
||||
statement->append_uchar(blr_label);
|
||||
statement->append_uchar(0);
|
||||
statement->req_loop_level = 0;
|
||||
statement->req_cursor_number = 0;
|
||||
GEN_statement(statement, PASS1_statement(statement, actions));
|
||||
GEN_hidden_variables(statement);
|
||||
GEN_statement(statement, actions);
|
||||
statement->req_scope_level--;
|
||||
statement->append_uchar(blr_end);
|
||||
statement->end_blr();
|
||||
@ -6209,6 +6219,8 @@ static void put_local_variable( CompiledStatement* statement, dsql_var* variable
|
||||
|
||||
statement->put_debug_variable(variable->var_variable_number,
|
||||
variable->var_name);
|
||||
|
||||
++statement->req_hidden_vars_number;
|
||||
}
|
||||
|
||||
|
||||
|
@ -433,6 +433,7 @@ public:
|
||||
req_dt_context(p),
|
||||
req_labels(p),
|
||||
req_cursors(p),
|
||||
req_hidden_vars(p),
|
||||
req_curr_ctes(p),
|
||||
req_ctes(p),
|
||||
req_cte_aliases(p)
|
||||
@ -539,6 +540,8 @@ public:
|
||||
USHORT req_client_dialect; //!< dialect passed into the API call
|
||||
USHORT req_in_outer_join; //!< processing inside outer-join part
|
||||
dsql_str* req_alias_relation_prefix; //!< prefix for every relation-alias.
|
||||
DsqlNodStack req_hidden_vars; // hidden variables
|
||||
USHORT req_hidden_vars_number; // next hidden variable number
|
||||
|
||||
DsqlNodStack req_curr_ctes; // current processing CTE's
|
||||
class dsql_ctx* req_recursive_ctx; // context of recursive CTE
|
||||
|
@ -67,7 +67,6 @@ static void gen_cast(CompiledStatement*, const dsql_nod*);
|
||||
static void gen_coalesce(CompiledStatement*, const dsql_nod*);
|
||||
static void gen_constant(CompiledStatement*, const dsc*, bool);
|
||||
static void gen_constant(CompiledStatement*, dsql_nod*, bool);
|
||||
static void gen_descriptor(CompiledStatement*, const dsc*, bool);
|
||||
static void gen_error_condition(CompiledStatement*, const dsql_nod*);
|
||||
static void gen_exec_stmt(CompiledStatement* statement, const dsql_nod* node);
|
||||
static void gen_field(CompiledStatement*, const dsql_ctx*, const dsql_fld*, dsql_nod*);
|
||||
@ -103,6 +102,29 @@ const bool NEGATE_VALUE = true;
|
||||
const bool USE_VALUE = false;
|
||||
|
||||
|
||||
void GEN_hidden_variables(CompiledStatement* statement)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* G E N _ h i d d e n _ v a r i a b l e s
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Function
|
||||
* Emit BLR for hidden variables.
|
||||
*
|
||||
**************************************/
|
||||
for (DsqlNodStack::const_iterator i(statement->req_hidden_vars);
|
||||
i.hasData(); ++i)
|
||||
{
|
||||
dsql_var* var = ((dsql_var*) i.object()->nod_arg[e_var_variable]);
|
||||
statement->append_uchar(blr_dcl_variable);
|
||||
statement->append_ushort(var->var_variable_number);
|
||||
GEN_descriptor(statement, &i.object()->nod_desc, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
||||
GEN_expr
|
||||
@ -694,7 +716,7 @@ void GEN_port(CompiledStatement* statement, dsql_msg* message)
|
||||
parameter->par_desc.dsc_address = (UCHAR*)(IPTR) offset;
|
||||
offset += parameter->par_desc.dsc_length;
|
||||
// if (statement->req_blr_string)
|
||||
gen_descriptor(statement, ¶meter->par_desc, false);
|
||||
GEN_descriptor(statement, ¶meter->par_desc, false);
|
||||
}
|
||||
|
||||
if (offset > MAX_FORMAT_SIZE) {
|
||||
@ -758,6 +780,8 @@ void GEN_request( CompiledStatement* statement, dsql_nod* node)
|
||||
{
|
||||
stuff(statement, blr_begin);
|
||||
|
||||
GEN_hidden_variables(statement);
|
||||
|
||||
switch (statement->req_type)
|
||||
{
|
||||
case REQ_SELECT:
|
||||
@ -1033,13 +1057,15 @@ void GEN_statement( CompiledStatement* statement, dsql_nod* node)
|
||||
return;
|
||||
|
||||
case nod_list:
|
||||
stuff(statement, blr_begin);
|
||||
if (!(node->nod_flags & NOD_SIMPLE_LIST))
|
||||
stuff(statement, blr_begin);
|
||||
for (ptr = node->nod_arg, end = ptr + node->nod_count; ptr < end;
|
||||
ptr++)
|
||||
{
|
||||
GEN_statement(statement, *ptr);
|
||||
}
|
||||
stuff(statement, blr_end);
|
||||
if (!(node->nod_flags & NOD_SIMPLE_LIST))
|
||||
stuff(statement, blr_end);
|
||||
return;
|
||||
|
||||
case nod_erase:
|
||||
@ -1382,7 +1408,7 @@ static void gen_coalesce( CompiledStatement* statement, const dsql_nod* node)
|
||||
// blr_value_if is used for building the coalesce function
|
||||
dsql_nod* list = node->nod_arg[0];
|
||||
stuff(statement, blr_cast);
|
||||
gen_descriptor(statement, &node->nod_desc, true);
|
||||
GEN_descriptor(statement, &node->nod_desc, true);
|
||||
dsql_nod* const* ptr = list->nod_arg;
|
||||
for (const dsql_nod* const* const end = ptr + (list->nod_count - 1);
|
||||
ptr < end; ptr++)
|
||||
@ -1427,7 +1453,7 @@ static void gen_constant( CompiledStatement* statement, const dsc* desc, bool ne
|
||||
|
||||
switch (desc->dsc_dtype) {
|
||||
case dtype_short:
|
||||
gen_descriptor(statement, desc, true);
|
||||
GEN_descriptor(statement, desc, true);
|
||||
value = *(SSHORT *) p;
|
||||
if (negate_value)
|
||||
value = -value;
|
||||
@ -1435,7 +1461,7 @@ static void gen_constant( CompiledStatement* statement, const dsc* desc, bool ne
|
||||
break;
|
||||
|
||||
case dtype_long:
|
||||
gen_descriptor(statement, desc, true);
|
||||
GEN_descriptor(statement, desc, true);
|
||||
value = *(SLONG *) p;
|
||||
if (negate_value)
|
||||
value = -value;
|
||||
@ -1446,7 +1472,7 @@ static void gen_constant( CompiledStatement* statement, const dsc* desc, bool ne
|
||||
|
||||
case dtype_sql_time:
|
||||
case dtype_sql_date:
|
||||
gen_descriptor(statement, desc, true);
|
||||
GEN_descriptor(statement, desc, true);
|
||||
value = *(SLONG *) p;
|
||||
stuff_word(statement, value);
|
||||
stuff_word(statement, value >> 16);
|
||||
@ -1457,7 +1483,7 @@ static void gen_constant( CompiledStatement* statement, const dsc* desc, bool ne
|
||||
/* this is used for approximate/large numeric literal
|
||||
which is transmitted to the engine as a string.
|
||||
*/
|
||||
gen_descriptor(statement, desc, true);
|
||||
GEN_descriptor(statement, desc, true);
|
||||
// Length of string literal, cast because it could be > 127 bytes.
|
||||
const USHORT l = (USHORT)(UCHAR) desc->dsc_scale;
|
||||
if (negate_value) {
|
||||
@ -1521,7 +1547,7 @@ static void gen_constant( CompiledStatement* statement, const dsc* desc, bool ne
|
||||
case dtype_blob:
|
||||
case dtype_array:
|
||||
case dtype_timestamp:
|
||||
gen_descriptor(statement, desc, true);
|
||||
GEN_descriptor(statement, desc, true);
|
||||
value = *(SLONG *) p;
|
||||
stuff_word(statement, value);
|
||||
stuff_word(statement, value >> 16);
|
||||
@ -1534,7 +1560,7 @@ static void gen_constant( CompiledStatement* statement, const dsc* desc, bool ne
|
||||
{
|
||||
const USHORT length = desc->dsc_length;
|
||||
|
||||
gen_descriptor(statement, desc, true);
|
||||
GEN_descriptor(statement, desc, true);
|
||||
if (length)
|
||||
statement->append_raw_string(p, length);
|
||||
}
|
||||
@ -1571,7 +1597,7 @@ static void gen_constant( CompiledStatement* statement, dsql_nod* node, bool neg
|
||||
|
||||
/**
|
||||
|
||||
gen_descriptor
|
||||
GEN_descriptor
|
||||
|
||||
@brief Generate a blr descriptor from an internal descriptor.
|
||||
|
||||
@ -1581,7 +1607,7 @@ static void gen_constant( CompiledStatement* statement, dsql_nod* node, bool neg
|
||||
@param texttype
|
||||
|
||||
**/
|
||||
static void gen_descriptor( CompiledStatement* statement, const dsc* desc, bool texttype)
|
||||
void GEN_descriptor( CompiledStatement* statement, const dsc* desc, bool texttype)
|
||||
{
|
||||
switch (desc->dsc_dtype) {
|
||||
case dtype_text:
|
||||
@ -2417,7 +2443,7 @@ static void gen_searched_case( CompiledStatement* statement, const dsql_nod* nod
|
||||
// blr_value_if is used for building the case expression
|
||||
|
||||
stuff(statement, blr_cast);
|
||||
gen_descriptor(statement, &node->nod_desc, true);
|
||||
GEN_descriptor(statement, &node->nod_desc, true);
|
||||
const SSHORT count =
|
||||
node->nod_arg[e_searched_case_search_conditions]->nod_count;
|
||||
dsql_nod* boolean_list = node->nod_arg[e_searched_case_search_conditions];
|
||||
@ -2637,7 +2663,7 @@ static void gen_simple_case( CompiledStatement* statement, const dsql_nod* node)
|
||||
// blr_value_if is used for building the case expression
|
||||
|
||||
stuff(statement, blr_cast);
|
||||
gen_descriptor(statement, &node->nod_desc, true);
|
||||
GEN_descriptor(statement, &node->nod_desc, true);
|
||||
SSHORT count = node->nod_arg[e_simple_case_when_operands]->nod_count;
|
||||
dsql_nod* when_list = node->nod_arg[e_simple_case_when_operands];
|
||||
dsql_nod* results_list = node->nod_arg[e_simple_case_results];
|
||||
|
@ -24,7 +24,9 @@
|
||||
#ifndef DSQL_GEN_PROTO_H
|
||||
#define DSQL_GEN_PROTO_H
|
||||
|
||||
void GEN_descriptor(Jrd::CompiledStatement* statement, const dsc* desc, bool texttype);
|
||||
void GEN_expr(Jrd::CompiledStatement*, Jrd::dsql_nod*);
|
||||
void GEN_hidden_variables(Jrd::CompiledStatement* statement);
|
||||
void GEN_port(Jrd::CompiledStatement*, Jrd::dsql_msg*);
|
||||
void GEN_request(Jrd::CompiledStatement*, Jrd::dsql_nod*);
|
||||
void GEN_return(Jrd::CompiledStatement*, const Jrd::dsql_nod*, bool);
|
||||
|
@ -1836,7 +1836,8 @@ dsql_nod* MAKE_variable(dsql_fld* field, const TEXT* name, const dsql_var_type t
|
||||
strcpy(variable->var_name, name);
|
||||
//variable->var_flags = 0;
|
||||
variable->var_type = type;
|
||||
MAKE_desc_from_field(&node->nod_desc, field);
|
||||
if (field)
|
||||
MAKE_desc_from_field(&node->nod_desc, field);
|
||||
|
||||
return node;
|
||||
}
|
||||
@ -2006,7 +2007,8 @@ static void make_parameter_names(dsql_par* parameter, const dsql_nod* item)
|
||||
case nod_variable:
|
||||
{
|
||||
dsql_var* variable = (dsql_var*) item->nod_arg[e_var_variable];
|
||||
name_alias = variable->var_field->fld_name.c_str();
|
||||
if (variable->var_field)
|
||||
name_alias = variable->var_field->fld_name.c_str();
|
||||
break;
|
||||
}
|
||||
case nod_udf:
|
||||
|
@ -1043,6 +1043,7 @@ enum nod_flags_vals {
|
||||
|
||||
NOD_UNION_ALL = 1, // nod_list
|
||||
NOD_UNION_RECURSIVE = 2,
|
||||
NOD_SIMPLE_LIST = 4, // no need to enclose with blr_begin ... blr_end
|
||||
|
||||
NOD_READ_ONLY = 1, // nod_access
|
||||
NOD_READ_WRITE = 2,
|
||||
|
@ -241,6 +241,7 @@ static bool pass1_found_aggregate(const dsql_nod*, USHORT, USHORT, bool);
|
||||
static bool pass1_found_field(const dsql_nod*, USHORT, USHORT, bool*);
|
||||
static bool pass1_found_sub_select(const dsql_nod*);
|
||||
static dsql_nod* pass1_group_by_list(CompiledStatement*, dsql_nod*, dsql_nod*);
|
||||
static dsql_nod* pass1_hidden_variable(CompiledStatement* statement, dsql_nod* value);
|
||||
static dsql_nod* pass1_insert(CompiledStatement*, dsql_nod*, bool);
|
||||
static dsql_nod* pass1_join(CompiledStatement*, dsql_nod*);
|
||||
static dsql_nod* pass1_label(CompiledStatement*, dsql_nod*);
|
||||
@ -6155,6 +6156,30 @@ static dsql_nod* pass1_group_by_list(CompiledStatement* statement, dsql_nod* inp
|
||||
}
|
||||
|
||||
|
||||
// Create (if necessary) a hidden variable to store a temporary value.
|
||||
static dsql_nod* pass1_hidden_variable(CompiledStatement* statement, dsql_nod* value)
|
||||
{
|
||||
// For some node types, it's better to not create temporary value.
|
||||
switch (value->nod_type)
|
||||
{
|
||||
case nod_constant:
|
||||
case nod_dbkey:
|
||||
case nod_field:
|
||||
case nod_parameter:
|
||||
case nod_user_name:
|
||||
case nod_variable:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dsql_nod* var = MAKE_variable(NULL, "", VAR_local, 0, 0, statement->req_hidden_vars_number++);
|
||||
MAKE_desc(statement, &var->nod_desc, value, NULL);
|
||||
|
||||
statement->req_hidden_vars.push(var);
|
||||
|
||||
return var;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
||||
pass1_insert
|
||||
@ -9286,6 +9311,8 @@ static dsql_nod* pass1_update_or_insert(CompiledStatement* statement, dsql_nod*
|
||||
dsql_nod* match = NULL;
|
||||
USHORT match_count = 0;
|
||||
|
||||
DsqlNodStack varStack;
|
||||
|
||||
DsqlNodStack stack;
|
||||
dsql_nod** field_ptr = fields->nod_arg;
|
||||
dsql_nod** value_ptr = values->nod_arg;
|
||||
@ -9296,12 +9323,12 @@ static dsql_nod* pass1_update_or_insert(CompiledStatement* statement, dsql_nod*
|
||||
DEV_BLKCHK(*field_ptr, dsql_type_nod);
|
||||
DEV_BLKCHK(*value_ptr, dsql_type_nod);
|
||||
|
||||
dsql_nod* temp = MAKE_node(nod_assign, e_asgn_count);
|
||||
temp->nod_arg[e_asgn_value] = *value_ptr;
|
||||
temp->nod_arg[e_asgn_field] = *field_ptr;
|
||||
stack.push(temp);
|
||||
dsql_nod* assign = MAKE_node(nod_assign, e_asgn_count);
|
||||
assign->nod_arg[e_asgn_value] = *value_ptr;
|
||||
assign->nod_arg[e_asgn_field] = *field_ptr;
|
||||
stack.push(assign);
|
||||
|
||||
temp = *value_ptr;
|
||||
dsql_nod* temp = *value_ptr;
|
||||
dsql_nod* temp2 = insert->nod_arg[e_sto_statement]->nod_arg[field_ptr - fields->nod_arg]->nod_arg[1];
|
||||
set_parameter_type(statement, temp, temp2, false);
|
||||
|
||||
@ -9337,9 +9364,25 @@ static dsql_nod* pass1_update_or_insert(CompiledStatement* statement, dsql_nod*
|
||||
{
|
||||
++match_count;
|
||||
|
||||
dsql_nod*& expr = insert->nod_arg[e_sto_statement]->nod_arg[
|
||||
field_ptr - fields->nod_arg]->nod_arg[0];
|
||||
dsql_nod* var = pass1_hidden_variable(statement, expr);
|
||||
|
||||
if (var)
|
||||
{
|
||||
temp = MAKE_node(nod_assign, e_asgn_count);
|
||||
temp->nod_arg[e_asgn_value] = expr;
|
||||
temp->nod_arg[e_asgn_field] = var;
|
||||
varStack.push(temp);
|
||||
|
||||
assign->nod_arg[e_asgn_value] = expr = var;
|
||||
}
|
||||
else
|
||||
var = *value_ptr;
|
||||
|
||||
dsql_nod* eql = MAKE_node(equality_type, 2);
|
||||
eql->nod_arg[0] = *field_ptr;
|
||||
eql->nod_arg[1] = *value_ptr;
|
||||
eql->nod_arg[1] = var;
|
||||
|
||||
if (match)
|
||||
{
|
||||
@ -9424,9 +9467,11 @@ static dsql_nod* pass1_update_or_insert(CompiledStatement* statement, dsql_nod*
|
||||
if_nod->nod_arg[e_if_true] = insert;
|
||||
|
||||
// build the UPDATE / IF nodes
|
||||
dsql_nod* list = MAKE_node(nod_list, 2);
|
||||
list->nod_arg[0] = update;
|
||||
list->nod_arg[1] = if_nod;
|
||||
dsql_nod* list = MAKE_node(nod_list, 3);
|
||||
list->nod_arg[0] = MAKE_list(varStack);
|
||||
list->nod_arg[0]->nod_flags |= NOD_SIMPLE_LIST;
|
||||
list->nod_arg[1] = update;
|
||||
list->nod_arg[2] = if_nod;
|
||||
|
||||
// if RETURNING is present, req_type is already REQ_EXEC_PROCEDURE
|
||||
if (!input->nod_arg[e_upi_return])
|
||||
|
Loading…
Reference in New Issue
Block a user