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

Fix derived table issues with NEW/OLD contexts (Triggers/check-constraints)

Also adjust IN predicate behaviour to derived table.
PLAN parsing for derived tables will be fixed later.
This commit is contained in:
arnobrinkman 2005-07-25 14:43:28 +00:00
parent 67b12093cf
commit 22ac7c9cdc
4 changed files with 58 additions and 29 deletions

View File

@ -1166,9 +1166,11 @@ static void define_constraint_trigger(dsql_req* request, dsql_nod* node)
// record for fetch operation". // record for fetch operation".
relation_node->nod_arg[e_rln_alias] = (dsql_nod*) MAKE_cstring(OLD_CONTEXT); relation_node->nod_arg[e_rln_alias] = (dsql_nod*) MAKE_cstring(OLD_CONTEXT);
PASS1_make_context(request, relation_node); dsql_ctx* oldContext = PASS1_make_context(request, relation_node);
oldContext->ctx_flags |= CTX_system;
relation_node->nod_arg[e_rln_alias] = (dsql_nod*) MAKE_cstring(NEW_CONTEXT); relation_node->nod_arg[e_rln_alias] = (dsql_nod*) MAKE_cstring(NEW_CONTEXT);
PASS1_make_context(request, relation_node); dsql_ctx* newContext = PASS1_make_context(request, relation_node);
newContext->ctx_flags |= CTX_system;
// generate the condition for firing the trigger // generate the condition for firing the trigger
@ -3109,7 +3111,8 @@ static void define_trigger( dsql_req* request, dsql_nod* node)
{ {
relation_node->nod_arg[e_rln_alias] = relation_node->nod_arg[e_rln_alias] =
(dsql_nod*) MAKE_cstring(OLD_CONTEXT); (dsql_nod*) MAKE_cstring(OLD_CONTEXT);
PASS1_make_context(request, relation_node); dsql_ctx* oldContext = PASS1_make_context(request, relation_node);
oldContext->ctx_flags |= CTX_system;
} }
else else
{ {
@ -3120,7 +3123,8 @@ static void define_trigger( dsql_req* request, dsql_nod* node)
{ {
relation_node->nod_arg[e_rln_alias] = relation_node->nod_arg[e_rln_alias] =
(dsql_nod*) MAKE_cstring(NEW_CONTEXT); (dsql_nod*) MAKE_cstring(NEW_CONTEXT);
PASS1_make_context(request, relation_node); dsql_ctx* newContext = PASS1_make_context(request, relation_node);
newContext->ctx_flags |= CTX_system;
} }
else else
{ {
@ -4010,9 +4014,11 @@ static void define_view_trigger( dsql_req* request, dsql_nod* node, dsql_nod* rs
reset_context_stack(request); reset_context_stack(request);
dsql_nod* temp_alias = relation_node->nod_arg[e_rln_alias]; dsql_nod* temp_alias = relation_node->nod_arg[e_rln_alias];
relation_node->nod_arg[e_rln_alias] = (dsql_nod*) MAKE_cstring(OLD_CONTEXT); relation_node->nod_arg[e_rln_alias] = (dsql_nod*) MAKE_cstring(OLD_CONTEXT);
PASS1_make_context(request, relation_node); dsql_ctx* oldContext = PASS1_make_context(request, relation_node);
oldContext->ctx_flags |= CTX_system;
relation_node->nod_arg[e_rln_alias] = (dsql_nod*) MAKE_cstring(NEW_CONTEXT); relation_node->nod_arg[e_rln_alias] = (dsql_nod*) MAKE_cstring(NEW_CONTEXT);
PASS1_make_context(request, relation_node); dsql_ctx* newContext = PASS1_make_context(request, relation_node);
newContext->ctx_flags |= CTX_system;
relation_node->nod_arg[e_rln_alias] = temp_alias; relation_node->nod_arg[e_rln_alias] = temp_alias;
if (sav_context) { if (sav_context) {

View File

@ -532,6 +532,7 @@ public:
dsql_nod* ctx_rse; //!< Sub-rse for aggregates dsql_nod* ctx_rse; //!< Sub-rse for aggregates
dsql_ctx* ctx_parent; //!< Parent context for aggregates dsql_ctx* ctx_parent; //!< Parent context for aggregates
TEXT* ctx_alias; //!< Context alias TEXT* ctx_alias; //!< Context alias
TEXT* ctx_internal_alias; //!< Alias as specified in query
USHORT ctx_context; //!< Context id USHORT ctx_context; //!< Context id
USHORT ctx_scope_level; //!< Subquery level within this request USHORT ctx_scope_level; //!< Subquery level within this request
USHORT ctx_flags; //!< Various flag values USHORT ctx_flags; //!< Various flag values
@ -559,6 +560,7 @@ public:
// Flag values for ctx_flags // Flag values for ctx_flags
const USHORT CTX_outer_join = 0x01; // reference is part of an outer join const USHORT CTX_outer_join = 0x01; // reference is part of an outer join
const USHORT CTX_system = 0x02; // Context generated by system (NEW/OLD in triggers,check-constraint)
//! Aggregate/union map block to map virtual fields to their base //! Aggregate/union map block to map virtual fields to their base
//! TMN: NOTE! This datatype should definitely be renamed! //! TMN: NOTE! This datatype should definitely be renamed!

View File

@ -404,7 +404,8 @@ enum nod_flags_vals {
NOD_CURSOR_FOR = 2, NOD_CURSOR_FOR = 2,
NOD_CURSOR_ALL = USHORT(-1U), NOD_CURSOR_ALL = USHORT(-1U),
NOD_DT_IGNORE_COLUMN_CHECK = 1 NOD_DT_IGNORE_COLUMN_CHECK = 1,
NOD_DT_ALLOW_OUTER_REFERENCE = 2
}; };
// Parameters to MAKE_constant // Parameters to MAKE_constant

View File

@ -395,6 +395,11 @@ dsql_ctx* PASS1_make_context(dsql_req* request, dsql_nod* relation_node)
string = (dsql_str*) relation_node->nod_arg[e_rln_alias]; string = (dsql_str*) relation_node->nod_arg[e_rln_alias];
} }
if (string)
{
context->ctx_internal_alias = (TEXT*) string->str_data;
}
DEV_BLKCHK(string, dsql_type_str); DEV_BLKCHK(string, dsql_type_str);
if (request->req_alias_relation_prefix && !(relation_node->nod_type == nod_derived_table)) if (request->req_alias_relation_prefix && !(relation_node->nod_type == nod_derived_table))
{ {
@ -2928,7 +2933,7 @@ static dsql_nod* pass1_any( dsql_req* request, dsql_nod* input, NOD_TYPE ntype)
// create a derived table representing our subquery // create a derived table representing our subquery
dsql_nod* dt = MAKE_node(nod_derived_table, e_derived_table_count); dsql_nod* dt = MAKE_node(nod_derived_table, e_derived_table_count);
// Ignore validation for columnames that must exist for "user" derived tables. // Ignore validation for columnames that must exist for "user" derived tables.
dt->nod_flags |= NOD_DT_IGNORE_COLUMN_CHECK; dt->nod_flags |= (NOD_DT_IGNORE_COLUMN_CHECK | NOD_DT_ALLOW_OUTER_REFERENCE);
dt->nod_arg[e_derived_table_rse] = input->nod_arg[1]; dt->nod_arg[e_derived_table_rse] = input->nod_arg[1];
dsql_nod* from = MAKE_node(nod_list, 1); dsql_nod* from = MAKE_node(nod_list, 1);
from->nod_arg[0] = dt; from->nod_arg[0] = dt;
@ -3658,8 +3663,21 @@ static dsql_nod* pass1_derived_table(dsql_req* request, dsql_nod* input, bool pr
// Change req_context, because when we are processing the derived table rse // Change req_context, because when we are processing the derived table rse
// it may not reference to other streams in the same scope_level. // it may not reference to other streams in the same scope_level.
const bool allowOuterReference = (input->nod_flags & NOD_DT_ALLOW_OUTER_REFERENCE);
DsqlContextStack temp; DsqlContextStack temp;
if (!allowOuterReference)
{
// Put special contexts (NEW/OLD) also on the stack
for (DsqlContextStack::iterator stack(*request->req_context); stack.hasData(); ++stack)
{
dsql_ctx* context = stack.object();
if (context->ctx_flags & CTX_system)
{
temp.push(context);
}
}
request->req_context = &temp; request->req_context = &temp;
}
request->req_alias_relation_prefix = pass1_alias_concat(req_alias_relation_prefix, alias); request->req_alias_relation_prefix = pass1_alias_concat(req_alias_relation_prefix, alias);
// AB: 2005-01-06 // AB: 2005-01-06
@ -3695,7 +3713,7 @@ static dsql_nod* pass1_derived_table(dsql_req* request, dsql_nod* input, bool pr
// Finish off by cleaning up contexts and put them into req_dt_context // Finish off by cleaning up contexts and put them into req_dt_context
// so create view (ddl) can deal with it. // so create view (ddl) can deal with it.
// Also add the used contexts into the childs stack. // Also add the used contexts into the childs stack.
while (request->req_context->hasData()) while (request->req_context->hasData() && (request->req_context != req_base))
{ {
request->req_dt_context.push(request->req_context->object()); request->req_dt_context.push(request->req_context->object());
context->ctx_childs_derived_table.push(request->req_context->pop()); context->ctx_childs_derived_table.push(request->req_context->pop());
@ -4100,15 +4118,15 @@ static dsql_nod* pass1_field( dsql_req* request, dsql_nod* input,
} }
dsql_fld* field; dsql_fld* field;
if (request->req_alias_relation_prefix && qualifier) { //if (request->req_alias_relation_prefix && qualifier) {
dsql_str* req_qualifier = //dsql_str* req_qualifier =
pass1_alias_concat(request->req_alias_relation_prefix, qualifier); // pass1_alias_concat(request->req_alias_relation_prefix, qualifier);
field = resolve_context(request, req_qualifier, context, is_check_constraint); // field = resolve_context(request, qualifier, context, is_check_constraint);
delete req_qualifier; //delete req_qualifier;
} //}
else { //else {
field = resolve_context(request, qualifier, context, is_check_constraint); field = resolve_context(request, qualifier, context, is_check_constraint);
} //}
// AB: When there's no relation and no procedure then we have a derived table. // AB: When there's no relation and no procedure then we have a derived table.
const bool is_derived_table = const bool is_derived_table =
(!context->ctx_procedure && !context->ctx_relation && context->ctx_rse); (!context->ctx_procedure && !context->ctx_relation && context->ctx_rse);
@ -5716,15 +5734,17 @@ static dsql_nod* pass1_alias_list(dsql_req* request, dsql_nod* alias_list)
// Is this context a derived table. // Is this context a derived table.
if (!context->ctx_relation && !context->ctx_procedure && context->ctx_rse) { if (!context->ctx_relation && !context->ctx_procedure && context->ctx_rse) {
dsql_str* tmp_qualifier = (dsql_str*) *arg; //dsql_str* tmp_qualifier = (dsql_str*) *arg;
arg++; arg++;
tmp_qualifier = pass1_alias_concat(tmp_qualifier, (dsql_str*) *arg); //tmp_qualifier = pass1_alias_concat(tmp_qualifier, (dsql_str*) *arg);
request->req_scope_level++;
//dsql_ctx* dt_context =
// pass1_alias(request, context->ctx_childs_derived_table, tmp_qualifier);
//if (!dt_context) {
dsql_ctx* dt_context = dsql_ctx* dt_context =
pass1_alias(request, context->ctx_childs_derived_table, tmp_qualifier);
if (!dt_context) {
dt_context =
pass1_alias(request, context->ctx_childs_derived_table, (dsql_str*) *arg); pass1_alias(request, context->ctx_childs_derived_table, (dsql_str*) *arg);
} //}
request->req_scope_level--;
if (!dt_context) { if (!dt_context) {
// there is no alias or table named %s at this scope level. // there is no alias or table named %s at this scope level.
@ -5821,8 +5841,8 @@ static dsql_ctx* pass1_alias(dsql_req* request, DsqlContextStack& stack, dsql_st
} }
// check for matching alias. // check for matching alias.
if (context->ctx_alias) { if (context->ctx_internal_alias) {
if (!strcmp(context->ctx_alias, if (!strcmp(context->ctx_internal_alias,
reinterpret_cast<const char*>(alias->str_data))) reinterpret_cast<const char*>(alias->str_data)))
{ {
return context; return context;
@ -7803,8 +7823,8 @@ static dsql_fld* resolve_context( dsql_req* request, const dsql_str* qualifier,
// } // }
TEXT* table_name = NULL; TEXT* table_name = NULL;
if (context->ctx_alias) { if (context->ctx_internal_alias) {
table_name = context->ctx_alias; table_name = context->ctx_internal_alias;
} }
// AB: For a check constraint we should ignore the alias if the alias // AB: For a check constraint we should ignore the alias if the alias
// contains the "NEW" alias. This is because it is possible // contains the "NEW" alias. This is because it is possible