1
0
mirror of https://github.com/MariaDB/server.git synced 2026-10-23 18:49:29 +03:00
Files
Lawrin Novitsky 6e064d0f24 MDEV-16670 Improve execute direct (prepare and execute) performance
The patch detects if the processed PREPARE command is first part of the
pipelined DIRECT+EXECUTE commands with stmt id -1 for execution. For
that the vio class has been extended with peek method that lets us
verify that the server has already received next command, it is EXECUTE
with stmt id -1, and the packet is minimally complete.

If it is so, the execution is forwarded to the fused prepare+execute path
as if it was a single command. It lets a statement's execute leg run before
any real prepare/check_prepared_statement() has happened and the prepare
leg does basically query parsing only. Several places
downstream assumed that had already happened, so give Query_arena a single
predicate, is_direct_exec_unresolved() - true only for the one-shot fused
pass that never went through a real prepare - and fix each broken
assumption against it:

* Query cache: a cached response is replayed without ever running
  mysql_execute_command(), so the buffered prepare-response hook never
  fires; conversely, populating the cache captures that hook's bytes too
  (net_real_write() sees the whole flushed buffer), poisoning the entry
  for unrelated later clients. Direct-exec statements now opt out of the
  query cache entirely (query_cache_is_applicable /
  lex->safe_to_cache_query, saved and restored around just that one
  execution). Covered by test_mdev_16670_qc_hit_hang and
  test_mdev_16670_qc_poison.

* Reprepare: a mid-execute reprepare() (e.g. ER_NEED_REPREPARE) swaps in
  a lex that DID go through a real prepare, so the statement is no
  longer "unresolved" once that happens - tracked via a new
  IS_DIRECT_EXEC_REPREPARED flag so the direct-exec special-casing only
  applies to the original pass.

* System versioning / periods: skip_setup_conds() treated the fused pass
  as an ordinary re-execution rather than a first resolution, so
  vers_setup_conds()/period_setup_conds() never ran - a versioned table
  or FOR PORTION OF statement used the wrong predicate. Now counted as
  "first execute" via is_direct_exec_unresolved(). Covered by
  test_mdev_16670_versioned_rows and test_mdev_16670_trigger_versioned.

* Unsupported statements check used to be done as part of the
  check_prepared_statement, has been moved to the new
  check_stmt_command_supported function called from the
  Prepared_statement::prepare method. Covered by
  test_mdev_16670_unsupported_ps.

* CALL statements and queries referencing a stored function are excluded
  from the optimized path (skip_direct_exec_optimization()): their nested
  sub-statements run with thd->cur_stmt still pointing at the outer
  statement, which would otherwise misfire the buffered prepare-response
  hook. Also, the stored function use would cause guaranteed re-prepare.
  The flag is reset for them after the query parsing. Covered by
  test_mdev_16670_demoted_function_call.

Also adds regression tests for the reply-pair on parse error
(test_mdev_16670_parse_error_reply_pair), SQLSTATE/errno preservation
through the execute-leg fallback (test_mdev_16670_fallback_sqlstate),
general_log coverage (test_mdev_16670_general_log), a statement killed
mid-fallback (test_mdev_16670_kill_during_fallback), and prebind usage of
mariadb_stmt_execute_direct() with real bound parameters
(test_mdev_16670_prebind_direct).

It's possible to compile with global variable opt_exec_direct that controls
if the optimization should be used. Its existence can be switched on
using cmake option WITH_DIRECT_EXEC_OPTIMIZE_SWITCH. By default it does
not exist, as it is believed to be unneeded in the general case.

create_and_prepare_stmt() helper added to perform common statement creation
routine, and erase_stmt_safely() helper - for cleaning in
create_and_prepare_stmt()'s prepare-failure cleanup, direct_exec_prepare_ok_fallback()'s
OOM branch, and mysqld_stmt_direct_execute()'s packet_error branch.

Assisted-by: Claude Sonnet 5
2026-10-15 00:39:19 +02:00
..
2025-04-29 11:18:00 +10:00
…
…
2026-06-15 16:53:03 +02:00
…
2024-12-11 14:46:43 +02:00