8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-23 23:23:04 +01:00

Fixed CORE-2041 - update or insert with gen_id() with wrong generator value

This commit is contained in:
asfernandes 2008-08-15 16:32:42 +00:00
parent 28209cb815
commit 5d4084d30c
7 changed files with 125 additions and 34 deletions

View File

@ -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); 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); statement->append_uchar(blr_stall);
// put a label before body of procedure, // put a label before body of procedure,
// so that any EXIT statement can get out // so that any EXIT statement can get out
statement->append_uchar(blr_label); statement->append_uchar(blr_label);
statement->append_uchar(0); statement->append_uchar(0);
statement->req_loop_level = 0; GEN_statement(statement, stmtNode);
statement->req_cursor_number = 0;
GEN_statement(statement, PASS1_statement(statement, procedure_node->nod_arg[e_prc_body]));
statement->req_type = REQ_DDL; statement->req_type = REQ_DDL;
statement->append_uchar(blr_end); statement->append_uchar(blr_end);
GEN_return(statement, procedure_node->nod_arg[e_prc_outputs], true); 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); 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); statement->append_uchar(blr_stall);
// Put a label before body of procedure, so that // Put a label before body of procedure, so that
// any exit statement can get out // any exit statement can get out
statement->append_uchar(blr_label); statement->append_uchar(blr_label);
statement->append_uchar(0); statement->append_uchar(0);
statement->req_loop_level = 0; GEN_statement(statement, stmtNode);
GEN_statement(statement, PASS1_statement(statement, node->nod_arg[e_exe_blk_body]));
if (outputs) if (outputs)
statement->req_type = REQ_SELECT_BLOCK; statement->req_type = REQ_SELECT_BLOCK;
else 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); trigger_node->nod_arg[e_trg_actions]->nod_arg[e_trg_act_dcls], 0);
statement->req_scope_level++; 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, // dimitr: I see no reason to deny EXIT command in triggers,
// hence I've added zero label at the beginning. // hence I've added zero label at the beginning.
// My first suspicion regarding an obvious conflict // 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. // Hopefully, system triggers are never recompiled.
statement->append_uchar(blr_label); statement->append_uchar(blr_label);
statement->append_uchar(0); statement->append_uchar(0);
statement->req_loop_level = 0; GEN_hidden_variables(statement);
statement->req_cursor_number = 0; GEN_statement(statement, actions);
GEN_statement(statement, PASS1_statement(statement, actions));
statement->req_scope_level--; statement->req_scope_level--;
statement->append_uchar(blr_end); statement->append_uchar(blr_end);
statement->end_blr(); 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, statement->put_debug_variable(variable->var_variable_number,
variable->var_name); variable->var_name);
++statement->req_hidden_vars_number;
} }

View File

@ -433,6 +433,7 @@ public:
req_dt_context(p), req_dt_context(p),
req_labels(p), req_labels(p),
req_cursors(p), req_cursors(p),
req_hidden_vars(p),
req_curr_ctes(p), req_curr_ctes(p),
req_ctes(p), req_ctes(p),
req_cte_aliases(p) req_cte_aliases(p)
@ -539,6 +540,8 @@ public:
USHORT req_client_dialect; //!< dialect passed into the API call USHORT req_client_dialect; //!< dialect passed into the API call
USHORT req_in_outer_join; //!< processing inside outer-join part USHORT req_in_outer_join; //!< processing inside outer-join part
dsql_str* req_alias_relation_prefix; //!< prefix for every relation-alias. 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 DsqlNodStack req_curr_ctes; // current processing CTE's
class dsql_ctx* req_recursive_ctx; // context of recursive CTE class dsql_ctx* req_recursive_ctx; // context of recursive CTE

View File

@ -67,7 +67,6 @@ static void gen_cast(CompiledStatement*, const dsql_nod*);
static void gen_coalesce(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*, const dsc*, bool);
static void gen_constant(CompiledStatement*, dsql_nod*, 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_error_condition(CompiledStatement*, const dsql_nod*);
static void gen_exec_stmt(CompiledStatement* statement, const dsql_nod* node); static void gen_exec_stmt(CompiledStatement* statement, const dsql_nod* node);
static void gen_field(CompiledStatement*, const dsql_ctx*, const dsql_fld*, dsql_nod*); 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; 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 GEN_expr
@ -694,7 +716,7 @@ void GEN_port(CompiledStatement* statement, dsql_msg* message)
parameter->par_desc.dsc_address = (UCHAR*)(IPTR) offset; parameter->par_desc.dsc_address = (UCHAR*)(IPTR) offset;
offset += parameter->par_desc.dsc_length; offset += parameter->par_desc.dsc_length;
// if (statement->req_blr_string) // if (statement->req_blr_string)
gen_descriptor(statement, &parameter->par_desc, false); GEN_descriptor(statement, &parameter->par_desc, false);
} }
if (offset > MAX_FORMAT_SIZE) { if (offset > MAX_FORMAT_SIZE) {
@ -758,6 +780,8 @@ void GEN_request( CompiledStatement* statement, dsql_nod* node)
{ {
stuff(statement, blr_begin); stuff(statement, blr_begin);
GEN_hidden_variables(statement);
switch (statement->req_type) switch (statement->req_type)
{ {
case REQ_SELECT: case REQ_SELECT:
@ -1033,13 +1057,15 @@ void GEN_statement( CompiledStatement* statement, dsql_nod* node)
return; return;
case nod_list: 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; for (ptr = node->nod_arg, end = ptr + node->nod_count; ptr < end;
ptr++) ptr++)
{ {
GEN_statement(statement, *ptr); GEN_statement(statement, *ptr);
} }
stuff(statement, blr_end); if (!(node->nod_flags & NOD_SIMPLE_LIST))
stuff(statement, blr_end);
return; return;
case nod_erase: 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 // blr_value_if is used for building the coalesce function
dsql_nod* list = node->nod_arg[0]; dsql_nod* list = node->nod_arg[0];
stuff(statement, blr_cast); 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; dsql_nod* const* ptr = list->nod_arg;
for (const dsql_nod* const* const end = ptr + (list->nod_count - 1); for (const dsql_nod* const* const end = ptr + (list->nod_count - 1);
ptr < end; ptr++) ptr < end; ptr++)
@ -1427,7 +1453,7 @@ static void gen_constant( CompiledStatement* statement, const dsc* desc, bool ne
switch (desc->dsc_dtype) { switch (desc->dsc_dtype) {
case dtype_short: case dtype_short:
gen_descriptor(statement, desc, true); GEN_descriptor(statement, desc, true);
value = *(SSHORT *) p; value = *(SSHORT *) p;
if (negate_value) if (negate_value)
value = -value; value = -value;
@ -1435,7 +1461,7 @@ static void gen_constant( CompiledStatement* statement, const dsc* desc, bool ne
break; break;
case dtype_long: case dtype_long:
gen_descriptor(statement, desc, true); GEN_descriptor(statement, desc, true);
value = *(SLONG *) p; value = *(SLONG *) p;
if (negate_value) if (negate_value)
value = -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_time:
case dtype_sql_date: case dtype_sql_date:
gen_descriptor(statement, desc, true); GEN_descriptor(statement, desc, true);
value = *(SLONG *) p; value = *(SLONG *) p;
stuff_word(statement, value); stuff_word(statement, value);
stuff_word(statement, value >> 16); 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 /* this is used for approximate/large numeric literal
which is transmitted to the engine as a string. 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. // Length of string literal, cast because it could be > 127 bytes.
const USHORT l = (USHORT)(UCHAR) desc->dsc_scale; const USHORT l = (USHORT)(UCHAR) desc->dsc_scale;
if (negate_value) { if (negate_value) {
@ -1521,7 +1547,7 @@ static void gen_constant( CompiledStatement* statement, const dsc* desc, bool ne
case dtype_blob: case dtype_blob:
case dtype_array: case dtype_array:
case dtype_timestamp: case dtype_timestamp:
gen_descriptor(statement, desc, true); GEN_descriptor(statement, desc, true);
value = *(SLONG *) p; value = *(SLONG *) p;
stuff_word(statement, value); stuff_word(statement, value);
stuff_word(statement, value >> 16); 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; const USHORT length = desc->dsc_length;
gen_descriptor(statement, desc, true); GEN_descriptor(statement, desc, true);
if (length) if (length)
statement->append_raw_string(p, 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. @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 @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) { switch (desc->dsc_dtype) {
case dtype_text: 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 // blr_value_if is used for building the case expression
stuff(statement, blr_cast); stuff(statement, blr_cast);
gen_descriptor(statement, &node->nod_desc, true); GEN_descriptor(statement, &node->nod_desc, true);
const SSHORT count = const SSHORT count =
node->nod_arg[e_searched_case_search_conditions]->nod_count; node->nod_arg[e_searched_case_search_conditions]->nod_count;
dsql_nod* boolean_list = node->nod_arg[e_searched_case_search_conditions]; 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 // blr_value_if is used for building the case expression
stuff(statement, blr_cast); 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; 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* when_list = node->nod_arg[e_simple_case_when_operands];
dsql_nod* results_list = node->nod_arg[e_simple_case_results]; dsql_nod* results_list = node->nod_arg[e_simple_case_results];

View File

@ -24,7 +24,9 @@
#ifndef DSQL_GEN_PROTO_H #ifndef DSQL_GEN_PROTO_H
#define 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_expr(Jrd::CompiledStatement*, Jrd::dsql_nod*);
void GEN_hidden_variables(Jrd::CompiledStatement* statement);
void GEN_port(Jrd::CompiledStatement*, Jrd::dsql_msg*); void GEN_port(Jrd::CompiledStatement*, Jrd::dsql_msg*);
void GEN_request(Jrd::CompiledStatement*, Jrd::dsql_nod*); void GEN_request(Jrd::CompiledStatement*, Jrd::dsql_nod*);
void GEN_return(Jrd::CompiledStatement*, const Jrd::dsql_nod*, bool); void GEN_return(Jrd::CompiledStatement*, const Jrd::dsql_nod*, bool);

View File

@ -1836,7 +1836,8 @@ dsql_nod* MAKE_variable(dsql_fld* field, const TEXT* name, const dsql_var_type t
strcpy(variable->var_name, name); strcpy(variable->var_name, name);
//variable->var_flags = 0; //variable->var_flags = 0;
variable->var_type = type; variable->var_type = type;
MAKE_desc_from_field(&node->nod_desc, field); if (field)
MAKE_desc_from_field(&node->nod_desc, field);
return node; return node;
} }
@ -2006,7 +2007,8 @@ static void make_parameter_names(dsql_par* parameter, const dsql_nod* item)
case nod_variable: case nod_variable:
{ {
dsql_var* variable = (dsql_var*) item->nod_arg[e_var_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; break;
} }
case nod_udf: case nod_udf:

View File

@ -1043,6 +1043,7 @@ enum nod_flags_vals {
NOD_UNION_ALL = 1, // nod_list NOD_UNION_ALL = 1, // nod_list
NOD_UNION_RECURSIVE = 2, 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_ONLY = 1, // nod_access
NOD_READ_WRITE = 2, NOD_READ_WRITE = 2,

View File

@ -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_field(const dsql_nod*, USHORT, USHORT, bool*);
static bool pass1_found_sub_select(const dsql_nod*); 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_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_insert(CompiledStatement*, dsql_nod*, bool);
static dsql_nod* pass1_join(CompiledStatement*, dsql_nod*); static dsql_nod* pass1_join(CompiledStatement*, dsql_nod*);
static dsql_nod* pass1_label(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 pass1_insert
@ -9286,6 +9311,8 @@ static dsql_nod* pass1_update_or_insert(CompiledStatement* statement, dsql_nod*
dsql_nod* match = NULL; dsql_nod* match = NULL;
USHORT match_count = 0; USHORT match_count = 0;
DsqlNodStack varStack;
DsqlNodStack stack; DsqlNodStack stack;
dsql_nod** field_ptr = fields->nod_arg; dsql_nod** field_ptr = fields->nod_arg;
dsql_nod** value_ptr = values->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(*field_ptr, dsql_type_nod);
DEV_BLKCHK(*value_ptr, dsql_type_nod); DEV_BLKCHK(*value_ptr, dsql_type_nod);
dsql_nod* temp = MAKE_node(nod_assign, e_asgn_count); dsql_nod* assign = MAKE_node(nod_assign, e_asgn_count);
temp->nod_arg[e_asgn_value] = *value_ptr; assign->nod_arg[e_asgn_value] = *value_ptr;
temp->nod_arg[e_asgn_field] = *field_ptr; assign->nod_arg[e_asgn_field] = *field_ptr;
stack.push(temp); 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]; 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); set_parameter_type(statement, temp, temp2, false);
@ -9337,9 +9364,25 @@ static dsql_nod* pass1_update_or_insert(CompiledStatement* statement, dsql_nod*
{ {
++match_count; ++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); dsql_nod* eql = MAKE_node(equality_type, 2);
eql->nod_arg[0] = *field_ptr; eql->nod_arg[0] = *field_ptr;
eql->nod_arg[1] = *value_ptr; eql->nod_arg[1] = var;
if (match) 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; if_nod->nod_arg[e_if_true] = insert;
// build the UPDATE / IF nodes // build the UPDATE / IF nodes
dsql_nod* list = MAKE_node(nod_list, 2); dsql_nod* list = MAKE_node(nod_list, 3);
list->nod_arg[0] = update; list->nod_arg[0] = MAKE_list(varStack);
list->nod_arg[1] = if_nod; 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 RETURNING is present, req_type is already REQ_EXEC_PROCEDURE
if (!input->nod_arg[e_upi_return]) if (!input->nod_arg[e_upi_return])