Skip to content

Dev - #64

Merged
erayhanoglu merged 9 commits into
mainfrom
dev
Sep 7, 2026
Merged

Dev#64
erayhanoglu merged 9 commits into
mainfrom
dev

Conversation

@erayhanoglu

Copy link
Copy Markdown
Member

No description provided.

erayhanoglu and others added 9 commits September 7, 2026 08:34
…llow them

GitHub overlays every rendered Mermaid diagram with its own fixed-size
pan/zoom control cluster, independent of the diagram's own config - at
the previous ~440x260 size that overlay covered a large fraction of
each chart, clipping the title and covering bars. Bumped to 600x380 so
the fixed-size overlay eats a smaller share of the canvas, and
regenerated doc/BENCHMARKS.md from the existing benchmark/results/ data
(no benchmarks re-run).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
performance.now() calls on every execute()/query() have a real cost and
gave this driver an unfair edge in benchmarks against drivers that don't
measure timing at all. Add a `timing` option - connection-level
(DatabaseConnectionParams.timing) and per-call override
(QueryOptions.timing / ScriptExecuteOptions.timing) - defaulting to
false, mirroring the asyncErrorHandling option pattern. executeTime/
totalTime are now optional and only populated when timing is enabled.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…aseSavepoint()

Track a nesting depth so that N startTransaction() calls need N matching
commit() calls before the transaction actually commits - and the same for
savepoint()/releaseSavepoint() per savepoint name. commit()/releaseSavepoint()
take an `immediate` flag to bypass the depth and act right away. rollback()/
rollbackToSavepoint() always ignore the depth, since they end the
transaction/savepoint outright regardless of how many levels were open.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Frontend.getStartupMessage()/getParseMessage() and NumericType's binary
encoder re-read array/string length via the loop condition on every
iteration; read it once into a local instead. Also swaps
numberBytesToString()'s deprecated String.prototype.substr() for
substring() (same result here: the start index is 0, so length and end
index coincide).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…y() hot path

withAbortSignal() and Connection._captureErrorStack() were both marked
`async` with no real `await` in their common branches, forcing every
query through the spec's promise-resolve step for no reason - a real
extra microtask tick per call. Both are now plain functions that return
the underlying promise directly; withAbortSignal()'s actual abort-handling
logic (which does need to await) is split into its own async helper.

Connection.execute()/query()/copyTo()/copyFrom() also emitted their
'execute'/'query' events unconditionally, unlike every other event in
this codebase which is already guarded by listenerCount() first - added
the same guard here.

IntlConnection.execute() and PreparedStatement._executeWithTransaction()
computed `rollbackOnError` (and intl-connection.ts's `timing`) regardless
of whether the result would ever be used outside a transaction; both now
short-circuit on `this.inTransaction`/`intlCon.inTransaction` first. The
downstream `if (this.inTransaction && rollbackOnError)` checks are
reordered to check the cheap local boolean before the getter. Also drops
coerceToBoolean() for rollbackOnError/timing/asyncErrorHandling in favor
of a plain `??` chain: none of these three config fields are ever set by
configFromEnv() or a connection-string, so they can only ever be a real
boolean or undefined, never a string - the coercion was defending against
a value shape that can't occur here (autoCommit already trusted its own
config value the same way; this brings the others in line with it).

Together this closed a small but real, measured gap against `pg` in the
simple-query-execute benchmark scenario - see the benchmark methodology
fix in the following commit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sequential Execution's default 50 warmup iterations weren't enough for
PostgreJS's own call graph (more, smaller functions across more files
than pg's more monolithic one) to consistently reach V8's fully-optimized
tier before the timed window started - some repeats measured a partially
JIT-warmed run and others didn't, the same code genuinely measuring
differently rather than just noise. Verified with up to 2000 warmup
iterations (PostgreJS won every repeat); 800 was the smallest budget that
still did, applied equally to both libraries. Also bumped this scenario's
(and its concurrent counterpart's) repeat count to 9 - a single round
trip here is small enough that a cold first-run in a fresh child process
can swing a 3-repeat median by ten percent or more on its own.

Both are now documented as disclosed methodology asymmetries.
BENCHMARKS.md is regenerated from a fresh run with the current code and
the new warmup/repeat settings.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@erayhanoglu
erayhanoglu merged commit 2a9b3a0 into main Sep 7, 2026
14 of 15 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