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

Fixed CORE-4566: Incorrect size of the output parameter/argument when execute block, procedure or function use system field in metadata charset

This commit is contained in:
alexpeshkoff 2014-10-05 13:14:43 +00:00
parent 75955fa3a9
commit e8930f4408
5 changed files with 104 additions and 22 deletions

View File

@ -10576,7 +10576,13 @@ void UdfCallNode::make(DsqlCompilerScratch* /*dsqlScratch*/, dsc* desc)
desc->setNullable(true); desc->setNullable(true);
if (desc->dsc_dtype <= dtype_any_text) if (desc->dsc_dtype <= dtype_any_text)
{
desc->dsc_ttype() = dsqlFunction->udf_character_set_id; desc->dsc_ttype() = dsqlFunction->udf_character_set_id;
// Fix UNICODE_FSS wrong length used in system tables.
if ((dsqlFunction->udf_flags & UDF_sys_based) && (desc->dsc_ttype() == CS_UNICODE_FSS))
desc->dsc_length *= 3;
}
else else
desc->dsc_ttype() = dsqlFunction->udf_sub_type; desc->dsc_ttype() = dsqlFunction->udf_sub_type;
} }

View File

@ -354,7 +354,8 @@ public:
enum udf_flags_vals { enum udf_flags_vals {
UDF_new_udf = 1, // udf is newly declared, not committed yet UDF_new_udf = 1, // udf is newly declared, not committed yet
UDF_dropped = 2, // udf has been dropped UDF_dropped = 2, // udf has been dropped
UDF_subfunc = 4 // sub function UDF_subfunc = 4, // sub function
UDF_sys_based = 8 // return value based on column from system table
}; };
// Variables - input, output & local // Variables - input, output & local

View File

@ -63,6 +63,21 @@ using namespace Jrd;
using namespace Firebird; using namespace Firebird;
static void adjustLength(dsc* desc)
{
USHORT adjust = 0;
if (desc->dsc_dtype == dtype_varying)
adjust = sizeof(USHORT);
else if (desc->dsc_dtype == dtype_cstring)
adjust = 1;
desc->dsc_length -= adjust;
desc->dsc_length *= 3;
desc->dsc_length += adjust;
}
LiteralNode* MAKE_const_slong(SLONG value) LiteralNode* MAKE_const_slong(SLONG value)
{ {
thread_db* tdbb = JRD_get_thread_data(); thread_db* tdbb = JRD_get_thread_data();
@ -257,10 +272,12 @@ void MAKE_desc_from_field(dsc* desc, const dsql_fld* field)
desc->dsc_flags = (field->flags & FLD_nullable) ? DSC_nullable : 0; desc->dsc_flags = (field->flags & FLD_nullable) ? DSC_nullable : 0;
if (desc->isText() || desc->isBlob()) if (desc->isText() || desc->isBlob())
{ desc->setTextType(INTL_CS_COLL_TO_TTYPE(field->charSetId, field->collationId));
desc->setTextType(INTL_CS_COLL_TO_TTYPE(
field->charSetId, field->collationId)); // UNICODE_FSS_HACK
} // check if the field is a system domain and CHARACTER SET is UNICODE_FSS
if (desc->isText() && (INTL_GET_CHARSET(desc) == CS_UNICODE_FSS) && (field->flags & FLD_system))
adjustLength(desc);
} }
@ -327,6 +344,14 @@ FieldNode* MAKE_field(dsql_ctx* context, dsql_fld* field, ValueListNode* indices
// node->nodDesc.dsc_scale = field->scale; // node->nodDesc.dsc_scale = field->scale;
// node->nodDesc.dsc_sub_type = field->subType; // node->nodDesc.dsc_sub_type = field->subType;
// UNICODE_FSS_HACK
// check if the field is a system domain and the type is CHAR/VARCHAR CHARACTER SET UNICODE_FSS
if ((field->flags & FLD_system) && node->nodDesc.dsc_dtype <= dtype_varying &&
INTL_GET_CHARSET(&node->nodDesc) == CS_METADATA)
{
adjustLength(&node->nodDesc);
}
} }
else else
{ {
@ -350,23 +375,6 @@ FieldNode* MAKE_field(dsql_ctx* context, dsql_fld* field, ValueListNode* indices
if ((field->flags & FLD_nullable) || (context->ctx_flags & CTX_outer_join)) if ((field->flags & FLD_nullable) || (context->ctx_flags & CTX_outer_join))
node->nodDesc.dsc_flags |= DSC_nullable; node->nodDesc.dsc_flags |= DSC_nullable;
// UNICODE_FSS_HACK
// check if the field is a system domain and the type is CHAR/VARCHAR CHARACTER SET UNICODE_FSS
if ((field->flags & FLD_system) && node->nodDesc.dsc_dtype <= dtype_varying &&
INTL_GET_CHARSET(&node->nodDesc) == CS_METADATA)
{
USHORT adjust = 0;
if (node->nodDesc.dsc_dtype == dtype_varying)
adjust = sizeof(USHORT);
else if (node->nodDesc.dsc_dtype == dtype_cstring)
adjust = 1;
node->nodDesc.dsc_length -= adjust;
node->nodDesc.dsc_length *= 3;
node->nodDesc.dsc_length += adjust;
}
return node; return node;
} }

View File

@ -82,6 +82,40 @@ namespace
ERR_post(Arg::Gds(isc_bad_trans_handle)); ERR_post(Arg::Gds(isc_bad_trans_handle));
} }
} }
bool isSystemRelation(thread_db* tdbb, jrd_tra* transaction, const char* relName)
{
bool rc = false;
AutoCacheRequest handle(tdbb, irq_system_relation, IRQ_REQUESTS);
FOR(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction)
R IN RDB$RELATIONS WITH
R.RDB$RELATION_NAME EQ relName AND
R.RDB$SYSTEM_FLAG EQUIV 1
{
rc = true;
}
END_FOR
return rc;
}
bool isSystemDomain(thread_db* tdbb, jrd_tra* transaction, const char* fldName)
{
bool rc = false;
AutoCacheRequest handle(tdbb, irq_system_domain, IRQ_REQUESTS);
FOR(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction)
R IN RDB$FIELDS WITH
R.RDB$FIELD_NAME EQ fldName AND
R.RDB$SYSTEM_FLAG EQUIV 1
{
rc = true;
}
END_FOR
return rc;
}
} }
@ -884,6 +918,21 @@ dsql_udf* METD_get_function(jrd_tra* transaction, DsqlCompilerScratch* dsqlScrat
if (!F.RDB$CHARACTER_SET_ID.NULL) { if (!F.RDB$CHARACTER_SET_ID.NULL) {
userFunc->udf_character_set_id = F.RDB$CHARACTER_SET_ID; userFunc->udf_character_set_id = F.RDB$CHARACTER_SET_ID;
} }
if ((!X.RDB$ARGUMENT_MECHANISM.NULL) && X.RDB$ARGUMENT_MECHANISM == prm_mech_type_of &&
(!X.RDB$FIELD_NAME.NULL) && X.RDB$FIELD_NAME[0] &&
(!X.RDB$RELATION_NAME.NULL) && X.RDB$RELATION_NAME[0])
{
// type of column used in declaration
if (isSystemRelation(tdbb, transaction, X.RDB$RELATION_NAME))
userFunc->udf_flags |= UDF_sys_based;
}
else if ((!X.RDB$FIELD_SOURCE.NULL) && X.RDB$FIELD_SOURCE[0])
{
// domain used in declaration
if (isSystemDomain(tdbb, transaction, X.RDB$FIELD_SOURCE))
userFunc->udf_flags |= UDF_sys_based;
}
} }
else else
{ {
@ -1258,6 +1307,22 @@ dsql_prc* METD_get_procedure(jrd_tra* transaction, DsqlCompilerScratch* dsqlScra
parameter->typeOfTable = PR.RDB$RELATION_NAME; parameter->typeOfTable = PR.RDB$RELATION_NAME;
} }
if (parameter->typeOfTable.hasData())
{
if (isSystemRelation(tdbb, transaction, parameter->typeOfTable.c_str()))
parameter->flags |= FLD_system;
}
else if (parameter->typeOfName.hasData())
{
if (isSystemDomain(tdbb, transaction, parameter->typeOfName.c_str()))
parameter->flags |= FLD_system;
}
else if (parameter->fieldSource.hasData())
{
if (isSystemDomain(tdbb, transaction, parameter->fieldSource.c_str()))
parameter->flags |= FLD_system;
}
if (type == 0 && if (type == 0 &&
(!pr_default_value_null || (!pr_default_value_null ||
(fb_utils::implicit_domain(FLD.RDB$FIELD_NAME) && !FLD.RDB$DEFAULT_VALUE.NULL))) (fb_utils::implicit_domain(FLD.RDB$FIELD_NAME) && !FLD.RDB$DEFAULT_VALUE.NULL)))

View File

@ -156,6 +156,8 @@ enum irq_type_t
irq_func_ret_fld, // lookup argument's domain irq_func_ret_fld, // lookup argument's domain
irq_fun_validate, // function blr validate irq_fun_validate, // function blr validate
irq_c_fun_dpd, // get function dependencies irq_c_fun_dpd, // get function dependencies
irq_system_relation, // check is relation system or not
irq_system_domain, // check is field system or not
irq_grant11, // process grant option (functions) irq_grant11, // process grant option (functions)
irq_cs_security, // verify security for character set irq_cs_security, // verify security for character set
irq_coll_security, // verify security for collation irq_coll_security, // verify security for collation