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

Fix nodDesc of NullNode being changed after its initial construction.

This commit is contained in:
Adriano dos Santos Fernandes 2020-06-28 21:07:58 -03:00 committed by Adriano dos Santos Fernandes
parent 6ca9b607ba
commit a329a92786
7 changed files with 203 additions and 104 deletions

View File

@ -394,7 +394,7 @@ string ValueExprNode::internalPrint(NodePrinter& printer) const
ExprNode::internalPrint(printer);
NODE_PRINT(printer, nodScale);
NODE_PRINT(printer, nodDesc);
NODE_PRINT(printer, getDsqlDesc());
return "ValueExprNode";
}
@ -3390,9 +3390,9 @@ ValueExprNode* CastNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
node->setParameterType(dsqlScratch, NULL, false);
DsqlDescMaker::fromField(&node->castDesc, node->dsqlField);
DsqlDescMaker::fromNode(dsqlScratch, &node->source->nodDesc, node->source);
DsqlDescMaker::fromNode(dsqlScratch, node->source);
node->castDesc.dsc_flags = node->source->nodDesc.dsc_flags & DSC_nullable;
node->castDesc.dsc_flags = node->source->getDsqlDesc().dsc_flags & DSC_nullable;
return node;
}
@ -3628,7 +3628,7 @@ ValueExprNode* CoalesceNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
CoalesceNode* node = FB_NEW_POOL(dsqlScratch->getPool()) CoalesceNode(
dsqlScratch->getPool(), doDsqlPass(dsqlScratch, args));
node->make(dsqlScratch, &node->nodDesc); // Set descriptor for output node.
node->makeDsqlDesc(dsqlScratch); // Set descriptor for output node.
for (auto& item : node->args->items)
PASS1_set_parameter_type(dsqlScratch, item, node, false);
@ -3753,12 +3753,12 @@ ValueExprNode* CollateNode::pass1Collate(DsqlCompilerScratch* dsqlScratch, Value
dsql_fld* field = FB_NEW_POOL(pool) dsql_fld(pool);
CastNode* castNode = FB_NEW_POOL(pool) CastNode(pool, input, field);
DsqlDescMaker::fromNode(dsqlScratch, &input->nodDesc, input);
DsqlDescMaker::fromNode(dsqlScratch, input);
if (input->nodDesc.dsc_dtype <= dtype_any_text ||
(input->nodDesc.dsc_dtype == dtype_blob && input->nodDesc.dsc_sub_type == isc_blob_text))
if (input->getDsqlDesc().dsc_dtype <= dtype_any_text ||
(input->getDsqlDesc().dsc_dtype == dtype_blob && input->getDsqlDesc().dsc_sub_type == isc_blob_text))
{
assignFieldDtypeFromDsc(field, &input->nodDesc);
assignFieldDtypeFromDsc(field, &input->getDsqlDesc());
field->charLength = 0;
}
else
@ -4605,10 +4605,10 @@ ValueExprNode* DecodeNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
doDsqlPass(dsqlScratch, test), doDsqlPass(dsqlScratch, conditions), doDsqlPass(dsqlScratch, values));
node->label = label;
node->make(dsqlScratch, &node->nodDesc); // Set descriptor for output node.
node->makeDsqlDesc(dsqlScratch); // Set descriptor for output node.
node->setParameterType(dsqlScratch,
[&] (dsc* desc) { *desc = node->nodDesc; },
[&] (dsc* desc) { *desc = node->getDsqlDesc(); },
false);
// Workaround for DECODE/CASE supporting only 255 items - see CORE-5366.
@ -5270,7 +5270,7 @@ ValueExprNode* ExtractNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
// sure the requested type of information can be extracted.
ValueExprNode* sub1 = doDsqlPass(dsqlScratch, arg);
DsqlDescMaker::fromNode(dsqlScratch, &sub1->nodDesc, sub1);
DsqlDescMaker::fromNode(dsqlScratch, sub1);
switch (blrSubOp)
{
@ -5281,8 +5281,8 @@ ValueExprNode* ExtractNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
case blr_extract_yearday:
case blr_extract_week:
if (!nodeIs<NullNode>(sub1) &&
sub1->nodDesc.dsc_dtype != dtype_sql_date &&
!sub1->nodDesc.isTimeStamp())
sub1->getDsqlDesc().dsc_dtype != dtype_sql_date &&
!sub1->getDsqlDesc().isTimeStamp())
{
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-105) <<
Arg::Gds(isc_extract_input_mismatch));
@ -5294,8 +5294,8 @@ ValueExprNode* ExtractNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
case blr_extract_second:
case blr_extract_millisecond:
if (!nodeIs<NullNode>(sub1) &&
!sub1->nodDesc.isTime() &&
!sub1->nodDesc.isTimeStamp())
!sub1->getDsqlDesc().isTime() &&
!sub1->getDsqlDesc().isTimeStamp())
{
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-105) <<
Arg::Gds(isc_extract_input_mismatch));
@ -5305,8 +5305,8 @@ ValueExprNode* ExtractNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
case blr_extract_timezone_hour:
case blr_extract_timezone_minute:
if (!nodeIs<NullNode>(sub1) &&
!sub1->nodDesc.isTime() &&
!sub1->nodDesc.isTimeStamp())
!sub1->getDsqlDesc().isTime() &&
!sub1->getDsqlDesc().isTimeStamp())
{
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-105) <<
Arg::Gds(isc_extract_input_mismatch));
@ -6408,8 +6408,8 @@ void FieldNode::genBlr(DsqlCompilerScratch* dsqlScratch)
void FieldNode::make(DsqlCompilerScratch* /*dsqlScratch*/, dsc* desc)
{
if (nodDesc.dsc_dtype)
*desc = nodDesc;
if (getDsqlDesc().dsc_dtype)
*desc = getDsqlDesc();
else
{
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-203) <<
@ -8216,7 +8216,7 @@ ValueExprNode* DsqlAliasNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
{
DsqlAliasNode* node = FB_NEW_POOL(dsqlScratch->getPool()) DsqlAliasNode(dsqlScratch->getPool(), name,
doDsqlPass(dsqlScratch, value));
DsqlDescMaker::fromNode(dsqlScratch, &node->value->nodDesc, node->value);
DsqlDescMaker::fromNode(dsqlScratch, node->value);
return node;
}
@ -8243,7 +8243,9 @@ void DsqlAliasNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc)
DsqlMapNode::DsqlMapNode(MemoryPool& pool, dsql_ctx* aContext, dsql_map* aMap)
: TypedNode<ValueExprNode, ExprNode::TYPE_MAP>(pool),
context(aContext),
map(aMap)
map(aMap),
setNullable(false),
clearNull(false)
{
}
@ -8253,6 +8255,8 @@ string DsqlMapNode::internalPrint(NodePrinter& printer) const
NODE_PRINT(printer, context);
NODE_PRINT(printer, map);
NODE_PRINT(printer, setNullable);
NODE_PRINT(printer, clearNull);
return "DsqlMapNode";
}
@ -8397,8 +8401,11 @@ void DsqlMapNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc)
DsqlDescMaker::fromNode(dsqlScratch, desc, map->map_node);
// ASF: We should mark nod_agg_count as nullable when it's in an outer join - CORE-2660.
if (context->ctx_flags & CTX_outer_join)
if (setNullable || (context->ctx_flags & CTX_outer_join))
desc->setNullable(true);
if (clearNull)
desc->clearNull();
}
bool DsqlMapNode::dsqlMatch(DsqlCompilerScratch* dsqlScratch, const ExprNode* other, bool ignoreMapCast) const
@ -12079,8 +12086,8 @@ void SysFuncCallNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc)
for (auto& arg : args->items)
{
DsqlDescMaker::fromNode(dsqlScratch, &arg->nodDesc, arg);
argsArray.add(&arg->nodDesc);
DsqlDescMaker::fromNode(dsqlScratch, arg);
argsArray.add(&arg->getDsqlDesc());
}
DSqlDataTypeUtil dataTypeUtil(dsqlScratch);
@ -12207,12 +12214,24 @@ ValueExprNode* SysFuncCallNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
if (node->function->setParamsFunc)
{
Array<dsc*> argsArray;
Array<dsc> tempDescs(node->args->items.getCount());
tempDescs.resize(node->args->items.getCount());
Array<dsc*> argsArray(node->args->items.getCount());
for (auto& item : node->args->items)
{
DsqlDescMaker::fromNode(dsqlScratch, &item->nodDesc, item);
argsArray.add(&item->nodDesc);
DsqlDescMaker::fromNode(dsqlScratch, item);
auto itemDesc = item->dsqlSetableDesc();
if (!itemDesc)
{
tempDescs.push(item->getDsqlDesc());
itemDesc = &tempDescs.back();
}
argsArray.add(itemDesc);
}
DSqlDataTypeUtil dataTypeUtil(dsqlScratch);
@ -12222,7 +12241,7 @@ ValueExprNode* SysFuncCallNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
for (auto& item : node->args->items)
{
PASS1_set_parameter_type(dsqlScratch, item,
[&] (dsc* desc) { *desc = item->nodDesc; },
[&] (dsc* desc) { *desc = item->getDsqlDesc(); },
false);
}
}
@ -13310,11 +13329,11 @@ void ValueIfNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc)
{
Array<const dsc*> args;
DsqlDescMaker::fromNode(dsqlScratch, &trueValue->nodDesc, trueValue);
args.add(&trueValue->nodDesc);
DsqlDescMaker::fromNode(dsqlScratch, trueValue);
args.add(&trueValue->getDsqlDesc());
DsqlDescMaker::fromNode(dsqlScratch, &falseValue->nodDesc, falseValue);
args.add(&falseValue->nodDesc);
DsqlDescMaker::fromNode(dsqlScratch, falseValue);
args.add(&falseValue->getDsqlDesc());
DSqlDataTypeUtil(dsqlScratch).makeFromList(desc, "CASE", args.getCount(), args.begin());
}

View File

@ -258,6 +258,11 @@ public:
virtual void genBlr(DsqlCompilerScratch* dsqlScratch);
virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc);
void setDsqlDesc(const dsc& desc)
{
dsqlDesc = desc;
}
virtual void getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc);
virtual ValueExprNode* copy(thread_db* tdbb, NodeCopier& copier) const;
virtual bool dsqlMatch(DsqlCompilerScratch* dsqlScratch, const ExprNode* other, bool ignoreMapCast) const;
@ -765,6 +770,11 @@ public:
virtual bool dsqlMatch(DsqlCompilerScratch* dsqlScratch, const ExprNode* other, bool ignoreMapCast) const;
virtual bool sameAs(CompilerScratch* csb, const ExprNode* other, bool ignoreStreams) const;
void setDsqlDesc(const dsc& desc)
{
dsqlDesc = desc;
}
virtual bool possiblyUnknown(OptimizerBlk* /*opt*/)
{
return false;
@ -964,6 +974,11 @@ public:
virtual void genBlr(DsqlCompilerScratch* dsqlScratch);
virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc);
void setDsqlDesc(const dsc& desc)
{
dsqlDesc = desc;
}
virtual void getDesc(thread_db* /*tdbb*/, CompilerScratch* /*csb*/, dsc* /*desc*/)
{
fb_assert(false);
@ -1008,6 +1023,11 @@ public:
virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc);
virtual bool dsqlMatch(DsqlCompilerScratch* dsqlScratch, const ExprNode* other, bool ignoreMapCast) const;
void setDsqlDesc(const dsc& desc)
{
dsqlDesc = desc;
}
virtual void getDesc(thread_db* /*tdbb*/, CompilerScratch* /*csb*/, dsc* /*desc*/)
{
fb_assert(false);
@ -1028,6 +1048,8 @@ public:
public:
dsql_ctx* context;
dsql_map* map;
bool setNullable;
bool clearNull;
};
@ -1059,6 +1081,11 @@ public:
virtual void genBlr(DsqlCompilerScratch* dsqlScratch);
virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc);
void setDsqlDesc(const dsc& desc)
{
dsqlDesc = desc;
}
virtual void getDesc(thread_db* /*tdbb*/, CompilerScratch* /*csb*/, dsc* /*desc*/)
{
fb_assert(false);
@ -1177,6 +1204,7 @@ private:
explicit NullNode(MemoryPool& pool)
: TypedNode<ValueExprNode, ExprNode::TYPE_NULL>(pool)
{
dsqlDesc.makeNullString();
}
public:
@ -1187,6 +1215,11 @@ public:
static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR blrOp);
virtual bool isSharedNode()
{
return true;
}
virtual Firebird::string internalPrint(NodePrinter& printer) const;
virtual void setParameterName(dsql_par* parameter) const;
virtual void genBlr(DsqlCompilerScratch* dsqlScratch);
@ -2141,6 +2174,11 @@ public:
virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc);
virtual bool dsqlMatch(DsqlCompilerScratch* dsqlScratch, const ExprNode* other, bool ignoreMapCast) const;
void setDsqlDesc(const dsc& desc)
{
dsqlDesc = desc;
}
virtual void getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc);
virtual ValueExprNode* copy(thread_db* tdbb, NodeCopier& copier) const;
virtual ValueExprNode* pass1(thread_db* tdbb, CompilerScratch* csb);

View File

@ -747,7 +747,7 @@ public:
: ExprNode(aType, pool),
nodScale(0)
{
nodDesc.clear();
dsqlDesc.clear();
}
public:
@ -758,6 +758,30 @@ public:
return KIND_VALUE;
}
const dsc& getDsqlDesc() const
{
return dsqlDesc;
}
void makeDsqlDesc(DsqlCompilerScratch* dsqlScratch)
{
auto settableDesc = dsqlSetableDesc();
if (settableDesc)
make(dsqlScratch, settableDesc);
}
dsc* dsqlSetableDesc()
{
return isSharedNode() ? nullptr : &dsqlDesc;
}
// Must be overriden returning true in shared nodes.
virtual bool isSharedNode()
{
return false;
}
virtual ValueExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch)
{
ExprNode::dsqlPass(dsqlScratch);
@ -799,7 +823,9 @@ public:
public:
SCHAR nodScale;
dsc nodDesc;
protected:
dsc dsqlDesc;
};
template <typename T, typename ValueExprNode::Type typeConst>

View File

@ -9388,7 +9388,7 @@ static VariableNode* dsqlPassHiddenVariable(DsqlCompilerScratch* dsqlScratch, Va
0, 0, dsqlScratch->hiddenVarsNumber++);
DsqlDescMaker::fromNode(dsqlScratch, &varNode->dsqlVar->desc, expr);
varNode->nodDesc = varNode->dsqlVar->desc;
varNode->setDsqlDesc(varNode->dsqlVar->desc);
return varNode;
}
@ -9592,7 +9592,7 @@ static void dsqlSetParameterName(DsqlCompilerScratch* dsqlScratch, ExprNode* exp
const FieldNode* fieldNode = nodeAs<FieldNode>(fld_node);
fb_assert(fieldNode); // Could it be something else ???
if (fieldNode->nodDesc.dsc_dtype != dtype_array)
if (fieldNode->getDsqlDesc().dsc_dtype != dtype_array)
return;
switch (exprNode->getType())

View File

@ -90,8 +90,8 @@ void DsqlDescMaker::fromList(DsqlCompilerScratch* scratch, dsc* desc,
while (p != end)
{
DsqlDescMaker::fromNode(scratch, &(*p)->nodDesc, *p);
args.add(&(*p)->nodDesc);
DsqlDescMaker::fromNode(scratch, *p);
args.add(&(*p)->getDsqlDesc());
++p;
}
@ -106,14 +106,23 @@ void DsqlDescMaker::fromNode(DsqlCompilerScratch* scratch, dsc* desc,
DEV_BLKCHK(node, dsql_type_nod);
// If we already know the datatype, don't worry about anything.
if (node->nodDesc.dsc_dtype)
*desc = node->nodDesc;
if (node->getDsqlDesc().dsc_dtype)
*desc = node->getDsqlDesc();
else
node->make(scratch, desc);
desc->dsc_flags |= nullable ? DSC_nullable : 0;
}
void DsqlDescMaker::fromNode(DsqlCompilerScratch* scratch, ValueExprNode* node)
{
DEV_BLKCHK(node, dsql_type_nod);
// If we already know the datatype, don't worry about anything.
if (!node->getDsqlDesc().dsc_dtype)
node->makeDsqlDesc(scratch);
}
void DsqlDescMaker::composeDesc(dsc* desc,
USHORT dtype,
SSHORT scale,
@ -374,19 +383,22 @@ FieldNode* MAKE_field(dsql_ctx* context, dsql_fld* field, ValueListNode* indices
FieldNode* const node = FB_NEW_POOL(*tdbb->getDefaultPool()) FieldNode(
*tdbb->getDefaultPool(), context, field, indices);
dsc desc;
if (field->dimensions)
{
if (indices)
{
DsqlDescMaker::fromElement(&node->nodDesc, field);
}
DsqlDescMaker::fromElement(&desc, field);
else
{
node->nodDesc.dsc_dtype = dtype_array;
node->nodDesc.dsc_length = sizeof(ISC_QUAD);
node->nodDesc.dsc_scale = static_cast<SCHAR>(field->scale);
node->nodDesc.dsc_sub_type = field->subType;
desc = node->getDsqlDesc();
desc.dsc_dtype = dtype_array;
desc.dsc_length = sizeof(ISC_QUAD);
desc.dsc_scale = static_cast<SCHAR>(field->scale);
desc.dsc_sub_type = field->subType;
}
node->setDsqlDesc(desc);
}
else
{
@ -396,11 +408,16 @@ FieldNode* MAKE_field(dsql_ctx* context, dsql_fld* field, ValueListNode* indices
Arg::Gds(isc_dsql_only_can_subscript_array) << Arg::Str(field->fld_name));
}
DsqlDescMaker::fromField(&node->nodDesc, field);
DsqlDescMaker::fromField(&desc, field);
node->setDsqlDesc(desc);
}
if ((field->flags & FLD_nullable) || (context->ctx_flags & CTX_outer_join))
node->nodDesc.dsc_flags |= DSC_nullable;
{
desc = node->getDsqlDesc();
desc.dsc_flags |= DSC_nullable;
node->setDsqlDesc(desc);
}
return node;
}

View File

@ -64,6 +64,7 @@ namespace Jrd {
ValueListNode*, const char*, bool = false);
static void fromNode(DsqlCompilerScratch*, dsc*,
ValueExprNode*, bool = false);
static void fromNode(DsqlCompilerScratch*, ValueExprNode*);
private:
static void composeDesc(dsc* desc,

View File

@ -1066,8 +1066,7 @@ RseNode* PASS1_derived_table(DsqlCompilerScratch* dsqlScratch, SelectExprNode* i
// the worse thing is that a UNION currently can't be used in
// deciding the JOIN order.
bool foundSubSelect = false;
RseNode* queryNode = nodeAs<RseNode>(query);
if (queryNode)
if (auto queryNode = nodeAs<RseNode>(query))
foundSubSelect = SubSelectFinder::find(dsqlScratch->getPool(), queryNode->dsqlSelectList);
if (foundSubSelect)
@ -1146,13 +1145,13 @@ RseNode* PASS1_derived_table(DsqlCompilerScratch* dsqlScratch, SelectExprNode* i
for (FB_SIZE_T count = 0; count < input->columns->getCount(); ++count)
{
ValueExprNode* select_item = rse->dsqlSelectList->items[count];
DsqlDescMaker::fromNode(dsqlScratch, &select_item->nodDesc, select_item);
DsqlDescMaker::fromNode(dsqlScratch, select_item);
// Make new derived field node.
DerivedFieldNode* derivedField = FB_NEW_POOL(pool) DerivedFieldNode(pool,
(*input->columns)[count], dsqlScratch->scopeLevel, select_item);
derivedField->nodDesc = select_item->nodDesc;
derivedField->setDsqlDesc(select_item->getDsqlDesc());
rse->dsqlSelectList->items[count] = derivedField;
}
}
@ -1168,7 +1167,7 @@ RseNode* PASS1_derived_table(DsqlCompilerScratch* dsqlScratch, SelectExprNode* i
// Auto-create dummy column name for pass1_any()
if (ignoreColumnChecks && !nodeIs<DerivedFieldNode>(select_item))
{
DsqlDescMaker::fromNode(dsqlScratch, &select_item->nodDesc, select_item);
DsqlDescMaker::fromNode(dsqlScratch, select_item);
// Construct dummy fieldname
char fieldname[25];
@ -1178,7 +1177,7 @@ RseNode* PASS1_derived_table(DsqlCompilerScratch* dsqlScratch, SelectExprNode* i
DerivedFieldNode* derivedField = FB_NEW_POOL(pool) DerivedFieldNode(pool,
fieldname, dsqlScratch->scopeLevel, select_item);
derivedField->nodDesc = select_item->nodDesc;
derivedField->setDsqlDesc(select_item->getDsqlDesc());
select_item = derivedField;
}
@ -1655,7 +1654,7 @@ static ValueExprNode* pass1_make_derived_field(thread_db* tdbb, DsqlCompilerScra
// Create a derived field and ignore alias node.
DerivedFieldNode* newField = FB_NEW_POOL(pool) DerivedFieldNode(pool,
aliasNode->name, dsqlScratch->scopeLevel, aliasNode->value);
newField->nodDesc = aliasNode->value->nodDesc;
newField->setDsqlDesc(aliasNode->value->getDsqlDesc());
return newField;
}
else if ((subQueryNode = nodeAs<SubQueryNode>(select_item)))
@ -1680,7 +1679,7 @@ static ValueExprNode* pass1_make_derived_field(thread_db* tdbb, DsqlCompilerScra
{
derivedField->value = select_item;
derivedField->scope = dsqlScratch->scopeLevel;
derived_field->nodDesc = select_item->nodDesc;
derivedField->setDsqlDesc(select_item->getDsqlDesc());
return derived_field;
}
}
@ -1690,7 +1689,7 @@ static ValueExprNode* pass1_make_derived_field(thread_db* tdbb, DsqlCompilerScra
DerivedFieldNode* newField = FB_NEW_POOL(pool) DerivedFieldNode(pool,
fieldNode->dsqlField->fld_name, dsqlScratch->scopeLevel, select_item);
newField->nodDesc = fieldNode->nodDesc;
newField->setDsqlDesc(fieldNode->getDsqlDesc());
return newField;
}
else if ((derivedField = nodeAs<DerivedFieldNode>(select_item)))
@ -1699,7 +1698,7 @@ static ValueExprNode* pass1_make_derived_field(thread_db* tdbb, DsqlCompilerScra
DerivedFieldNode* newField = FB_NEW_POOL(pool) DerivedFieldNode(pool,
derivedField->name, dsqlScratch->scopeLevel, select_item);
newField->nodDesc = select_item->nodDesc;
newField->setDsqlDesc(select_item->getDsqlDesc());
return newField;
}
@ -1797,10 +1796,7 @@ static RseNode* pass1_rse_impl(DsqlCompilerScratch* dsqlScratch, RecordSourceNod
thread_db* tdbb = JRD_get_thread_data();
MemoryPool& pool = *tdbb->getDefaultPool();
SelectExprNode* selNode = nodeAs<SelectExprNode>(input);
UnionSourceNode* unionNode = nodeAs<UnionSourceNode>(input);
if (selNode)
if (auto selNode = nodeAs<SelectExprNode>(input))
{
WithClause* withClause = selNode->withClause;
try
@ -1826,7 +1822,7 @@ static RseNode* pass1_rse_impl(DsqlCompilerScratch* dsqlScratch, RecordSourceNod
throw;
}
}
else if (unionNode)
else if (auto unionNode = nodeAs<UnionSourceNode>(input))
{
fb_assert(unionNode->dsqlClauses->items.hasData());
return pass1_union(dsqlScratch, unionNode, order, rows, updateLock, flags);
@ -2532,31 +2528,21 @@ static RseNode* pass1_union(DsqlCompilerScratch* dsqlScratch, UnionSourceNode* i
ValueListNode* tmp_list = FB_NEW_POOL(pool) ValueListNode(
pool, unionSource->dsqlClauses->items.getCount());
Array<dsc> descs(unionSource->dsqlClauses->items.getCount());
for (FB_SIZE_T j = 0; j < items->items.getCount(); ++j)
{
for (FB_SIZE_T i = 0; i < unionSource->dsqlClauses->items.getCount(); ++i)
{
ValueListNode* nod1 = nodeAs<RseNode>(unionSource->dsqlClauses->items[i])->dsqlSelectList;
DsqlDescMaker::fromNode(dsqlScratch, &nod1->items[j]->nodDesc, nod1->items[j]);
DsqlDescMaker::fromNode(dsqlScratch, nod1->items[j]);
tmp_list->items[i] = nod1->items[j];
// We look only at the items->nod_arg[] when creating the
// output descriptors. Make sure that the sub-rses
// descriptor flags are copied onto items->nod_arg[]->nodDesc.
// Bug 65584.
// -Sudesh 07/28/1999.
if (i > 0)
{
if (nod1->items[j]->nodDesc.dsc_flags & DSC_nullable)
items->items[j]->nodDesc.dsc_flags |= DSC_nullable;
}
}
dsc desc;
DsqlDescMaker::fromList(dsqlScratch, &desc, tmp_list, "UNION");
// Only mark upper node as a NULL node when all sub-nodes are NULL
items->items[j]->nodDesc.dsc_flags &= ~DSC_null;
items->items[j]->nodDesc.dsc_flags |= (desc.dsc_flags & DSC_null);
descs.push(desc);
pass1_union_auto_cast(dsqlScratch, unionSource->dsqlClauses, desc, j);
}
@ -2583,7 +2569,18 @@ static RseNode* pass1_union(DsqlCompilerScratch* dsqlScratch, UnionSourceNode* i
map->map_window = NULL;
union_context->ctx_map = map;
*ptr = FB_NEW_POOL(pool) DsqlMapNode(pool, union_context, map);
auto mapNode = FB_NEW_POOL(pool) DsqlMapNode(pool, union_context, map);
if (descs[map->map_position].dsc_flags & DSC_nullable)
mapNode->setNullable = true;
if ((items->items[map->map_position]->getDsqlDesc().dsc_flags & DSC_null) &&
!(descs[map->map_position].dsc_flags & DSC_null))
{
mapNode->clearNull = true;
}
*ptr = mapNode;
}
unionRse->dsqlSelectList = union_items;
@ -2701,13 +2698,15 @@ static void pass1_union_auto_cast(DsqlCompilerScratch* dsqlScratch, ExprNode* in
(unionNode = nodeAs<UnionSourceNode>(rseNode->dsqlStreams->items[0])) &&
unionNode->dsqlParentRse == rseNode)
{
// We're now in a UNION under a UNION so don't change the existing mappings.
// We're now in a UNION under a UNION (for example A UNION ALL B UNION C) so don't
// change the existing mappings.
// Only replace the node where the map points to, because they could be changed.
ValueListNode* sub_rse_items =
nodeAs<RseNode>(unionNode->dsqlClauses->items[0])->dsqlSelectList;
dsql_map* map = nodeAs<DsqlMapNode>(rseNode->dsqlSelectList->items[position])->map;
auto mapNode = nodeAs<DsqlMapNode>(rseNode->dsqlSelectList->items[position]);
dsql_map* map = mapNode->map;
map->map_node = sub_rse_items->items[position];
rseNode->dsqlSelectList->items[position]->nodDesc = desc;
mapNode->setDsqlDesc(desc);
}
else
{
@ -2723,12 +2722,12 @@ static void pass1_union_auto_cast(DsqlCompilerScratch* dsqlScratch, ExprNode* in
else
{
ValueExprNode* select_item = list->items[position];
DsqlDescMaker::fromNode(dsqlScratch, &select_item->nodDesc, select_item);
DsqlDescMaker::fromNode(dsqlScratch, select_item);
if (select_item->nodDesc.dsc_dtype != desc.dsc_dtype ||
select_item->nodDesc.dsc_length != desc.dsc_length ||
select_item->nodDesc.dsc_scale != desc.dsc_scale ||
select_item->nodDesc.dsc_sub_type != desc.dsc_sub_type)
if (select_item->getDsqlDesc().dsc_dtype != desc.dsc_dtype ||
select_item->getDsqlDesc().dsc_length != desc.dsc_length ||
select_item->getDsqlDesc().dsc_scale != desc.dsc_scale ||
select_item->getDsqlDesc().dsc_sub_type != desc.dsc_sub_type)
{
// Because this select item has a different descriptor then
// our finally descriptor CAST it.
@ -2750,7 +2749,7 @@ static void pass1_union_auto_cast(DsqlCompilerScratch* dsqlScratch, ExprNode* in
else
castNode = nodeAs<CastNode>(select_item);
if (castNode && !DSC_EQUIV(&castNode->nodDesc, &desc, false))
if (castNode && !DSC_EQUIV(&castNode->getDsqlDesc(), &desc, false))
castNode = NULL;
if (!castNode)
@ -2782,9 +2781,7 @@ static void pass1_union_auto_cast(DsqlCompilerScratch* dsqlScratch, ExprNode* in
name_node = mapNode->map->map_node;
}
const FieldNode* fieldNode;
if ((fieldNode = nodeAs<FieldNode>(name_node)))
if (auto fieldNode = nodeAs<FieldNode>(name_node))
{
// Create new node for alias and copy fieldname.
newAliasNode = FB_NEW_POOL(*tdbb->getDefaultPool()) DsqlAliasNode(
@ -2823,31 +2820,32 @@ static void pass1_union_auto_cast(DsqlCompilerScratch* dsqlScratch, ExprNode* in
// Finally copy the descriptors to the root nodes and swap
// the necessary nodes.
castNode->nodDesc = desc;
if (select_item->nodDesc.dsc_flags & DSC_nullable)
castNode->nodDesc.dsc_flags |= DSC_nullable;
castNode->setDsqlDesc(desc);
if ((aliasNode = nodeAs<DsqlAliasNode>(select_item)))
{
aliasNode->value = castNode;
aliasNode->value->nodDesc = desc;
select_item->nodDesc = desc;
aliasNode->setDsqlDesc(desc);
}
else if ((derivedField = nodeAs<DerivedFieldNode>(select_item)))
{
derivedField->value = castNode;
derivedField->value->nodDesc = desc;
select_item->nodDesc = desc;
derivedField->setDsqlDesc(desc);
}
else
{
if (select_item->getDsqlDesc().dsc_flags & DSC_nullable)
{
dsc castDesc = castNode->getDsqlDesc();
castDesc.dsc_flags |= DSC_nullable;
castNode->setDsqlDesc(castDesc);
}
// If a new alias was created for keeping original field-name
// make the alias the "top" node.
if (newAliasNode)
{
newAliasNode->value = castNode;
newAliasNode->value->nodDesc = castNode->nodDesc;
list->items[position] = newAliasNode;
}
else
@ -2918,7 +2916,7 @@ DsqlMapNode* PASS1_post_map(DsqlCompilerScratch* dsqlScratch, ValueExprNode* nod
map->map_window = windowMap;
}
DsqlDescMaker::fromNode(dsqlScratch, &node->nodDesc, node);
DsqlDescMaker::fromNode(dsqlScratch, node);
return FB_NEW_POOL(*tdbb->getDefaultPool()) DsqlMapNode(*tdbb->getDefaultPool(), context, map);
}
@ -2977,8 +2975,8 @@ bool PASS1_set_parameter_type(DsqlCompilerScratch* dsqlScratch, ValueExprNode* i
auto makeDesc = [&] (dsc* desc)
{
DsqlDescMaker::fromNode(dsqlScratch, &node->nodDesc, node);
*desc = node->nodDesc;
DsqlDescMaker::fromNode(dsqlScratch, node);
*desc = node->getDsqlDesc();
};
return inNode->setParameterType(dsqlScratch, makeDesc, forceVarchar);