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

fix some derived tables problems

This commit is contained in:
arnobrinkman 2003-08-24 02:36:46 +00:00
parent 5a09f3b11d
commit c61cbdc5ca

View File

@ -166,7 +166,7 @@ static BOOLEAN aggregate_found2(DSQL_REQ, DSQL_NOD, USHORT *, USHORT *, BOOLEAN)
static DSQL_NOD ambiguity_check(DSQL_REQ, DSQL_NOD, STR, DLLS);
static void assign_fld_dtype_from_dsc(DSQL_FLD, DSC *);
static DSQL_NOD compose(DSQL_NOD, DSQL_NOD, NOD_TYPE);
static void explode_asterisk(DSQL_NOD, DSQL_NOD, DLLS *);
static void explode_asterisk(DSQL_REQ, DSQL_NOD, DSQL_NOD, DLLS *);
static DSQL_NOD explode_outputs(DSQL_REQ, DSQL_PRC);
static void field_error(TEXT *, TEXT *, DSQL_NOD);
static PAR find_dbkey(DSQL_REQ, DSQL_NOD);
@ -193,6 +193,7 @@ static BOOLEAN pass1_found_field(DSQL_NOD, USHORT, USHORT, BOOLEAN *);
static DSQL_NOD pass1_group_by_list(DSQL_REQ, DSQL_NOD, DSQL_NOD);
static DSQL_NOD pass1_insert(DSQL_REQ, DSQL_NOD);
static DSQL_NOD pass1_join(DSQL_REQ, DSQL_NOD, USHORT);
static DSQL_NOD pass1_make_alias_from_field(TSQL, DSQL_FLD);
static void pass1_put_args_on_stack(DSQL_REQ, DSQL_NOD, DLLS *, USHORT);
static DSQL_NOD pass1_relation(DSQL_REQ, DSQL_NOD);
static DSQL_NOD pass1_rse(DSQL_REQ, DSQL_NOD, DSQL_NOD, DSQL_NOD);
@ -1583,10 +1584,16 @@ static BOOLEAN aggregate_found2(DSQL_REQ request, DSQL_NOD node, USHORT * curren
case nod_alias:
if (node->nod_flags & NOD_DERIVED_TABLE) {
// This is an alias from a derived table don't look further.
return aggregate;
// This is an alias from a derived table don't look further,
// but don't forget to check for deepest scope_level.
USHORT lscope_level = (node->nod_flags >> 1);
if (*deepest_level < lscope_level) {
*deepest_level = lscope_level;
}
}
else {
aggregate = aggregate_found2(request, node->nod_arg[e_alias_value], current_level, deepest_level, ignore_sub_selects);
}
aggregate = aggregate_found2(request, node->nod_arg[e_alias_value], current_level, deepest_level, ignore_sub_selects);
return aggregate;
case nod_map:
@ -1900,12 +1907,13 @@ static DSQL_NOD compose( DSQL_NOD expr1, DSQL_NOD expr2, NOD_TYPE operator_)
@brief Expand an '*' in a field list to the corresponding fields.
@param request
@param node
@param aggregate
@param stack
**/
static void explode_asterisk( DSQL_NOD node, DSQL_NOD aggregate, DLLS * stack)
static void explode_asterisk(DSQL_REQ request, DSQL_NOD node, DSQL_NOD aggregate, DLLS * stack)
{
DSQL_CTX context;
DSQL_REL relation;
@ -1916,8 +1924,8 @@ static void explode_asterisk( DSQL_NOD node, DSQL_NOD aggregate, DLLS * stack)
DEV_BLKCHK(aggregate, dsql_type_nod);
if (node->nod_type == nod_join) {
explode_asterisk(node->nod_arg[e_join_left_rel], aggregate, stack);
explode_asterisk(node->nod_arg[e_join_rght_rel], aggregate, stack);
explode_asterisk(request, node->nod_arg[e_join_left_rel], aggregate, stack);
explode_asterisk(request, node->nod_arg[e_join_rght_rel], aggregate, stack);
}
else if (node->nod_type == nod_derived_table) {
// AB: Derived table support
@ -1940,7 +1948,7 @@ static void explode_asterisk( DSQL_NOD node, DSQL_NOD aggregate, DLLS * stack)
node_alias->nod_arg[e_alias_value] = node_select_item->nod_arg[e_alias_value];
node_alias->nod_arg[e_alias_alias] = node_select_item->nod_arg[e_alias_alias];
node_alias->nod_desc = node_select_item->nod_desc;
node_alias->nod_flags |= NOD_DERIVED_TABLE;
node_alias->nod_flags = (request->req_scope_level << 1) | NOD_DERIVED_TABLE;
LLS_PUSH(node_alias, stack);
}
}
@ -2368,8 +2376,19 @@ static BOOLEAN invalid_reference(DSQL_CTX context, DSQL_NOD node, DSQL_NOD list,
break;
case nod_alias:
invalid |=
invalid_reference(context, node->nod_arg[e_alias_value], list, inside_own_map, inside_higher_map);
// If this is a derived table "virtual" field then it's a
// invalid mapping, because it should already be seen by
// checking group by list or as aggregate function.
if (node->nod_flags & NOD_DERIVED_TABLE) {
USHORT lscope_level = (node->nod_flags >> 1);
if (lscope_level == context->ctx_scope_level) {
invalid |= TRUE;
}
}
else {
invalid |=
invalid_reference(context, node->nod_arg[e_alias_value], list, inside_own_map, inside_higher_map);
}
break;
case nod_aggregate:
@ -2400,6 +2419,7 @@ static BOOLEAN invalid_reference(DSQL_CTX context, DSQL_NOD node, DSQL_NOD list,
case nod_current_role:
case nod_internal_info:
case nod_dbkey:
case nod_derived_table:
return FALSE;
}
@ -3259,12 +3279,11 @@ static DSQL_NOD pass1_derived_table(DSQL_REQ request, DSQL_NOD input)
{
DSQL_NOD *ptr, *end;
int count;
TSQL tdsql;
DEV_BLKCHK(request, dsql_type_req);
DEV_BLKCHK(input, dsql_type_nod);
tdsql = GET_THREAD_DATA;
TSQL tdsql = GET_THREAD_DATA;
DSQL_NOD node = MAKE_node (nod_derived_table, e_derived_table_count);
STR alias = (STR) input->nod_arg[e_derived_table_alias];
@ -3375,7 +3394,7 @@ static DSQL_NOD pass1_derived_table(DSQL_REQ request, DSQL_NOD input)
rse->nod_arg[e_rse_items]->nod_arg[count] = node_alias;
}
node_alias->nod_arg[e_alias_alias] = (DSQL_NOD) alias;
node_alias->nod_flags |= NOD_DERIVED_TABLE;
node_alias->nod_flags = (request->req_scope_level << 1) | NOD_DERIVED_TABLE;
}
}
@ -3387,35 +3406,37 @@ static DSQL_NOD pass1_derived_table(DSQL_REQ request, DSQL_NOD input)
for (; ptr < end; ptr++) {
DSQL_NOD node_select_item = (*ptr);
if (node_select_item->nod_type == nod_field) {
STR alias;
TEXT *src, *dest;
DSQL_NOD node_alias;
DSQL_FLD field = (DSQL_FLD) node_select_item->nod_arg[e_fld_field];
int alias_length = strlen(field->fld_name);
DSQL_NOD node_alias = pass1_make_alias_from_field(tdsql, field);
// Copy fieldname to a new string.
alias = FB_NEW_RPT(*tdsql->tsql_default, alias_length) str;
alias->str_length = alias_length;
src = field->fld_name;
dest = alias->str_data;
for (; alias_length; alias_length--) {
*dest++ = *src++;
}
// Create a alias and hook in.
node_alias = MAKE_node(nod_alias, e_alias_count);
node_alias->nod_arg[e_alias_value] = node_select_item;
node_alias->nod_arg[e_alias_alias] = (DSQL_NOD) alias;
node_alias->nod_desc = node_select_item->nod_desc;
node_alias->nod_flags |= NOD_DERIVED_TABLE;
node_alias->nod_flags = (request->req_scope_level << 1) | NOD_DERIVED_TABLE;
rse->nod_arg[e_rse_items]->nod_arg[count] = node_alias;
}
else if (node_select_item->nod_type == nod_map) {
// Don't forget aggregate's that have map on top.
MAP map_ = (MAP) node_select_item->nod_arg[e_map_map];
if (map_->map_node && (map_->map_node->nod_type == nod_field)) {
DSQL_FLD field = (DSQL_FLD) map_->map_node->nod_arg[e_fld_field];
DSQL_NOD node_alias = pass1_make_alias_from_field(tdsql, field);
node_alias->nod_arg[e_alias_value] = node_select_item;
node_alias->nod_desc = node_select_item->nod_desc;
node_alias->nod_flags = (request->req_scope_level << 1) | NOD_DERIVED_TABLE;
rse->nod_arg[e_rse_items]->nod_arg[count] = node_alias;
}
}
else if (node_select_item->nod_type == nod_alias) {
node_select_item->nod_flags = (request->req_scope_level << 1) | NOD_DERIVED_TABLE;
}
count++;
}
// Check if all select-items have an alias else show a message.
count = 0;
count = 1;
ptr = rse->nod_arg[e_rse_items]->nod_arg;
end = ptr + rse->nod_arg[e_rse_items]->nod_count;
for (; ptr < end; ptr++) {
@ -3547,7 +3568,7 @@ static DSQL_NOD pass1_field( DSQL_REQ request, DSQL_NOD input, USHORT list)
DSQL_CTX context = reinterpret_cast<DSQL_CTX>(stack->lls_object);
if (request->req_alias_relation_prefix) {
if (request->req_alias_relation_prefix && qualifier) {
STR req_qualifier = pass1_alias_concat(request->req_alias_relation_prefix, qualifier);
field = resolve_context(request, name, req_qualifier, context);
delete req_qualifier;
@ -3849,8 +3870,11 @@ static BOOLEAN pass1_found_aggregate(DSQL_NOD node, USHORT check_scope_level,
break;
case nod_alias:
found |= pass1_found_aggregate(node->nod_arg[e_alias_value],
check_scope_level, match_type, current_scope_level_equal);
// If this is a derived table alias don't look deeper.
if (!(node->nod_flags & NOD_DERIVED_TABLE)) {
found |= pass1_found_aggregate(node->nod_arg[e_alias_value],
check_scope_level, match_type, current_scope_level_equal);
}
break;
case nod_aggregate:
@ -4062,8 +4086,15 @@ static BOOLEAN pass1_found_field(DSQL_NOD node, USHORT check_scope_level,
break;
case nod_alias:
found |= pass1_found_field(node->nod_arg[e_alias_value],
check_scope_level, match_type, field);
// This is an alias from a derived table don't check it.
if (node->nod_flags & NOD_DERIVED_TABLE) {
// This is a "virtual" field
*field = TRUE;
}
else {
found |= pass1_found_field(node->nod_arg[e_alias_value],
check_scope_level, match_type, field);
}
break;
case nod_aggregate:
@ -4153,7 +4184,7 @@ static DSQL_NOD pass1_group_by_list(DSQL_REQ request, DSQL_NOD input, DSQL_NOD s
LLS_PUSH(frnode, &stack);
}
else {
explode_asterisk(frnode, NULL, &stack);
explode_asterisk(request, frnode, NULL, &stack);
}
}
else if ((sub->nod_type == nod_constant) && (sub->nod_desc.dsc_dtype == dtype_long)) {
@ -4355,6 +4386,34 @@ static DSQL_NOD pass1_join(DSQL_REQ request, DSQL_NOD input, USHORT proc_flag)
}
/**
pass1_make_alias_from_field
@brief Create a alias based on field name
@param tdsql
@param request
@param field
**/
static DSQL_NOD pass1_make_alias_from_field(TSQL tdsql, DSQL_FLD field)
{
DEV_BLKCHK(field, dsql_type_fld);
// Copy fieldname to a new string.
STR alias = FB_NEW_RPT(*tdsql->tsql_default, strlen(field->fld_name)) str;
strcpy(alias->str_data, field->fld_name);
alias->str_length = strlen(field->fld_name);
// Create a alias and hook in.
DSQL_NOD node_alias = MAKE_node(nod_alias, e_alias_count);
node_alias->nod_arg[e_alias_alias] = (DSQL_NOD) alias;
return node_alias;
}
/**
pass1_put_args_on_stack
@ -4811,7 +4870,7 @@ static DSQL_NOD pass1_rse( DSQL_REQ request, DSQL_NOD input, DSQL_NOD order, DSQ
stack = NULL;
list = rse->nod_arg[e_rse_streams];
for (ptr = list->nod_arg, end = ptr + list->nod_count; ptr < end; ptr++) {
explode_asterisk(*ptr, aggregate, &stack);
explode_asterisk(request, *ptr, aggregate, &stack);
}
list = rse->nod_arg[e_rse_items] = MAKE_list(stack);
/* dimitr: the below code reconstructs the select list after creation
@ -4938,7 +4997,7 @@ static DSQL_NOD pass1_rse( DSQL_REQ request, DSQL_NOD input, DSQL_NOD order, DSQ
stack = NULL;
list = rse->nod_arg[e_rse_streams];
for (ptr = list->nod_arg, end = ptr + list->nod_count; ptr < end; ptr++) {
explode_asterisk(*ptr, aggregate, &stack);
explode_asterisk(request, *ptr, aggregate, &stack);
}
target_rse->nod_arg[e_rse_reduced] = MAKE_list(stack);
}
@ -5122,7 +5181,7 @@ static DSQL_NOD pass1_sel_list( DSQL_REQ request, DSQL_NOD input)
LLS_PUSH(frnode, &stack);
}
else {
explode_asterisk(frnode, NULL, &stack);
explode_asterisk(request, frnode, NULL, &stack);
}
}
else
@ -5942,14 +6001,25 @@ static DSQL_NOD remap_field(DSQL_REQ request, DSQL_NOD field, DSQL_CTX context,
switch (field->nod_type) {
case nod_alias:
field->nod_arg[e_alias_value] =
remap_field(request, field->nod_arg[e_alias_value], context, current_level);
// If we got a alias from a derived table we should not remap anything
// deeper in the alias, but this "virtual" field should be mapped to
// the give context (ofcourse only if we're in the same scope-level).
if (field->nod_flags & NOD_DERIVED_TABLE) {
USHORT lscope_level = (field->nod_flags >> 1);
if (lscope_level == context->ctx_scope_level) {
return post_map(field, context);
}
}
else {
field->nod_arg[e_alias_value] =
remap_field(request, field->nod_arg[e_alias_value], context, current_level);
}
return field;
case nod_field:
lcontext = reinterpret_cast<DSQL_CTX>(field->nod_arg[e_fld_context]);
if (lcontext->ctx_scope_level == context->ctx_scope_level) {
return post_map(field, context);
return post_map(field, context);
}
else {
return field;