Skip to content

Guard against insert() concatenating statements again (#294) - #573

Merged
GermanBluefox merged 1 commit into
masterfrom
fix/split-insert-statements
Oct 2, 2026
Merged

GermanBluefox merged 1 commit into
masterfrom
fix/split-insert-statements

Conversation

@GermanBluefox

Copy link
Copy Markdown
Contributor

The bug in #294 is already gone. This adds the regression test that was missing, rather than a fix.

What I checked

The issue was filed against 1.16.1 / 2.2.0 and reports a single query carrying two statements:

INSERT INTO `iobroker`.ts_counter (id, ts, val) VALUES (...);INSERT INTO `iobroker`.ts_number (...) VALUES (...);

Reproducing that exact batch — a counter datapoint, which writes to ts_counter and ts_number in the same flush — against the current builders:

dialect statements concatenated
mysql 2 no
postgresql 2 no
mssql 2 no
sqlite 2 no

And _insertValuesIntoDB() sends them one at a time through a recursive next(i), each with its own client.execute, over one borrowed connection. The whole path is sound.

What was missing

Nothing stops it from coming back. A list of queries where one would do is exactly the kind of thing someone "optimizes" by joining — and the only thing in the way was a comment on _insertValuesIntoDB().

test/testInsertStatements.js asserts per dialect that:

  • a batch with both counter and value rows yields one statement per table,
  • no statement carries a second one behind a semicolon (the trailing ; of a statement is not a match),
  • a 1200-row batch chunks into 500 / 500 / 200 without the chunks being glued back together.

Verification

12 cases, in the CI unit list. Control run with the old behaviour restored in the compiled mysql builder (return [query.join('')]):

with concatenation as shipped
mysql cases 3 failing 3 passing
total 9 passing, 3 failing 12 passing

177 unit tests pass overall, prettier --check clean.

One thing I did not change

The reported batch also shows a duplicate row — (5, 1676138387812, 53) twice in ts_counter. That is inherent to the counter-reset path: main.ts pushes both the old and the new state on a reset, so a value that is the "new" state of one reset is the "old" state of the next. It is harmless — ts_counter has no primary key, getCounterDiff selects DISTINCT, and equal consecutive values contribute nothing to the summed progression — so I left it alone rather than change counter semantics on the side.

#294 can be closed, and #304 with it if it is the same report, as the commenter suggests.

🤖 Generated with Claude Code

The bug reported in #294 is gone. The adapter used to emit

  INSERT INTO `iobroker`.ts_counter ...;INSERT INTO `iobroker`.ts_number ...;

as a single query, which MariaDB rejects: no driver here is configured for
multi-statement batches. Reproducing the reported batch against the current
builders gives two separate statements on all four dialects, and
_insertValuesIntoDB() sends them one at a time over one borrowed connection.

What was missing is anything that keeps it that way. Joining the statements
back together is the obvious "optimization" for someone looking at a list of
queries where one would do, and the only thing standing in the way was a
comment. test/testInsertStatements.js now asserts, per dialect, that a batch
holding both counter and value rows produces one statement per table, that no
statement carries a second one behind a semicolon, and that a 1200 row batch
chunks into 500/500/200 without the chunks being glued back together.

Verified by restoring the old behaviour in the compiled mysql builder: the
three mysql cases fail, and pass again once it is reverted.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@GermanBluefox
GermanBluefox merged commit ce17cf1 into master Oct 2, 2026
17 checks passed
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.

1 participant