On 18/05/2025 15:17, 'Dimitry Sibiryakov' via firebird-devel wrote:
> 'Mark Rotteveel' via firebird-devel wrote 18.05.2025 14:44:
>>
>> Again, not that familiar with the engine internals, but from the
>> perspective of the outside API (e.g. wire protocol), there is a pretty
>> big difference between using CHAR vs VARCHAR in that you can (or even:
>> should) send VARCHAR without caring about any padding.
>
> It is not quite so.
>
> Consider following code:
>
> param_vary* buffer = { 2, "a " };
> sqltype = SQL_VARYING;
> sqlsubtype = 4; // charset UTF-8
> sqldata = buffer;
> sqllen = 6;
>
> This will end up in any kind of error because server expect sqllen
> for this data to be at least 10 (2 + 2*4). You still have to pad VARCHAR
> parameter to max byte length, just padding is not whitespaces but unused
> space.
Not in the wire protocol. There you can send the BLR for this column as
{ blr_varying2, 4, 0, 2, 0 } (length = 2, not 6!) and the row data would
be {0, 0, 0, 2, 0x61, 0x20 } + padding { 0x20, 0x20 } (or maybe { 0x00,
0x00 }) so it's a multiple of 4.
And even in native, you should be able to use:
char* buffer = { 2, 0, 0x61, 0x20, 0 };
sqltype = SQL_VARYING;
sqlsubtype = 4; // charset UTF-8
sqldata = buffer;
sqllen = 2;
I've used char* as I don't know what param_vary* is, nor could I find it
in Firebird sources. The length prefix is an Int16LE ox x86/AMD64, and
the buffer needs a nul-terminator
Also not that the sqllen is 2, not 6 (the length prefix and
nul-terminator are not part of the sqllen!).
That said, Jaybird's native implementation does use a buffer that was
allocated to the original length (sqllen + 3 for SQL_VARYING), even
though it modifies the sqllen on execute, so that could make a difference.
However, if I understand it correctly, previously Firebird would copy
the data into a buffer of the correct length with the original sqllen
value, allowing it to correctly calculate the CHAR(n) using sqllen/4,
and your change broke that because you now simply reuse the user buffer
(which, BTW, I wonder is actually secure to do in case of embedded), and
you update the sqllen to a value that breaks the assumption that the
engine can calculate character length as sqllen/4.
>> And Jaybird's test involving CHAR indeed now do break (tested against
>> Firebird-6.0.0.783-0-3732012-windows-x64), while the version from the
>> 5th of May (Firebird-6.0.0.770-0-82c4a08-windows-x64) works fine.
>
> Could you test artifacts from
https://github.com/FirebirdSQL/
> firebird/pull/8566, please?
Tests still fail, even tests that don't seem to involve CHAR, like a
test with TIME WITH TIME ZONE
(TimeWithTimeZoneSupportTest.testSelectCondition()):
Stack overflow. The resource requirements of the runtime stack have
exceeded the memory available to it. [SQLState:HY001, ISC error
code:335544781]
However, the Jaybird tests seem to have issues with recovering from some
of the test failures, and I can't easily discern if a failure is due to
a server-side issue, or due to failure to recover from a previous test
failure.
>> Doesn't that mean that change should be backed out (reverted) until it
>> can be fixed properly?
>
> Normally yes, but a) the only idea of "a proper fix" was another
> workaround that would make things slower; b) this PR caused ~5%
> performance gain for database restore (and any DSQL-level bulk insert in
> common). The latter is the reason why I would prefer to properly fix
> consequences than to revert the PR.
A change that breaks things is not a good change, no matter the
performance improvement.
I'd say this needs to be backed out, until it can be fixed in its entirety
Mark
--
Mark Rotteveel