Skip to content

feat: opt-in EXECUTE_ARRAY prepared batch path for executemany() #839

Closed

Description

@yeongseon

Problem and evidence

#836 measured a prototype EXECUTE_ARRAY (function code 21) path: one PREPARE, one request with every row's bound values, one CLOSE_REQ. At 10,000 rows, commit included, it takes 0.33-0.55x of the shipped executemany() for INSERT, UPDATE and DELETE and 0.15-0.16x for MERGE on CUBRID 11.0-11.4 (0.51-0.61x on 10.2). It is also 0.41-0.54x of the prepare-once loop. Experiment and raw data: cubrid-lab/cubrid-benchmark#23 (experiments/pycubrid-prepared-batch).

On 10.2, 11.0, 11.2 and 11.4 the server keeps the shipped batch's semantics:

  • every row is executed and only the failing row is undone;
  • autocommit commits each successful row;
  • per-row counts and the rowcount sum are identical.

The path differs in three ways:

So the decision in #836 is an opt-in path. The default stays the same.

Scope

  1. Add ExecuteArrayPacket (request: query handle, query timeout for protocol V4+, autocommit byte, one type/value pair per marker per row; reply: per-row count + OID or error code + message, shard id for V5+), with offline packet tests.
  2. Add an opt-in to executemany() on the sync and async cursors, for example a keyword-only prepared=True. Agree on the API in the design review first. For INSERT/UPDATE/DELETE/MERGE it runs PREPARE + EXECUTE_ARRAY, and it keeps the existing session-generation fence, the deferred-close handling (perf: release unclosed cursor handles in autocommit mode with a deferred close queue #488) and the reconnect rules.
  3. Keep the batch semantics: raise the first returned error, as today, with the same exception mapping, and set rowcount to the sum of the per-row counts.
  4. Reject values outside the prepared type set before anything is sent. Reject LOB handles when autocommit is on.
  5. Add integration tests on 10.2-11.4 for duplicate-key and conversion errors in the middle of a batch (autocommit on and off), rowcount, NULLs and SET values, matching the chore(performance): evaluate a prepared-statement batch path for executemany #836 probes. Update PERFORMANCE.md, API_REFERENCE.md, PARAMETER_BINDING.md, the Korean copies, CHANGELOG.md and RELEASE_POLICY.md (additive API).

Non-goals

  • Changing the default executemany() path.
  • Server-side protocol changes.

Links

Activity

  1. yeongseon commented on Oct 11, 2026

    @yeongseon
    ContributorAuthor

    Deferred until after the current stabilization release (2026-10-12). #815 admits only fixes for demonstrated regressions in the supported contract, plus the release-candidate work (#833). It does not admit "additional APIs … or opportunistic feature additions". This issue is a new opt-in feature or optional optimization, not a regression fix, so it waits for the next cycle. The evidence from #836 and #822 is already recorded (cubrid-benchmark#22, cubrid-benchmark#23, and the executemany() sections of docs/PERFORMANCE.md from #838 and #843). Nothing is lost by waiting.

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions