Skip to content

Commit 48e2d32

Browse files
committed
Recognize message format with a real data length for dtype_text
1 parent 3732012 commit 48e2d32

File tree

2 files changed

+36
-4
lines changed

2 files changed

+36
-4
lines changed

src/dsql/ExprNodes.cpp

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9881,6 +9881,19 @@ ParameterNode* ParameterNode::pass1(thread_db* tdbb, CompilerScratch* csb)
98819881
status_exception::raise(Arg::Gds(isc_ctxnotdef) << Arg::Gds(isc_random) << Arg::Str("Outer parameter has no outer scratch"));
98829882
}
98839883

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+
98849897
return this;
98859898
}
98869899

@@ -9944,9 +9957,6 @@ dsc* ParameterNode::execute(thread_db* tdbb, Request* request) const
99449957
{
99459958
if (impureForOuter)
99469959
EVL_make_value(tdbb, retDesc, impureForOuter);
9947-
9948-
if (retDesc->dsc_dtype == dtype_text)
9949-
INTL_adjust_text_descriptor(tdbb, retDesc);
99509960
}
99519961

99529962
auto impureFlags = paramRequest->getImpure<USHORT>(
@@ -9984,7 +9994,9 @@ dsc* ParameterNode::execute(thread_db* tdbb, Request* request) const
99849994
auto charSet = INTL_charset_lookup(tdbb, DSC_GET_CHARSET(retDesc));
99859995

99869996
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 ?`
998810000
}
998910001
else if (retDesc->isBlob())
999010002
{
@@ -10013,6 +10025,25 @@ dsc* ParameterNode::execute(thread_db* tdbb, Request* request) const
1001310025
*impureFlags |= VLU_checked;
1001410026
}
1001510027

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+
1001610047
return (request->req_flags & req_null) ? nullptr : retDesc;
1001710048
}
1001810049

src/dsql/ExprNodes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1671,6 +1671,7 @@ class ParameterNode final : public TypedNode<ValueExprNode, ExprNode::TYPE_PARAM
16711671
// Message can be modified during merge of SP/view subtrees
16721672
USHORT messageNumber = MAX_USHORT;
16731673
USHORT argNumber = 0;
1674+
USHORT maxCharLength = 0;
16741675
bool outerDecl = false;
16751676
};
16761677

0 commit comments

Comments
 (0)