@@ -9881,6 +9881,19 @@ ParameterNode* ParameterNode::pass1(thread_db* tdbb, CompilerScratch* csb)
9881
9881
status_exception::raise (Arg::Gds (isc_ctxnotdef) << Arg::Gds (isc_random) << Arg::Str (" Outer parameter has no outer scratch" ));
9882
9882
}
9883
9883
9884
+ const dsc& desc = format->fmt_desc [argNumber];
9885
+ if (desc.isText ())
9886
+ {
9887
+ // Remember expected maximum length in characters to be able to recognize format of the real data buffer later
9888
+ const CharSet* charSet = INTL_charset_lookup (tdbb, desc.getCharSet ());
9889
+ USHORT length = TEXT_LEN (&desc);
9890
+ if (charSet->isMultiByte ())
9891
+ {
9892
+ length /= charSet->maxBytesPerChar ();
9893
+ }
9894
+ maxCharLength = length;
9895
+ }
9896
+
9884
9897
return this ;
9885
9898
}
9886
9899
@@ -9944,9 +9957,6 @@ dsc* ParameterNode::execute(thread_db* tdbb, Request* request) const
9944
9957
{
9945
9958
if (impureForOuter)
9946
9959
EVL_make_value (tdbb, retDesc, impureForOuter);
9947
-
9948
- if (retDesc->dsc_dtype == dtype_text)
9949
- INTL_adjust_text_descriptor (tdbb, retDesc);
9950
9960
}
9951
9961
9952
9962
auto impureFlags = paramRequest->getImpure <USHORT>(
@@ -9984,7 +9994,9 @@ dsc* ParameterNode::execute(thread_db* tdbb, Request* request) const
9984
9994
auto charSet = INTL_charset_lookup (tdbb, DSC_GET_CHARSET (retDesc));
9985
9995
9986
9996
EngineCallbacks::instance->validateData (charSet, len, p);
9987
- EngineCallbacks::instance->validateLength (charSet, DSC_GET_CHARSET (retDesc), len, p, maxLen);
9997
+
9998
+ // Validation of length for user-provided data against user-provided metadata makes a little sense here. Leave it to the real assignment.
9999
+ // Besides in some cases overlong values are valid. For example `field like ?`
9988
10000
}
9989
10001
else if (retDesc->isBlob ())
9990
10002
{
@@ -10013,6 +10025,25 @@ dsc* ParameterNode::execute(thread_db* tdbb, Request* request) const
10013
10025
*impureFlags |= VLU_checked;
10014
10026
}
10015
10027
10028
+ // This block is after validation because having here a malformed data would produce a wrong result
10029
+ if (!(request->req_flags & req_null) && retDesc->dsc_dtype == dtype_text && maxCharLength != 0 )
10030
+ {
10031
+ // Data in the message buffer can be in a padded Firebird format or in an application-defined format with real length.
10032
+ // API provides no way to distinguish these cases so we must use some heuristics:
10033
+ // perform the adjustment only if the data length matches the length that would be expected in the padded format.
10034
+
10035
+ const CharSet* charSet = INTL_charset_lookup (tdbb, retDesc->getCharSet ());
10036
+
10037
+ if (charSet->isMultiByte () && maxCharLength * charSet->maxBytesPerChar () == retDesc->dsc_length )
10038
+ {
10039
+ Firebird::HalfStaticArray<UCHAR, BUFFER_SMALL> buffer;
10040
+
10041
+ retDesc->dsc_length = charSet->substring (retDesc->dsc_length , retDesc->dsc_address ,
10042
+ retDesc->dsc_length , buffer.getBuffer (retDesc->dsc_length ), 0 ,
10043
+ maxCharLength);
10044
+ }
10045
+ }
10046
+
10016
10047
return (request->req_flags & req_null) ? nullptr : retDesc;
10017
10048
}
10018
10049
0 commit comments