Skip to content

fix(utils/parseExecute): normalize sparse prepared parameters - #296

Closed
SimpleModder wants to merge 1 commit into
overextended:mainfrom
SimpleModder:fix/sparse-prepare-null
Closed

SimpleModder wants to merge 1 commit into
overextended:mainfrom
SimpleModder:fix/sparse-prepare-null

Conversation

@SimpleModder

Copy link
Copy Markdown

Problem

Prepared execution can pass an interior sparse positional value to mysql2 as undefined, which the driver rejects instead of binding SQL NULL.

A real reproducer is Ox Inventory 2.48.0: Inventory.Save represents an empty player inventory as Lua nil, and db.savePlayer calls:

MySQL.prepare.await('UPDATE players SET inventory = ? WHERE citizenid = ?', { inventory, owner })

The missing first value should bind NULL. Instead, the save raises Bind parameters must not contain undefined. To pass SQL NULL specify JS null. Because Inventory.Remove saves before clearing its entry, this also interrupts logout cleanup.

The independent parser regression uses a genuine hole:

const parameters = new Array(2);
parameters[1] = 'citizen-A'; // synthetic value

expect(0 in parameters).toBe(false);
expect(parseExecute(2, parameters as any)).toEqual([[null, 'citizen-A']]);

On unmodified v2.14.2 (286b8a28eed23203886d7c43bfec3f7cab19d6ad), this returns [[undefined, 'citizen-A']].

Fix

Move the existing indexed undefined-to-null normalization after row-shape conversion, applying it to flat and batch rows. The previous object-batch-only loop missed flat-array holes; rawExecute's trailing padding does not repair a hole inside the existing row length.

Only positions corresponding to placeholders are normalized. Explicit null, 0, false, empty strings, ordering and excess-parameter behavior are preserved. Eight regression tests cover sparse/undefined flat and batch values, short rows, falsey values, mixed object/array batches and excess entries. The diff contains only the parser and its unit-test file; no dependency or generated-artifact changes.

Validation

Revalidated on Windows with Bun 1.4.2 and Node 24.16.0:

  • Frozen install passed: bun install --frozen-lockfile --linker isolated; lockfile unchanged.
  • Genuine sparse regression fails on untouched source and passes after the patch.
  • Targeted file: 21 passed; complete unit suite: 146 passed, 0 failed (untouched baseline: 138 passed).
  • Changed-file oxfmt --check and bun run build passed, including the library TypeScript compilation.
  • bun run test:coverage exits 1 on both baseline and patch: unchanged profiler coverage is 80% functions / 82.76% lines, below the existing 85% threshold. Additional root/source TypeScript checks also reproduce identical baseline diagnostics. These checks are not claimed passing; thresholds and type configuration are unchanged.
  • Real FiveM for GTAV Enhanced integration (server b161/client b157, MariaDB 12.3.3, Qbox/Ox Inventory 2.48.0): two empty-inventory logout cycles successfully bound SQL NULL, removed the in-memory inventory entry and reloaded cleanly, with no provider/gameplay error.

@thelindat

Copy link
Copy Markdown
Member

The issue is that the build has not included the necessary patches to mysql2 which rebind undefined parameters to null.

@thelindat thelindat closed this Oct 6, 2026
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.

2 participants