8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-23 16:03:02 +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".
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);
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
@ -3109,7 +3111,8 @@ static void define_trigger( dsql_req* request, dsql_nod* node)
{
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;
}
else
{
@ -3120,7 +3123,8 @@ static void define_trigger( dsql_req* request, dsql_nod* node)
{
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;
}
else
{
@ -4010,9 +4014,11 @@ static void define_view_trigger( dsql_req* request, dsql_nod* node, dsql_nod* rs
reset_context_stack(request);
dsql_nod* temp_alias = relation_node->nod_arg[e_rln_alias];
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);
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;
if (sav_context) {

View File

@ -532,6 +532,7 @@ public:
dsql_nod* ctx_rse; //!< Sub-rse for aggregates
dsql_ctx* ctx_parent; //!< Parent context for aggregates
TEXT* ctx_alias; //!< Context alias
TEXT* ctx_internal_alias; //!< Alias as specified in query
USHORT ctx_context; //!< Context id
USHORT ctx_scope_level; //!< Subquery level within this request
USHORT ctx_flags; //!< Various flag values
@ -559,6 +560,7 @@ public:
// Flag values for ctx_flags
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
//! TMN: NOTE! This datatype should definitely be renamed!

View File

@ -404,7 +404,8 @@ enum nod_flags_vals {
NOD_CURSOR_FOR = 2,
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

View File

@ -395,9 +395,14 @@ dsql_ctx* PASS1_make_context(dsql_req* request, dsql_nod* relation_node)
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);
if (request->req_alias_relation_prefix && !(relation_node->nod_type == nod_derived_table))
{
{
if (string) {
string = pass1_alias_concat(request->req_alias_relation_prefix, string);
}
@ -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
dsql_nod* dt = MAKE_node(nod_derived_table, e_derived_table_count);
// 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];
dsql_nod* from = MAKE_node(nod_list, 1);
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
// 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;
request->req_context = &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_alias_relation_prefix = pass1_alias_concat(req_alias_relation_prefix, alias);
// 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
// so create view (ddl) can deal with it.
// 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());
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;
if (request->req_alias_relation_prefix && qualifier) {
dsql_str* req_qualifier =
pass1_alias_concat(request->req_alias_relation_prefix, qualifier);
field = resolve_context(request, req_qualifier, context, is_check_constraint);
delete req_qualifier;
}
else {
//if (request->req_alias_relation_prefix && qualifier) {
//dsql_str* req_qualifier =
// pass1_alias_concat(request->req_alias_relation_prefix, qualifier);
// field = resolve_context(request, qualifier, context, is_check_constraint);
//delete req_qualifier;
//}
//else {
field = resolve_context(request, qualifier, context, is_check_constraint);
}
//}
// AB: When there's no relation and no procedure then we have a derived table.
const bool is_derived_table =
(!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.
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++;
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 =
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);
}
//}
request->req_scope_level--;
if (!dt_context) {
// 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.
if (context->ctx_alias) {
if (!strcmp(context->ctx_alias,
if (context->ctx_internal_alias) {
if (!strcmp(context->ctx_internal_alias,
reinterpret_cast<const char*>(alias->str_data)))
{
return context;
@ -7803,8 +7823,8 @@ static dsql_fld* resolve_context( dsql_req* request, const dsql_str* qualifier,
// }
TEXT* table_name = NULL;
if (context->ctx_alias) {
table_name = context->ctx_alias;
if (context->ctx_internal_alias) {
table_name = context->ctx_internal_alias;
}
// AB: For a check constraint we should ignore the alias if the alias
// contains the "NEW" alias. This is because it is possible