Skip to content

fix(parser): call typeCast for NULL values in the binary protocol (#3368)#4394

Open
Develop-KIM wants to merge 5 commits into
sidorares:masterfrom
Develop-KIM:fix/3368-typecast-null-execute
Open

fix(parser): call typeCast for NULL values in the binary protocol (#3368)#4394
Develop-KIM wants to merge 5 commits into
sidorares:masterfrom
Develop-KIM:fix/3368-typecast-null-execute

Conversation

@Develop-KIM

Copy link
Copy Markdown

Closes #3368.

execute() never ran a user typeCast on NULL columns: the binary row parser set them to null before typeCast could see them, while query() (text parser) passes NULL columns through typeCast. So the same typeCast behaved differently between the two protocols.

This routes NULL columns through typeCast when it's a function, matching the text parser. The wrapper handed to typeCast for a NULL is null-safe — its string()/buffer()/geometry() return null without reading the packet, since a NULL value carries no bytes in the binary row. When typeCast isn't a function (or is false), NULL stays null as before.

Applied to both the eval (binary_parser.js) and disableEval (static_binary_parser.js) paths.

@wellwelwel pointed at the same spot in the issue — thanks for the root-cause note.

Added test/integration/connection/test-typecast-null-execute.test.mts: it fails on master (typeCast skips the NULL column) and passes with the fix, and it also checks that a column following a NULL still decodes correctly (no packet desync). Full suite is green in both eval and STATIC_PARSER=1 modes.

…dorares#3368)

The binary row parser (execute) short-circuited NULL columns to `null`
before the user-supplied typeCast could run, so typeCast never saw NULL
values. The text row parser (query) has no such short-circuit and passes
NULL columns through typeCast, so the two protocols behaved differently.

Route NULL columns through typeCast when it is a function, using a
null-safe field wrapper whose accessors return null without reading from
the packet (a NULL value carries no bytes in the binary row). Applied to
both the eval and disableEval (static) binary parsers.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Jul 13, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.44262% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.52%. Comparing base (6316492) to head (75299ff).

Files with missing lines Patch % Lines
lib/parsers/binary_parser.js 94.28% 2 Missing ⚠️
lib/parsers/static_binary_parser.js 92.30% 2 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##           master    #4394   +/-   ##
=======================================
  Coverage   91.52%   91.52%           
=======================================
  Files          91       91           
  Lines       14768    14823   +55     
  Branches     1948     1957    +9     
=======================================
+ Hits        13516    13567   +51     
- Misses       1252     1256    +4     
Flag Coverage Δ
compression-0 90.81% <93.44%> (+<0.01%) ⬆️
compression-1 91.50% <93.44%> (+<0.01%) ⬆️
static-parser-0 90.25% <59.01%> (-0.13%) ⬇️
static-parser-1 90.52% <67.21%> (-0.11%) ⬇️
tls-0 91.06% <93.44%> (+<0.01%) ⬆️
tls-1 91.31% <93.44%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

await describe('Typecast NULL Execute (#3368)', async () => {
const connection = createConnection();

try {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no need to use try-catch/finally in a describe or it block in tests. The connection is already being declared in a scope above it, as is its ending, which ensures that the connection is closed even if the tests fail 🙋🏻‍♂️

Comment on lines +34 to +35
strict.deepEqual(seen, [null]); // typeCast ran for the NULL column
strict.equal(res[0].foo, '<was-null>'); // and its return value was used

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In testing, we can use messages to identify and visually highlight errors when debugging is necessary, rather than relying on comments, for example:

Suggested change
strict.deepEqual(seen, [null]); // typeCast ran for the NULL column
strict.equal(res[0].foo, '<was-null>'); // and its return value was used
strict.deepEqual(seen, [null], 'typeCast ran for the NULL column');
strict.equal(res[0].foo, '<was-null>', 'and its return value was used');
  • The same applies to the other comments accompanying the assertions 🙋🏻‍♂️

Comment thread lib/parsers/static_binary_parser.js Outdated
Comment thread lib/parsers/binary_parser.js Outdated
@wellwelwel

Copy link
Copy Markdown
Collaborator

Thanks @Develop-KIM! I left a few revisions. If you need any help, feel free to reach out 🙋🏻‍♂️

wellwelwel and others added 3 commits July 13, 2026 09:39
Drop the try/finally around the it() blocks -- the connection is created
and ended at the describe scope, so poku still closes it if a test fails --
and move the trailing assertion comments into assertion messages.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Develop-KIM

Copy link
Copy Markdown
Author

Thanks! Took care of the rest: dropped the try/finally and moved the assertion notes into messages.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

typeCast does not work for the execute method

3 participants