Skip to content

Fix for #8565 #8566

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 35 additions & 4 deletions src/dsql/ExprNodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9881,6 +9881,19 @@ ParameterNode* ParameterNode::pass1(thread_db* tdbb, CompilerScratch* csb)
status_exception::raise(Arg::Gds(isc_ctxnotdef) << Arg::Gds(isc_random) << Arg::Str("Outer parameter has no outer scratch"));
}

const dsc& desc = format->fmt_desc[argNumber];
if (desc.isText())
{
// Remember expected maximum length in characters to be able to recognize format of the real data buffer later
const CharSet* charSet = INTL_charset_lookup(tdbb, desc.getCharSet());
USHORT length = TEXT_LEN(&desc);
if (charSet->isMultiByte())
{
length /= charSet->maxBytesPerChar();
}
maxCharLength = length;
}

return this;
}

Expand Down Expand Up @@ -9944,9 +9957,6 @@ dsc* ParameterNode::execute(thread_db* tdbb, Request* request) const
{
if (impureForOuter)
EVL_make_value(tdbb, retDesc, impureForOuter);

if (retDesc->dsc_dtype == dtype_text)
INTL_adjust_text_descriptor(tdbb, retDesc);
}

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

EngineCallbacks::instance->validateData(charSet, len, p);
EngineCallbacks::instance->validateLength(charSet, DSC_GET_CHARSET(retDesc), len, p, maxLen);

// Validation of length for user-provided data against user-provided metadata makes a little sense here. Leave it to the real assignment.
// Besides in some cases overlong values are valid. For example `field like ?`
}
else if (retDesc->isBlob())
{
Expand Down Expand Up @@ -10013,6 +10025,25 @@ dsc* ParameterNode::execute(thread_db* tdbb, Request* request) const
*impureFlags |= VLU_checked;
}

// This block is after validation because having here a malformed data would produce a wrong result
if (!(request->req_flags & req_null) && retDesc->dsc_dtype == dtype_text && maxCharLength != 0)
{
// Data in the message buffer can be in a padded Firebird format or in an application-defined format with real length.
// API provides no way to distinguish these cases so we must use some heuristics:
// perform the adjustment only if the data length matches the length that would be expected in the padded format.

const CharSet* charSet = INTL_charset_lookup(tdbb, retDesc->getCharSet());

if (charSet->isMultiByte() && maxCharLength * charSet->maxBytesPerChar() == retDesc->dsc_length)
{
Firebird::HalfStaticArray<UCHAR, BUFFER_SMALL> buffer;

retDesc->dsc_length = charSet->substring(retDesc->dsc_length, retDesc->dsc_address,
retDesc->dsc_length, buffer.getBuffer(retDesc->dsc_length), 0,
maxCharLength);
}
}

return (request->req_flags & req_null) ? nullptr : retDesc;
}

Expand Down
1 change: 1 addition & 0 deletions src/dsql/ExprNodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -1671,6 +1671,7 @@ class ParameterNode final : public TypedNode<ValueExprNode, ExprNode::TYPE_PARAM
// Message can be modified during merge of SP/view subtrees
USHORT messageNumber = MAX_USHORT;
USHORT argNumber = 0;
USHORT maxCharLength = 0;
bool outerDecl = false;
};

Expand Down
Loading