Repository navigation
Conversation
|
Two follow-ups after the initial push failed the FB-master matrix jobs:
All 10 matrix jobs green on the latest push. |
|
Does this issue only occur when executing a stored procedure? Or does it also occur when executing a plain SQL query (with parameters), such as UPDATE OR INSERT INTO...? |
Good catch. I ran a few quick tests here, and it does happen in that case as well. I’m expanding the test coverage now. |
62863e1 to
3d3b7a2
Compare
|
Follow-up after a question about test coverage — two findings worth recording: 1. The bug is not SP-specific. Empirical check against the old v3.0.1.21 driver:
Same failure signature in both cases — 9 single-digit rows + 1 NUL-corrupted Added 2. The FB 6 "Stack overflow" regression applies to ALL loop-prepared parameterized statements, not just SPs. My first attempt at the DML test failed CI on FB 6 master with the same 3. Sibling conversion coverage. The All 10 matrix jobs green on both PRs. |
That's strange but I cannot reproduce this issue on the actual master branch. What FB version you're using? I've tried 3, 4 and 5. No data loss, 500 records are inserted and commited, no data corruption.
|
I built upstream master ( If your test harness stringifies the integer and binds I put together a minimal standalone reproducer (one .cpp, 4 shapes — direct+char, direct+slong, prepare-once+slong, rebind+slong): repro_variants.cpp. Against upstream With this PR all four shapes are OK. Could you share the snippet you used (or point me at the C-type you bind)? If it's |
|
Also worth noting while I was at it: my gtest cases here are in fact That's a pre-existing issue — I'll open a small follow-up fixing |
|
@fdcastel |
|
Sure, take your time! That was just a first pass (yep, AI-generated 😄) to show it works. Now we can improve it. I just came across this -- while working on a totally a different project. |
d026ec7 to
e996b2b
Compare
|
Hi @irodushka — took your feedback and pushed a cleaner v2 on top of the PR: Three named helpers replace the scattered inlining:
Net effect: the ODBC conversion layer no longer writes VARYING length prefixes or reads I also rewrote the One small cosmetic follow-up — All 10 matrix jobs green on both commits. Happy to split, rearrange, or dig deeper into any piece if something still looks off. |
|
Aha... you gonna blow my brains) So the only failing scenario is to prepare the query, then on each iteration - reset parameters, bind them every time & exеcute?.. I mean "rebind_slong". All the others - direct_char, direct_slong and preponce_slong - are OK. And "preponce_slong" is the only sane scenario. All the rest are strange and extremely suboptimal. Okay, at least I got it and I see the misbehaviour (although, despite this, I would not recommend anyone to use this approach when working with sql queries 😃). |
|
Can you please check a bit simplified fix... Change the line OdbcConvert.cpp:1306 and nothing more. I mean - instead of all your changes in this PR. Well, and the line 1398 for the Wide version. |
|
Unfortunately it's not so simple. I built your one-liner against
(FB 5.0.3, Which lines up with there being two separate bugs the PR addresses:
The PR addresses both: the VARYING-vs-TEXT write rule now lives in On " |
|
Pushed e40dfa8 — two additional tests in The original two tests ( The two new tests
|
e40dfa8 to
d5daa1d
Compare
|
P.S.: I attempted to rename the (very poorly named) branch for this PR, but GitHub ended up closing the PR incorrectly. So I’m leaving it as is for now. |
|
Oh my Lord... That's not addressed to you, @fdcastel, just an idle talk. Finally I got it. The misbehavior occures when I set "CHARACTER SET UTF8" for varchar fields. And it works ok (with the 1-line fix of cause) when I use NONE charset. The reason is - if we use the UTF8 charset, the WIDE int->string conv function is called, and there's an extremely bad place in it: Such a familiar code, isn't it?) Your fix works because you've added the gating logic, I mean And the last - it does not relate to VARCHAR at all) Please try to create the test table as and run your tests... You can also create table with |
|
you can:
As for me, this solves the problem completely. Linux. P.S. And yes, it is true that when converting from any data type (except string) to string, we cannot get anything but ASCII characters... so your control logic ( |
|
Almost 😅 TL;DR Your minimal fix (3 lines) works for the write direction: my v3 theory was wrong. But unfortunately it breaks 4 pre-existing tests in the read direction. Tested both of your proposals empirically: CHAR target and CHARACTER SET NONE
Your 3-line minimal fix (line 1306 + 1387 +
|
|
No need to use the exact 3-lines patch, it was for illustration only. I
think it's ok to separate logic for read&write directions. And yes, that
legacy code is very, very, VERY entangled)
чт, 23 апр. 2026 г., 21:43 F.D.Castel ***@***.***>:
… *fdcastel* left a comment (FirebirdSQL/firebird-odbc-driver#292)
<#292?email_source=notifications&email_token=AAKZQLWDIDVTKYZDM4QOMOT4XJP4JA5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTIMZQGY4TENBRG4YKM4TFMFZW63VHNVSW45DJN5XKKZLWMVXHJNLQOJPWG33NNVSW45C7N5YGK3S7MNWGSY3L#issuecomment-4306924170>
Almost 😅
*TL;DR* Your minimal fix (3 lines) works for the *write* direction: my v3
theory was wrong. But unfortunately it breaks 4 pre-existing tests in the
*read* direction.
------------------------------
Tested both of your proposals empirically:
CHAR target and CHARACTER SET NONE
- pushed 220eb3c
<fdcastel@220eb3c> and
9a1a432
<fdcastel@9a1a432>.
- Three new gtest cases covering CHAR(20) + UTF8, VARCHAR(20) + NONE, CHAR(20)
+ NONE in the rebind shape;
- a cherry-picked rdb$get_context fix for GetServerMajorVersion so
SKIP_ON_FIREBIRD6 stops firing on FB 5.
- Combined effect on run 24850170760
<https://github.com/fdcastel/firebird-odbc-driver/actions/runs/24850170760>:
- 7/7 Issue161 tests
- Passed on ubuntu-22.04 / 5.0.3 AND on windows-2022 / 5.0.3,
correctly Skipped on FB 6 master
- so the coverage is real on both OSes now, not silent skips.
Your 3-line minimal fix (line 1306 + 1387 + from->isIndicatorSqlDagate)
- I applied it on top of clean master, pushed to a scratch branch, and
ran the full CI matrix (run 24851385888
<https://github.com/fdcastel/firebird-odbc-driver/actions/runs/24851385888>,
branch since deleted).
- On the write-direction matrix *it passes exactly as you described on
Linux*: all 16 (column type × charset × shape) combinations OK,
including CHAR + UTF8.
- *My earlier claim that the VARYING prefix stomp would persist under
your minimal fix was wrong*: the OO-API path via checkAndRebuild()
handles the sqllen mutation fine. Apologies for the sloppy theoretical
argument.
But
- the minimal fix regressed 4 pre-existing read-direction tests on
every matrix job: DataTypeTest.NumericPrecision, ResultConversionsTest.{IntegerToChar,
NumericToChar, BooleanToChar}.
- The reason is that s/to->length/to->octetLength/ at line 1306 *affects
both directions*
- and on the read direction (FB column → client SQL_C_CHAR buffer)
to->length and to->octetLength are not the same:
- to->length is the declared capacity (SQL_DESC_LENGTH) while
to->octetLength can come from the source column's display size and
be smaller.
- Using octetLength as the truncation cap on the read path writes only
part of the formatted number and the test fails.
This PR's chooseNumericToStringConv avoids that: it routes only when
to->isIndicatorSqlDa is true (write-to-FB), leaving the read path on the
wide variant unchanged and to->length semantics untouched.
I can't see a tweak to your 3-line approach that keeps it 3 lines without
introducing the same to->isIndicatorSqlDa branching we already have.
On chooseNumericToStringConv naming
Agreed, the helper covers date/time as well, not just numerics. I'll
rename to selectToStringConv in a follow-up commit on this PR.
On "what if not ASCII"
- the specific converters this PR touches (
conv<Numeric|Date|Time|DateTime>ToString{,W}) emit only ASCII: 0–9, .,
-, :, , e/E, *.
- No path in those macros produces a byte > 0x7F, so routing the UTF8
/ WVARCHAR target through the byte variant is bit-identical regardless of
charset.
- The character-data family (conv<String>ToString*) is a different
code path, unchanged by this PR, and continues to flow through
transferString*ToAllowedType with charset awareness.
Next steps
I need TWO beers, now.
—
Reply to this email directly, view it on GitHub
<#292?email_source=notifications&email_token=AAKZQLWDIDVTKYZDM4QOMOT4XJP4JA5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTIMZQGY4TENBRG4YKM4TFMFZW63VHNVSW45DJN5XKKZLWMVXHJNLQOJPWG33NNVSW45C7N5YGK3S7MNWGSY3L#issuecomment-4306924170>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAKZQLRR2JK3F6F2SIRPWN34XJP4JAVCNFSM6AAAAACYBN4RGGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHM2DGMBWHEZDIMJXGA>
.
Triage notifications, keep track of coding agent tasks and review pull
requests on the go with GitHub Mobile for iOS
<https://github.com/notifications/mobile/ios/AAKZQLUBYJAGO37ENWG7Z2L4XJP4JA5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTIMZQGY4TENBRG4YKM4TFMFZW63VHNVSW45DJN5XKKZLWMVXHJKTGN5XXIZLSL5UW64Y>
and Android
<https://github.com/notifications/mobile/android/AAKZQLQDMW3MMGFIQ6EE7BL4XJP4JA5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTIMZQGY4TENBRG4YKM4TFMFZW63VHNVSW45DJN5XKKZLWMVXHJLTGN5XXIZLSL5QW4ZDSN5UWI>.
Download it today!
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
Binding SQL_C_SLONG/SQL_C_SBIGINT/SQL_C_FLOAT/... to a SQL_VARCHAR column forces the ODBC driver to convert numeric-C to character-SQL internally. That conversion path is one of the least-exercised corners of many drivers: the Firebird ODBC driver ≤ 3.5.0 silently corrupted writes on it (duckdb#161 / FirebirdSQL/firebird-odbc-driver#292), and older MSSQL and MySQL ODBC releases have shipped similar defects. Params::SetExpectedTypes now transforms TINYINT…BIGINT and FLOAT/DOUBLE ScannerValues into TYPE_DECIMAL_AS_CHARS whenever the prepared parameter's expected type is a character family (CHAR / VARCHAR / LONGVARCHAR / WCHAR / WVARCHAR / WLONGVARCHAR). The scanner then binds SQL_C_CHAR → the actual expected character SQL type via the existing DecimalChars path. This entirely bypasses the driver's numeric-to-string coercion — no driver bug required. BindOdbcParam<DecimalChars> also now honors the expected character SQL type (it hard-coded SQL_VARCHAR before) so CHAR / WVARCHAR columns are not silently re-coerced.
|
@fdcastel |
9a1a432 to
b6ad723
Compare
The dispatcher routes SQL_C_WCHAR targets to the byte variant when the destination is a Firebird-side buffer. It covers numeric, date, time, and datetime conversions, not just numerics — so the "Numeric" in the old name was misleading. Per review feedback on PR FirebirdSQL#292. No behaviour change.
|
Sorry for the silence — I'd drafted this reply weeks ago and then never actually posted it. Posting now so you have the empirical answers to both of your last two comments. TL;DR
1. Column-type × charset matrix on Windows (FB 5.0.3 /
|
| Target column | direct_char | direct_slong | preponce_slong | rebind_slong |
|---|---|---|---|---|
VARCHAR(20) CHARACTER SET UTF8 |
500 / nul=0 OK | 500 / nul=500 FAIL | 500 / nul=500 FAIL | 11 / nul=1 FAIL |
CHAR(20) CHARACTER SET UTF8 |
500 / nul=0 OK | 500 / nul=500 FAIL | 500 / nul=500 FAIL | 11 / nul=1 FAIL |
VARCHAR(20) CHARACTER SET NONE |
500 / nul=0 OK | 500 / nul=0 OK | 500 / nul=0 OK | 10 / nul=0 FAIL |
CHAR(20) CHARACTER SET NONE |
500 / nul=0 OK | 500 / nul=0 OK | 500 / nul=0 OK | 10 / nul=0 FAIL |
master + your minimal fix (both line changes + from->isIndicatorSqlDa gate)
| Target column | direct_char | direct_slong | preponce_slong | rebind_slong |
|---|---|---|---|---|
VARCHAR(20) CHARACTER SET UTF8 |
500 / nul=0 OK | 500 / nul=0 OK | 500 / nul=0 OK | 500 / nul=0 OK |
CHAR(20) CHARACTER SET UTF8 |
500 / nul=0 OK | 500 / nul=0 OK | 500 / nul=0 OK | 500 / nul=0 OK |
VARCHAR(20) CHARACTER SET NONE |
500 / nul=0 OK | 500 / nul=0 OK | 500 / nul=0 OK | 500 / nul=0 OK |
CHAR(20) CHARACTER SET NONE |
500 / nul=0 OK | 500 / nul=0 OK | 500 / nul=0 OK | 500 / nul=0 OK |
This PR
| Target column | direct_char | direct_slong | preponce_slong | rebind_slong |
|---|---|---|---|---|
VARCHAR(20) CHARACTER SET UTF8 |
500 / nul=0 OK | 500 / nul=0 OK | 500 / nul=0 OK | 500 / nul=0 OK |
CHAR(20) CHARACTER SET UTF8 |
500 / nul=0 OK | 500 / nul=0 OK | 500 / nul=0 OK | 500 / nul=0 OK |
VARCHAR(20) CHARACTER SET NONE |
500 / nul=0 OK | 500 / nul=0 OK | 500 / nul=0 OK | 500 / nul=0 OK |
CHAR(20) CHARACTER SET NONE |
500 / nul=0 OK | 500 / nul=0 OK | 500 / nul=0 OK | 500 / nul=0 OK |
The first two tables confirm your Linux observations on Windows as well. My v3 reply argued theoretically that your minimal fix would leave the VARYING-prefix stomp in place — that was wrong. FB's OO-API checkAndRebuild() path handles the sqllen mutation cleanly; offset 0..1 is not reinterpreted the way the legacy XSQLVAR code would. Sorry for the sloppy theoretical argument — should have measured first.
Stored values are correct under the minimal fix too:
SELECT ID, OCTET_LENGTH(ID), CHAR_LENGTH(ID) FROM ISSUE161_T WHERE ID IN ('1','10','100','500');
ID OCTET_LENGTH CHAR_LENGTH
1 1 1
10 2 2
100 3 3
500 3 3
So at the write-direction the minimal fix is functionally equivalent for this workload.
2. But the minimal fix regresses the read direction
When I pushed the minimal fix to a scratch branch and ran the full CI matrix (run 24851385888, branch since deleted), all 10 matrix jobs failed — and not on the new Issue161 cases. They failed on 4 unrelated, pre-existing tests in the read direction:
DataTypeTest.NumericPrecisionResultConversionsTest.IntegerToCharResultConversionsTest.NumericToCharResultConversionsTest.BooleanToChar
Locally reproducible on Windows x64 / FB 5.0.3 with the minimal fix applied:
[ RUN ] DataTypeTest.NumericPrecision
test_data_types.cpp(132): error: The difference between dval and
12345678901234.5678 is 12345678901234.568, which exceeds 0.001
[ FAILED ] DataTypeTest.NumericPrecision
...
[ FAILED ] ResultConversionsTest.IntegerToChar
[ FAILED ] ResultConversionsTest.NumericToChar
[ FAILED ] ResultConversionsTest.BooleanToChar
Why
These tests exercise the read direction — SELECT integer_column with SQLBindCol(SQL_C_CHAR, buf, 32), then SQLFetch. Path: conv<Long>ToString runs with from = FB column (isIndicatorSqlDa = true) and to = client SQL_C_CHAR buffer (isIndicatorSqlDa = false).
The minimal fix swaps int len = to->length; for int len = to->octetLength; at the top of the byte macro. For a FB-side to, the two are pragmatically equivalent (both represent the declared column length). For a client-side to, they are not: to->length is SQL_DESC_LENGTH (the application-visible capacity in characters), while to->octetLength is SQL_DESC_OCTET_LENGTH (the raw buffer size in bytes), and they can diverge — in particular SQL_C_CHAR bindings made with a 32-byte buffer for a NUMERIC(18,4) target end up with length = 32 but octetLength coming from the source column's display size, which is 21 for NUMERIC(18,4). Using octetLength as the truncation cap writes only part of the number and breaks the read test.
This is exactly why this PR keeps to->length in the byte macro as-is and instead routes the write-direction to the byte variant from getAdressFunction via selectToStringConv (was chooseNumericToStringConv before b6ad723). The path selection depends on to->isIndicatorSqlDa, not on a universal substitution — so the read direction is untouched.
I did not catch this divergence theoretically; I caught it by running the full test suite on CI.
3. The non-ASCII concern, specifically for these converters
For the conv<Numeric|Date|Time|DateTime>ToString{,W} family — everything this PR modifies — the source-side output is ASCII by construction:
conv{TinyInt,Short,Long,Bigint}ToString:0–9,.,-,*convFloatToString/convDoubleToString:0–9,.,-,e,EconvDateToString/convTimeToString/convDateTimeToString:0–9,-,:,,.
No code path in these macros can produce a byte > 0x7F, so routing the UTF8 / WVARCHAR target through the byte variant is safe: ASCII is bit-identical under UTF8 / NONE / ISO8859_1 / WIN1252.
The non-ASCII concern would be legitimate for convString*ToString* — the conversion family for character data — but this PR does not touch those. They already go through transferString*ToAllowedType which honours the charset and is exercised by the WCharTest matrix.
4. Test coverage status
Pushed in 220eb3c and f412b68:
Issue161_SLongToCharViaDmlRebind—CHAR(20) CHARACTER SET UTF8Issue161_SLongToVarcharViaDmlRebindCharsetNone—VARCHAR(20) CHARACTER SET NONEIssue161_SLongToCharViaDmlRebindCharsetNone—CHAR(20) CHARACTER SET NONE
…on top of the existing 4 (Issue161_SLongToVarcharViaStoredProcedure, Issue161_SLongToVarcharViaDml, Issue161_SLongToVarcharViaDmlRebind, Issue161_SLongToVarcharViaDmlDirect).
Plus the cherry-picked rdb$get_context test-helper fix — same content as fix/sql-dbms-ver (now merged in #294); kept here so the Issue161 tests actually execute on FB 3 / 4 / 5 against the driver-side SQL_DBMS_VER fix.
CI on the rebased + renamed tip (run 25896309764):
| Job | Issue161 tests | Result |
|---|---|---|
| build-and-test (ubuntu-22.04, linux-x64) | 7 | 7 Passed, 0 Skipped |
| build-and-test (windows-2022, windows-x64) | 7 | 7 Passed, 0 Skipped |
| build-and-test (ubuntu-22.04, master / FB 6) | 7 | 0 Passed, 7 Skipped (correct — SKIP_ON_FIREBIRD6 firing only on FB 6 as intended) |
All 10 matrix jobs green.
Status & branch
Rebased on current master (b64c011, which now includes #294's SQL_DBMS_VER driver fix and #297's SQLCopyDesc fix). Branch tip: b6ad723 (the rename). No conflicts.
PR #293 (sibling test coverage for Short / Bigint / Float / Double) is also rebased on the new master; it'll reduce to a clean tests-only diff once this lands.
Happy to do whatever else makes review easier — split commits differently, drop the rdb$get_context cherry-pick now that #294 fixes the driver side, etc. Just say the word.
|
Added three commits: the fix for #300 and a second defect on the same code path that only becomes testable here.
Why the second one belongs in this PR rather than in #302: on master its payoff is invisible, because clearing the flag only exposes the truncation this PR fixes (master writes
#302 carries the #300 commit on its own for a master-based merge; whichever of the two lands first makes that commit a no-op in the other. Full suite green in all three charset configurations (141 passed, 10 pre-existing skips). |
…converter With CHARSET=UTF8 Firebird describes a text parameter as UTF8 and the driver maps it to SQL_C_WCHAR, so getAdressFunction picked conv<Type>ToStringW for a numeric, date or time C type bound to it. That converter writes UTF-16 code units into the Firebird buffer, which Firebird stores as bytes with embedded NULs: 500 rows sent through a stored procedure or UPDATE OR INSERT came back corrupted, with SQL_SUCCESS at every step (duckdb/odbc-scanner#161). Under CHARSET=NONE the slot maps to SQL_C_CHAR and the byte converter was used, which is why the bug did not reproduce there. Route Firebird-side targets through the byte variant (selectToStringConv). These converters emit ASCII only, so the bytes are correct in every charset; application-side targets keep the wide variant. ODBCCONVERT_CHECKNULL and ODBCCONVERT_CHECKNULLW set the Firebird-side null flag on the NULL path but never cleared it, so a value bound after a NULL on the same parameter was sent as NULL. Clear it on the not-null path, as the two sibling macros already do. Tests: the stored-procedure, DML and direct shapes of the numeric-to-VARCHAR bind, and a value bound after a NULL for four C types on VARCHAR and CHAR.
After the first execute the conversion layer shrinks the live sqlvar's sqllen to the length of the value it wrote. An application that re-binds the parameter for every row (the shape odbc_copy_from uses) made defFromMetaDataIn re-read the precision from that sqlvar, so record->length collapsed to the length of the first value and every later value was truncated to its first character: 500 distinct ids became 11 rows. Read INPUT precision from orgSqlProperties, the snapshot taken at prepare time, as getColumnDisplaySize already does. OUTPUT keeps the live sqlvar, and SQL_ARRAY keeps the mutable CAttrSqlVar for its array pointer. Tests: the rebind shape on VARCHAR, plus its CHAR and CHARACTER SET NONE corners.
The previous commits only exercised convLongToString. Add one loop test per sibling converter (Short, Bigint, Float, Double) that binds the C type to a VARCHAR column declared CHARACTER SET UTF8, executes the same prepared INSERT across values of different widths, and checks the row count, the absence of embedded NUL bytes, and the round trip through CAST.
|
Sorry for the long silence; other professional tasks took my available time. To answer your question: I rebuilt the branch from current master with only what you agreed with, and force-pushed with lease so this thread stays. Three commits:
Gone: The tests declare CHARACTER SET UTF8 on their columns so they reproduce on any database. Verified on FB 5.0.3 with CHARSET=UTF8 and NONE: all 17 new tests fail on current master and pass here; full suite 240 passed, 0 failed passed, 0 failed. |
039742b to
b63ba8b
Compare
Summary
Binding a numeric, date or time C type to a Firebird text parameter and executing the statement many times silently corrupted or dropped rows, with
SQL_SUCCESSat every step. Found through duckdb/odbc-scanner#161: anodbc_copy_fromof 500 rows into a Firebird stored procedure committed 11 of them.Root cause
Two defects, plus a third found while testing:
getAdressFunctionpickedconv<Type>ToStringW, which writes UTF-16 code units into the Firebird buffer. Firebird stored them as bytes, with embedded NULs. Under CHARSET=NONE the slot maps to SQL_C_CHAR and the byte converter was used, which is why the bug did not reproduce there.setSqlLen(actual_length)shrinks the sqlvar, and a rebind re-described the parameter from it, sorecord->lengthcollapsed to the length of the first value and later values were truncated to one character. This is the rebind-per-row shape odbc-scanner uses.ODBCCONVERT_CHECKNULLsets the Firebird-side null flag on the NULL path and never clears it, so a value bound after a NULL on the same parameter was sent as NULL.Fix
Three commits, each with the tests that fail without it:
selectToStringConv: for a numeric / date / time C type bound to SQL_C_WCHAR, Firebird-side targets go through the byte variant. These converters emit ASCII only, so the bytes are correct in every charset; application-side targets keep the wide variant.ODBCCONVERT_CHECKNULLandODBCCONVERT_CHECKNULLWnow clear the Firebird-side null flag on the not-null path, as the two sibling macros already did.Sqlda::getPrecisionreads INPUT parameters from the prepare-time snapshot (orgSqlProperties), asgetColumnDisplaySizealready does. OUTPUT and SQL_ARRAY keep the live sqlvar.Short,Bigint,FloatandDoubleto VARCHAR, previously tests: cover sibling numeric→VARCHAR conversions #293.An earlier version of this PR rewrote the converters to write a VARYING length prefix into the buffer. That rested on a wrong theory:
setHeadSqlVarretypes every Firebird-side text parameter to SQL_TEXT at bind time, so no VARYING buffer ever reaches a converter. That code is gone.Tests
ParamConversionsTest.Issue161_*: stored procedure, DML, direct and rebind shapes, plus the CHAR and CHARACTER SET NONE corners of the rebind shape.ParamConversionsTest.NullThen*ValueOn*Param: a value bound after a NULL, for SLONG, SSHORT, SBIGINT and DOUBLE on VARCHAR and CHAR.NumericToVarcharTest: the four sibling loop tests.All of them skip on the FB6 snapshot, which aborts parameterized statements server-side (the limitation guarded elsewhere in the suite), and run on FB 3, 4 and 5.
#302 (describe INPUT parameters from the prepared type) is independent of this PR and can merge first.