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

Fixed CORE-1246 - Incorrect column values with outer joins and derived tables

This commit is contained in:
asfernandes 2008-09-07 19:44:48 +00:00
parent 10562bbcdf
commit b550749a47
14 changed files with 201 additions and 25 deletions

View File

@ -654,7 +654,8 @@ class dsql_ctx : public pool_alloc<dsql_type_ctx>
{
public:
explicit dsql_ctx(MemoryPool &p)
: ctx_childs_derived_table(p),
: ctx_main_derived_contexts(p),
ctx_childs_derived_table(p),
ctx_imp_join(p)
{
}
@ -672,6 +673,8 @@ public:
USHORT ctx_recursive; //!< Secondary context id for recursive UNION (nobody referred to this context)
USHORT ctx_scope_level; //!< Subquery level within this request
USHORT ctx_flags; //!< Various flag values
USHORT ctx_in_outer_join; // req_in_outer_join when context was created
DsqlContextStack ctx_main_derived_contexts; // contexts used for blr_derived_expr
DsqlContextStack ctx_childs_derived_table; //!< Childs derived table context
Firebird::GenericMap<Firebird::Pair<Firebird::Left<
Firebird::MetaName, ImplicitJoin*> > > ctx_imp_join; // Map of USING fieldname to ImplicitJoin
@ -690,6 +693,8 @@ public:
ctx_recursive = v.ctx_recursive;
ctx_scope_level = v.ctx_scope_level;
ctx_flags = v.ctx_flags;
ctx_in_outer_join = v.ctx_in_outer_join;
ctx_main_derived_contexts.assign(v.ctx_main_derived_contexts);
ctx_childs_derived_table.assign(v.ctx_childs_derived_table);
ctx_imp_join.assign(v.ctx_imp_join);

View File

@ -171,6 +171,34 @@ void GEN_expr(CompiledStatement* statement, dsql_nod* node)
return;
case nod_derived_field:
// ASF: If we are not referencing a field, we should evaluate the expression based on
// a set (ORed) of contexts. If any of them are in a valid position the expression is
// evaluated, otherwise a NULL will be returned. This is fix for CORE-1246.
if (node->nod_arg[e_derived_field_value]->nod_type != nod_field &&
node->nod_arg[e_derived_field_value]->nod_type != nod_dbkey &&
node->nod_arg[e_derived_field_value]->nod_type != nod_map)
{
dsql_ctx* ctx = (dsql_ctx*) node->nod_arg[e_derived_field_context];
if (ctx->ctx_main_derived_contexts.hasData())
{
if (ctx->ctx_main_derived_contexts.getCount() > MAX_UCHAR)
{
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-204) <<
Arg::Gds(isc_imp_exc) <<
Arg::Gds(isc_ctx_too_big));
}
stuff(statement, blr_derived_expr);
stuff(statement, ctx->ctx_main_derived_contexts.getCount());
for (DsqlContextStack::iterator stack(ctx->ctx_main_derived_contexts);
stack.hasData(); ++stack)
{
stuff(statement, stack.object()->ctx_context);
}
}
}
GEN_expr(statement, node->nod_arg[e_derived_field_value]);
return;

View File

@ -2005,6 +2005,9 @@ static void make_parameter_names(dsql_par* parameter, const dsql_nod* item)
case nod_agg_list:
name_alias = "LIST";
break;
case nod_constant:
name_alias = "CONSTANT";
break;
} // switch(map_node->nod_type)
break;
} // case nod_map

View File

@ -418,6 +418,7 @@ dsql_ctx* PASS1_make_context(CompiledStatement* statement, const dsql_nod* relat
if (statement->req_in_outer_join) {
context->ctx_flags |= CTX_outer_join;
}
context->ctx_in_outer_join = statement->req_in_outer_join;
// find the context alias name, if it exists.
dsql_str* string;
@ -4837,18 +4838,38 @@ static dsql_nod* pass1_derived_table(CompiledStatement* statement, dsql_nod* inp
rse = PASS1_rse(statement, select_expr, NULL);
}
USHORT minOuterJoin = MAX_USHORT;
// 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 (temp.hasData() && (temp.object() != baseContext))
{
statement->req_dt_context.push(temp.object());
// Collect contexts that will be used for blr_derived_expr generation.
// We want all child contexts with minimum ctx_in_outer_join.
dsql_ctx* childCtx = temp.object();
if (childCtx->ctx_in_outer_join <= minOuterJoin &&
(childCtx->ctx_relation || childCtx->ctx_procedure))
{
if (childCtx->ctx_parent)
childCtx = childCtx->ctx_parent;
if (childCtx->ctx_in_outer_join < minOuterJoin)
{
minOuterJoin = childCtx->ctx_in_outer_join;
context->ctx_main_derived_contexts.clear();
}
context->ctx_main_derived_contexts.push(childCtx);
}
statement->req_dt_context.push(childCtx);
context->ctx_childs_derived_table.push(temp.pop());
}
while (temp.hasData())
{
temp.pop();
}
}
context->ctx_rse = node->nod_arg[e_derived_table_rse] = rse;
@ -6430,7 +6451,7 @@ static dsql_nod* pass1_join(CompiledStatement* statement, dsql_nod* input)
PASS1_node(statement, input->nod_arg[e_join_left_rel]);
node->nod_arg[e_join_rght_rel] =
PASS1_node(statement, input->nod_arg[e_join_rght_rel]);
break;
break;
case nod_join_left:
node->nod_arg[e_join_left_rel] =
PASS1_node(statement, input->nod_arg[e_join_left_rel]);
@ -6438,7 +6459,7 @@ static dsql_nod* pass1_join(CompiledStatement* statement, dsql_nod* input)
node->nod_arg[e_join_rght_rel] =
PASS1_node(statement, input->nod_arg[e_join_rght_rel]);
statement->req_in_outer_join--;
break;
break;
case nod_join_right:
statement->req_in_outer_join++;
node->nod_arg[e_join_left_rel] =
@ -6446,7 +6467,7 @@ static dsql_nod* pass1_join(CompiledStatement* statement, dsql_nod* input)
statement->req_in_outer_join--;
node->nod_arg[e_join_rght_rel] =
PASS1_node(statement, input->nod_arg[e_join_rght_rel]);
break;
break;
case nod_join_full:
statement->req_in_outer_join++;
node->nod_arg[e_join_left_rel] =
@ -6454,11 +6475,11 @@ static dsql_nod* pass1_join(CompiledStatement* statement, dsql_nod* input)
node->nod_arg[e_join_rght_rel] =
PASS1_node(statement, input->nod_arg[e_join_rght_rel]);
statement->req_in_outer_join--;
break;
break;
default:
fb_assert(false); // join type expected
break;
break;
}
// Process boolean
@ -10036,6 +10057,9 @@ static dsql_nod* remap_field(CompiledStatement* statement, dsql_nod* field,
field->nod_arg[e_hidden_var_expr], context, current_level);
return field;
case nod_constant:
return post_map(field, context);
default:
return field;
}

View File

@ -141,22 +141,44 @@ bool OPT_computable(CompilerScratch* csb, const jrd_nod* node, SSHORT stream,
case nod_rec_version:
case nod_dbkey:
n = (USHORT)(IPTR) node->nod_arg[0];
if (allowOnlyCurrentStream) {
if (n != stream &&
!(csb->csb_rpt[n].csb_flags & csb_sub_stream))
{
if (allowOnlyCurrentStream)
{
if (n != stream && !(csb->csb_rpt[n].csb_flags & csb_sub_stream))
return false;
}
}
else {
if (n == stream) {
else
{
if (n == stream)
return false;
}
}
return csb->csb_rpt[n].csb_flags & csb_active;
case nod_derived_expr:
{
UCHAR streamCount = (UCHAR)(IPTR) node->nod_arg[e_derived_expr_stream_count];
USHORT* streamList = (USHORT*) node->nod_arg[e_derived_expr_stream_list];
bool active = true;
for (UCHAR i = 0; i < streamCount; ++i)
{
n = streamList[i];
if (allowOnlyCurrentStream)
{
if (n != stream && !(csb->csb_rpt[n].csb_flags & csb_sub_stream))
return false;
}
else
{
if (n == stream)
return false;
}
active = active && (csb->csb_rpt[n].csb_flags & csb_active);
}
return active;
}
case nod_min:
case nod_max:
case nod_average:
@ -1068,11 +1090,26 @@ void OptimizerRetrieval::findDependentFromStreams(jrd_nod* node,
case nod_dbkey:
{
int keyStream = (USHORT)(IPTR) node->nod_arg[0];
if (keyStream != stream &&
(csb->csb_rpt[keyStream].csb_flags & csb_active))
if (keyStream != stream && (csb->csb_rpt[keyStream].csb_flags & csb_active))
{
if (!streamList->exist(keyStream)) {
if (!streamList->exist(keyStream))
streamList->add(keyStream);
}
return;
}
case nod_derived_expr:
{
UCHAR derivedStreamCount = (UCHAR)(IPTR) node->nod_arg[e_derived_expr_stream_count];
USHORT* derivedStreamList = (USHORT*) node->nod_arg[e_derived_expr_stream_list];
for (UCHAR i = 0; i < derivedStreamCount; ++i)
{
int keyStream = derivedStreamList[i];
if (keyStream != stream && (csb->csb_rpt[keyStream].csb_flags & csb_active))
{
if (!streamList->exist(keyStream))
streamList->add(keyStream);
}
}
return;

View File

@ -226,6 +226,7 @@ static const struct
{"similar", similar},
{"exec_stmt", exec_stmt},
{"stmt_expr", two},
{"derived_expr", derived_expr},
{0, 0}
};

View File

@ -373,5 +373,6 @@
#define blr_exec_stmt_out_params (unsigned char) 13 // output parameters
#define blr_stmt_expr (unsigned char) 190
#define blr_derived_expr (unsigned char) 191
#endif // JRD_BLR_H

View File

@ -1929,6 +1929,10 @@ void CMP_get_desc(thread_db* tdbb, CompilerScratch* csb, jrd_nod* node, DSC * de
CMP_get_desc(tdbb, csb, node->nod_arg[e_stmt_expr_expr], desc);
return;
case nod_derived_expr:
CMP_get_desc(tdbb, csb, node->nod_arg[e_derived_expr_expr], desc);
return;
default:
fb_assert(false);
break;
@ -2591,7 +2595,7 @@ static jrd_nod* catenate_nodes(thread_db* tdbb, NodeStack& stack)
static jrd_nod* copy(thread_db* tdbb,
CompilerScratch* csb,
jrd_nod* input,
UCHAR * remap,
UCHAR* remap,
USHORT field_id,
jrd_nod* message,
bool remap_fld)
@ -2727,6 +2731,32 @@ static jrd_nod* copy(thread_db* tdbb,
return temp_node;
}
case nod_derived_expr:
{
node = PAR_make_node(tdbb, e_derived_expr_length);
node->nod_count = e_derived_expr_count;
node->nod_type = input->nod_type;
node->nod_arg[e_derived_expr_expr] = copy(tdbb, csb, input->nod_arg[e_derived_expr_expr],
remap, field_id, message, remap_fld);
if (remap)
{
UCHAR streamCount = (UCHAR)(IPTR) input->nod_arg[e_derived_expr_stream_count];
USHORT* oldStreamList = (USHORT*) input->nod_arg[e_derived_expr_stream_list];
USHORT* newStreamList = FB_NEW(*tdbb->getDefaultPool()) USHORT[streamCount];
for (UCHAR i = 0; i < streamCount; ++i)
newStreamList[i] = remap[oldStreamList[i]];
node->nod_arg[e_derived_expr_stream_list] = (jrd_nod*) newStreamList;
}
else
node->nod_arg[e_derived_expr_stream_list] = input->nod_arg[e_derived_expr_stream_list];
node->nod_arg[e_derived_expr_stream_count] = input->nod_arg[e_derived_expr_stream_count];
return node;
}
case nod_function:
node = PAR_make_node(tdbb, e_fun_length);
node->nod_count = input->nod_count;

View File

@ -916,6 +916,21 @@ dsc* EVL_expr(thread_db* tdbb, jrd_nod* const node)
return &impure->vlu_desc;
}
case nod_derived_expr:
{
UCHAR streamCount = (UCHAR)(IPTR) node->nod_arg[e_derived_expr_stream_count];
USHORT* streamList = (USHORT*) node->nod_arg[e_derived_expr_stream_list];
for (UCHAR i = 0; i < streamCount; ++i)
{
if (request->req_rpb[streamList[i]].rpb_number.isValid())
return EVL_expr(tdbb, node->nod_arg[e_derived_expr_expr]);
}
request->req_flags |= req_null;
return NULL;
}
case nod_function:
FUN_evaluate(tdbb, reinterpret_cast<UserFunction*>(node->nod_arg[e_fun_function]),
node->nod_arg[e_fun_args], impure);

View File

@ -561,6 +561,13 @@ const int e_stmt_expr_stmt = 0;
const int e_stmt_expr_expr = 1;
const int e_stmt_expr_length = 2;
// nod_derived_expr
const int e_derived_expr_expr = 0;
const int e_derived_expr_stream_count = 1;
const int e_derived_expr_stream_list = 2;
const int e_derived_expr_count = 1;
const int e_derived_expr_length = 3;
// Request resources
struct Resource

View File

@ -278,7 +278,8 @@ const int op_relation = 20;
const int op_exec_into = 21;
const int op_cursor_stmt = 22;
const int op_byte_opt_verb = 23;
const int op_exec_stmt = 24;
const int op_exec_stmt = 24;
const int op_derived_expr = 25;
static const UCHAR
/* generic print formats */
@ -337,7 +338,8 @@ static const UCHAR
trim[] = { op_byte, op_byte_opt_verb, op_verb, 0},
modify2[] = { op_byte, op_byte, op_line, op_verb, op_verb, 0},
similar[] = { op_line, op_verb, op_verb, op_indent, op_byte_opt_verb, 0},
exec_stmt[] = { op_exec_stmt, 0};
exec_stmt[] = { op_exec_stmt, 0},
derived_expr[] = { op_derived_expr, 0};
#include "../jrd/blp.h"
@ -3394,6 +3396,14 @@ static void blr_print_verb(gds_ctl* control, SSHORT level)
break;
}
case op_derived_expr:
n = blr_print_byte(control);
for (UCHAR i = 0; i < (UCHAR) n; ++i)
blr_print_byte(control);
offset = blr_print_line(control, (SSHORT) offset);
blr_print_verb(control, level);
break;
case op_cursor_stmt: {
blr_operator = blr_print_byte(control);
blr_print_word(control);

View File

@ -200,4 +200,4 @@ NODE(nod_asn_list, asn_list, "")
NODE(nod_sys_function, sys_function, "")
NODE(nod_class_node_jrd, class_node_jrd, "class_node_jrd")
NODE(nod_stmt_expr, stmt_expr, "stmt_expr")
NODE(nod_derived_expr, derived_expr, "derived_expr")

View File

@ -3096,6 +3096,20 @@ jrd_nod* PAR_parse_node(thread_db* tdbb, CompilerScratch* csb, USHORT expected,
set_type = false; // to not change nod->nod_type to nod_field
break;
case blr_derived_expr:
{
UCHAR streamCount = BLR_BYTE;
USHORT* streamList = FB_NEW(*tdbb->getDefaultPool()) USHORT[streamCount];
for (UCHAR i = 0; i < streamCount; ++i)
streamList[i] = BLR_BYTE;
node->nod_arg[e_derived_expr_stream_list] = (jrd_nod*) streamList;
node->nod_arg[e_derived_expr_stream_count] = (jrd_nod*)(IPTR) streamCount;
node->nod_arg[e_derived_expr_expr] = PAR_parse_node(tdbb, csb, sub_type);
node->nod_count = e_derived_expr_count;
break;
}
case blr_gen_id:
case blr_set_generator:
{

View File

@ -223,6 +223,7 @@ static const VERB verbs[] =
PAIR(nod_class_node_jrd, blr_auto_trans, 1, 0, STATEMENT, STATEMENT),
PAIR(nod_similar, blr_similar, 3, 3, TYPE_BOOL, VALUE),
PAIR(nod_stmt_expr, blr_stmt_expr, e_stmt_expr_length, 2, VALUE, OTHER),
PAIR(nod_derived_expr, blr_derived_expr, e_derived_expr_length, e_derived_expr_count, VALUE, VALUE),
{0, NULL, NULL, NULL, NULL, NULL, NULL}
};