Home - Waterfall Grid T-Grid Console Builders Recent Builds Buildslaves Changesources - JSON API - About

Console View


Categories: connectors experimental galera main
Legend:   Passed Failed Warnings Failed Again Running Exception Offline No data

connectors experimental galera main
bsrikanth-mariadb
MDEV-42044: Check table privileges for the context recorder when trace is off
rusher
CONC-878: Skip the parameter definitions of a prepare response without copying them

mthd_stmt_get_param_metadata() built a MYSQL_DATA row set from the
parameter definition packets of the COM_STMT_PREPARE response and freed
it right away, since parameter metadata is not exposed. Read exactly
param_count packets and drop them, then the EOF packet, which is still
used to update the warning count and the server status as in
mthd_my_read_rows(). A missing or extra packet is reported as a
malformed packet.
Vladislav Vaintroub
MDEV-38741 Abort the running statement when its client disconnects

A watcher thread subscribes to the OS notification that a client has
gone (e.g. TCP FIN or RST for a TCP socket, a gone client process for a
named pipe) and aborts the running statement like KILL CONNECTION does.
Controlled by the global variable disconnect_watcher. Details in
PR#6035.

Assisted-by: Claude:claude-sonnet-5-5
sjaakola
MDEV-41597: GRANT ROLE is replicated before the privilege check

GRANT ROLE and REVOKE ROLE started TOI before mysql_grant_role()
checked whether the user may grant the role, and they could be
replicated, although they potentially could be refused on the
originating node later on.
On the other nodes the applier runs with a non-user security context,
and GRANT and REVOKE ROLE, will be applied causing the nodes' ACLs
to be diverged.

Begin TOI is moved inside mysql_grant_role(), after the role lookup and the
privilege check. The check is done by a new helper,
find_grantable_role(), which is also used for the second check under
LOCK_grant.

Under TOI the second check only looks up the role again and does not
repeat the privilege check. Otherwise an ACL change ordered between
the first check and the start of TOI (e.g. REVOKE ADMIN OPTION from
the granting user) could refuse the statement on the originating node
only, while the other nodes apply it. The pre-TOI check is therefore
final in a cluster, as it already is for the other ACL statements:
privileges are checked as of the start of the statement. Without
wsrep, or outside TOI, both checks are done as before.

A DEBUG_SYNC point, grant_role_before_toi, is added before TOI begins.

The test galera.MDEV-41597 checks that:
- a GRANT ROLE refused on node_1 is not applied on node_2
- when REVOKE ADMIN OPTION is ordered between the privilege check and
  the start of TOI, both nodes reach the same outcome
rusher
Merge branch '3.4-stmt-prepare-skip-params' into 3.4-perf
Jan Lindström
MDEV-31300 Suppress RESET SLAVE's Using_Gtid note across galera tests

RESET SLAVE/RESET SLAVE ALL emits a Note when it changes Using_Gtid,
and whether it does depends on the prior value, which can drift with
unrelated replication changes - galera_query_cache_invalidate,
galera_2_cluster and galera_gtid_2_cluster depend on it appearing.
Wrap every RESET SLAVE/RESET SLAVE ALL across the galera and
galera_3nodes suites in --disable_warnings/--enable_warnings, so no
test depends on that value.

Assisted-by: Claude:claude-4.6-sonnet
Pekka Lampio
MDEV-38999 followup: fix galera_sr.mysql-wsrep#215 regression

wsrep_must_sync_wait() now performs the causal wait on the first
real statement of an explicit transaction instead of skipping it as
soon as the transaction was merely BEGIN'd. mysql-wsrep#215
deliberately freezes node_1's local applier via a debug sync point
and then expects node_1's own first statement in the transaction to
proceed without waiting for that frozen apply - which the old,
buggy skip-on-BEGIN behaviour happened to allow, but the fix
correctly no longer does.

Disable wsrep_sync_wait for node_1's session before entering the
transaction, mirroring the same workaround node_1a's connection
already uses for the identical reason.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Elena Stepanova
MDEV-42198 Options from MTR opt files are added multiple times

Options from .opt files of included files were appended every time
the file was sourced, so they got repeated once per include path.
It caused unnecessary server restarts, and too long server command
lines lead to startup failures on Windows.

Now each file caches only its own .opt options plus an ordered list
of the files (itself and everything it sources) whose options apply,
each file listed once. The test's options are assembled from that list.
Options of included files still precede those of the including file.

Assisted-by: Claude:claude-opus-5-5
bsrikanth-mariadb
MDEV-42044: Do the table privilege check once for trace and recorder

Run opt_trace_disable_if_no_tables_access() once in
mysql_execute_command(), after the recorder is created, instead of
separately at trace start and in the recorder.

Remove opt_ctx_can_read_all_columns(). The recorder now relies on its
missing_priv flag and skips recording when it is set.
Sergei Petrunia
MDEV-42216: Optimizer Trace shows INSUFFICIENT_PRIVILEGES for sequences

opt_trace_disable_if_no_tables_access() checks if optimizer trace contents
would provide the user with something that otherwise the user won't have
access to. For tables, the requirement is that the user has per-table
SELECT right to the table (access to certain columns is not sufficient).

The check doesn't work for sequences that are used through NEXTVAL, CURVAL,
etc. They have a special permission check done at fix_fields() phase,
they do not have per-table vs per-column distinction.

Disable the check here. If the user doesn't have SELECT right for the
sequence, the query will fail and the trace will only list
"join_preparation" step.
Rex Johnston
MDEV-39492 PQ: a worker's join buffers are allocated on the worker's thread

In a debug build main.parallel_query_join aborted in the worker THD's
destructor: status_var.local_memory_used was not zero, and safemalloc
reported the join buffer and its field descriptors as freed by a worker
thread but allocated by the query thread.

The manager built each worker's JOIN_CACHE in setup_worker_jointabs() and
called init() there, on the query thread. init() allocates the buffer with
my_malloc(MY_THREAD_SPECIFIC) and the field descriptors on the cache's
JOIN's THD, the worker's. A thread-specific allocation is charged to
current_thd at the time, the manager's THD, while the free -- the buffer in
pwt_worker::close_tables(), the descriptors when the worker THD's mem_root
is torn down -- is credited to the worker's THD on the worker's thread. Each
THD's count ended up off by the buffer in opposite directions, and ~THD
asserts on a non-zero count.

The cache object is still built by the manager, on the statement's
mem_root, with the previous tab chained and the trackers attached. init()
now runs at the start of pwt_worker::execute_and_handoff(), on the worker's
thread, in tab order, before anything is locked, so a failure has nothing
to undo and is reported as out of memory through the worker's error path.
The allocation and the free are then made by the same thread and charged
to the same THD.

This commit was prepared with Claude Code (Fable 5.1), which reproduced the
assertion under mtr, resolved the safemalloc allocation stacks to
JOIN_CACHE::init() called from setup_worker_jointabs(), moved the init()
call to the worker thread, and verified the 24 parallel_query tests pass in
both protocols on the debug build.
Jan Lindström
MDEV-31300 Suppress RESET SLAVE's Using_Gtid note across galera tests

RESET SLAVE/RESET SLAVE ALL emits a Note when it changes Using_Gtid,
and whether it does depends on the prior value, which can drift with
unrelated replication changes - galera_query_cache_invalidate,
galera_2_cluster and galera_gtid_2_cluster depend on it appearing.
Wrap every RESET SLAVE/RESET SLAVE ALL across the galera and
galera_3nodes suites in --disable_warnings/--enable_warnings, so no
test depends on that value.

Assisted-by: Claude:claude-4.6-sonnet
Elena Stepanova
MDEV-41085 Enable MTR tests on Windows: rpl suite

rpl.rpl_row_mysqlbinlog fails because apparently the client command
line on Windows cannot interpret the literal cp932 string which is
passed to it. Since the point of the test is not how the original
INSERT happens, but how it further works while replaying the binlog,
it should be acceptable to insert a hex-encoded value
Susil
MDEV-41446 rpl.rpl_fragment_row_event_main: wait for binlog checkpoint

The test failed in buildbot with a result content mismatch: in Test
Case 7 the Binlog_checkpoint event naming the current binlog was
listed after the CREATE TABLE events instead of before them.

That event is logged asynchronously, normally by the binlog background
thread, once the previous binlog has been checkpointed, so its position
among the first events of a freshly rotated binlog depends on timing.
Test Case 7 lists the events of the binlog opened by the FLUSH LOGS at
the end of the previous test case, without waiting for that event. The
other listings of this test wait for it, in rpl_fragment_row_event.inc,
with include/wait_for_binlog_checkpoint.inc.

Wait for the checkpoint event in the same way before the CREATE TABLE
in Test Case 7.

The listed checkpoint rows can also differ in a second way.
show_binlog_events.inc skips the first Binlog_checkpoint of a binlog,
which normally names the previous binlog. If a FLUSH LOGS runs before
the background thread has logged the checkpoint of the previous one,
that skipped event names an older binlog, and the checkpoint naming the
previous binlog is listed as an extra row. The cleanup at the end of
rpl_fragment_row_event.inc runs FLUSH LOGS shortly after the FLUSH LOGS
of its last test phase, without waiting in between. Wait for the
checkpoint before each of the three cleanup FLUSH LOGS (one per server).

The recorded result is unchanged.

Verified with the debug point
inject_binlog_background_thread_before_mark_xid_done, which holds back
one checkpoint event: with the event of the cleanup FLUSH LOGS held
back, only the wait in Test Case 7 prevents the diff reported in the
bug; with the event of the FLUSH LOGS before it held back, only the
cleanup waits prevent the extra row. Both changes together pass in both
cases.

The same ordering variance failed binlog.binlog_checkpoint, see
MDEV-29607.

Assisted-by: Claude:claude-sonnet-5-5
bsrikanth-mariadb
MDEV-42044: Fix Optimizer Context privilege checks

Follow-up to the previous MDEV-42044 commit:

* opt_trace_disable_if_no_security_context_access() returned early when
  the optimizer trace was not started, so a context recorded through
  DEFINER routines, triggers or views was never marked as restricted.
  Mark the recorder before that return.
* Skip the access checks when built with NO_EMBEDDED_ACCESS_CHECKS.
* Factor the repeated "missing privilege" code in opt_trace.cc into
  helpers.

Tests: assert the "Insufficient privileges" output, and add cases for
column-level grants, an unexecuted function, a DEFINER trigger,
optimizer_trace=ON, and a privileged user who still gets a full context.
Vladislav Vaintroub
MDEV-42049 MTR server-cert.pem has no DNS SAN, fails on OpenSSL 4.1

OpenSSL 4.1 no longer matches a host name against the subject CN when
the certificate has no DNS subjectAltName. Re-sign server-cert.pem with
subjectAltName=DNS:localhost, and add it to generate-ssl-certs.sh.

main.ssl_7937, main.ssl_system_ca and rpl.rpl_ssl1 fail with
OpenSSL 4.1 without this change.

The SHA1 fingerprint changes. main.ssl_fp (11.4+) must be updated when
merging up: F1:D0:08:AF:A1:D2:F4:15:79:B4:39:06:41:F4:20:96:F1:90:A9:65
-> AE:F0:29:15:F1:9E:A0:A0:69:FB:83:20:B9:30:E3:DE:2F:25:2C:37

Assisted-by: Claude:claude-sonnet-5-5
bsrikanth-mariadb
MDEV-42044: Create the context recorder before the trace privilege checks
Vladislav Vaintroub
MDEV-38741 mtr: do not suppress the reason of a client disconnect

The global suppressions of "Aborted connection", in mariadb-test-run.pl
and mtr_warnings.sql, hid the line that the client disconnect watcher
writes when it aborts a command: "Aborted connection N to db: 'x' user:
'u' host: 'h' (Client disconnected)". Nothing showed when the watcher
aborted a connection that it should have left alone. main.locale found
one, because its server log is in German and the English entry did not
match.

Make the two entries skip a line that ends in "(Client disconnected)".
Other aborted connections are suppressed as before. The tests that drop
a client on purpose accept the reason with mtr.add_suppression(),
details in PR#6035.

Assisted-by: Claude:claude-sonnet-5-5
Alexander Barkov
MDEV-39563 Implement UPDATE ... RETURNING ... INTO

Adding support for UPDATE .. RETURNING .. INTO queries.

For example:

  UPDATE t1 SET a=10,b=20 RETURNING a,b INTO va,vb;
  UPDATE t1 SET a=10,b=20 RETURNING a,b INTO @a,@b;

Limitations:
1. These types of queries:
  - REPLACE .. RETURNING .. INTO
  - DELETE .. RETURNING .. INTO
  - INSERT .. RETURNING .. INTO
  do not work - they return an error.
  They will be implemented separately, when needed.

2. UPDATE..RETURNING..INTO with --binlog_format=statement is not allowed
  and an error is raised.

3. Using OLD_VALUE(col) inside UPDATE..RETURNING..INTO is not allowed
  and an error is raised.

4. Multi-table updates, as well as single table updates with a subquery
  to the same table in WHERE (which get converted to multi-table) do
  not work and an error is raised.

5. UPDATE IGNORE .. RETURNING .. INTO is not supported for storage engines
  that can send updates later (Spider), because it is not known if the row
  was rejected. ER_NOT_SUPPORTED_YET is raised.

Notes:

1. ANALYZE and EXPLAIN
  Both
    ANALYZE UPDATE .. RETURNING .. INTO ..
    EXPLAIN UPDATE .. RETURNING .. INTO ..
  return this error:
    'RETURNING..INTO' is not allowed in this context

2. Behavior on no data and on multiple rows

  Only the rows that were actually changed are processed. A row that matches
  the WHERE condition but needs no update is not changed, so it is not
  returned by plain RETURNING either.

  Situation                    | RETURNING        | RETURNING .. INTO
  -----------------------------+------------------+-----------------------------
  Empty table, WHERE matches  | empty set        | Warning ER_SP_FETCH_NO_DATA,
  nothing, WHERE 1=0, LIMIT 0  |                  | target is not changed

  One row matches, needs no    | empty set        | Warning ER_SP_FETCH_NO_DATA,
  update                      |                  | target is not changed

  Several rows match, none    | empty set        | Warning ER_SP_FETCH_NO_DATA,
  needs an update              |                  | target is not changed
                              |                  | (no ER_TOO_MANY_ROWS)

  One row matches and is      | that row        | Target is assigned
  changed                      |                  |

  Several rows match, exactly  | that row        | Target is assigned from
  one changes                  |                  | that row

  Two or more rows change      | all changed rows | ER_TOO_MANY_ROWS at the 2nd
                              |                  | changed row (not updated)

  Notes:
  - The warning is never an error: not in the strict mode, not with
    sql_mode='', not with IGNORE. The INTO targets keep their old values.
    In stored routines the warning activates NOT FOUND handlers.
  - This is the same for all storage engines, including those that quickly
    know the table is empty and use a degenerated plan (e.g. MyISAM).
  - After ER_TOO_MANY_ROWS, transactional engines roll back the statement,
    non-transactional engines keep the rows updated before the error
    (the second changed row is not updated).
  - The targets can be user variables, SP variables, ROW variables
    and ROW fields.

3. Behavior on VIEW with CHECK OPTION

  The "too many rows" check is done after the view's CHECK OPTION check.
  With UPDATE IGNORE, a row rejected by WITH CHECK OPTION is skipped
  (with a warning) and does not count as an updated row, so
  UPDATE IGNORE .. RETURNING .. INTO does not raise ER_TOO_MANY_ROWS
  if only one row is actually updated.

4. Behavior of UPDATE IGNORE .. RETURNING .. INTO

  With IGNORE, a row rejected by the storage engine (a duplicate key,
  no partition for the new values, a foreign key violation) is not changed,
  so it is not counted as a changed row, in the same way as for plain
  UPDATE IGNORE .. RETURNING. The engine decides about this in
  ha_update_row(), so the check for the second changed row is done after it:
  - Transactional engines: ER_TOO_MANY_ROWS rolls back the statement.
  - Non-transactional engines: the second row is updated back (including
    its BLOB values) before ER_TOO_MANY_ROWS is raised. Both updates are
    written to the binary log.
  Without IGNORE the check is done before the second row is updated.

Helper changes:

1. The grammar in analyze_stmt_command was changed to have
  LEX::analyze_stmt set to true earlier, so
  LEX::set_returning_into_result() already knows if this
  is an ANALYZE statement.

2. The Sql_cmd_update constructor is now called earlier in the grammar,
  to be able to call Sql_cmd_update::set_with_old_value_items()
  in the SET and RETURNING clauses.

3. Sql_cmd_dml::lex is now set during the constructor time.
  It makes things easier:
  - Sql_cmd_update::returns_result_set() needs the lex.
  - Sql_cmd_delete::orig_multitable and Sql_cmd_update::orig_multitable
    are not needed any more.
    They were used only in Sql_cmd_delete::sql_command_code() and
    Sql_cmd_update::sql_command_code().
    Sql_cmd_dml::sql_command_code() now returns lex->sql_command.
    The overrides Sql_cmd_delete::sql_command_code() and
    Sql_cmd_update::sql_command_code() were removed.

4. A new virtual method handler::update_may_be_deferred() tells if
  ha_update_row() can return success for a row that the engine rejects
  later. It is overridden in Spider and in ha_partition.

This commit also fixes bugs found during testing:
- MDEV-41262 ER_TOO_MANY_ROWS should be checked after CHECK OPTION in view
  while Update Returning Into
- MDEV-41265 SELECT/ UPDATE RETURNING INTO a single row-field fails with
  ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT, even though the column count matches
  This bug was also fixed in 12.3.4.
- MDEV-41260 Misleading message text "uses a LIMIT clause" after Update
  Returning Into
- MDEV-42212 UPDATE ... RETURNING ... INTO raises ER_TOO_MANY_ROWS on InnoDB
  when the second found row needs no update
- MDEV-42156 UPDATE IGNORE ... RETURNING ... INTO fails with
  ER_TOO_MANY_ROWS when the second row is skipped by IGNORE (duplicate key)
Alexander Barkov
MDEV-39563 Implement UPDATE ... RETURNING ... INTO

Adding support for UPDATE .. RETURNING .. INTO queries.

For example:

  UPDATE t1 SET a=10,b=20 RETURNING a,b INTO va,vb;
  UPDATE t1 SET a=10,b=20 RETURNING a,b INTO @a,@b;

Limitations:
1. These types of queries:
  - REPLACE .. RETURNING .. INTO
  - DELETE .. RETURNING .. INTO
  - INSERT .. RETURNING .. INTO
  do not work - they return an error.
  They will be implemented separately, when needed.

2. UPDATE..RETURNING..INTO with --binlog_format=statement is not allowed
  and an error is raised.

3. Using OLD_VALUE(col) inside UPDATE..RETURNING..INTO is not allowed
  and an error is raised.

4. Multi-table updates, as well as single table updates with a subquery
  to the same table in WHERE (which get converted to multi-table) do
  not work and an error is raised.

5. A row that looks changeable but is rejected by the engine (IGNORE with
  a duplicate key, no partition or foreign key violation) is still counted
  as found, so ER_TOO_MANY_ROWS can be raised while plain RETURNING
  returns only one row. Engines with batched updates (Spider) may return
  a row that was not changed. See MDEV-42156.

Notes:

1. ANALYZE and EXPLAIN
  Both
    ANALYZE UPDATE .. RETURNING .. INTO ..
    EXPLAIN UPDATE .. RETURNING .. INTO ..
  return this error:
    'RETURNING..INTO' is not allowed in this context

2. Behavior on no data and on multiple rows

  Only the rows that were actually changed are processed. A row that matches
  the WHERE condition but needs no update is not changed, so it is not
  returned by plain RETURNING either.

  Situation                    | RETURNING        | RETURNING .. INTO
  -----------------------------+------------------+-----------------------------
  Empty table, WHERE matches  | empty set        | Warning ER_SP_FETCH_NO_DATA,
  nothing, WHERE 1=0, LIMIT 0  |                  | target is not changed

  One row matches, needs no    | empty set        | Warning ER_SP_FETCH_NO_DATA,
  update                      |                  | target is not changed

  Several rows match, none    | empty set        | Warning ER_SP_FETCH_NO_DATA,
  needs an update              |                  | target is not changed
                              |                  | (no ER_TOO_MANY_ROWS)

  One row matches and is      | that row        | Target is assigned
  changed                      |                  |

  Several rows match, exactly  | that row        | Target is assigned from
  one changes                  |                  | that row. But see
                              |                  | Limitation 5.

  Two or more rows change      | all changed rows | ER_TOO_MANY_ROWS at the 2nd
                              |                  | changed row (not updated)

  Notes:
  - The warning is never an error: not in the strict mode, not with
    sql_mode='', not with IGNORE. The INTO targets keep their old values.
    In stored routines the warning activates NOT FOUND handlers.
  - This is the same for all storage engines, including those that quickly
    know the table is empty and use a degenerated plan (e.g. MyISAM).
  - After ER_TOO_MANY_ROWS, transactional engines roll back the statement,
    non-transactional engines keep the rows updated before the error.
  - The targets can be user variables, SP variables, ROW variables
    and ROW fields.

3. Behavior on VIEW with CHECK OPTION

  The "too many rows" check is done after the view's CHECK OPTION check.
  With UPDATE IGNORE, a row rejected by WITH CHECK OPTION is skipped
  (with a warning) and does not count as an updated row, so
  UPDATE IGNORE .. RETURNING .. INTO does not raise ER_TOO_MANY_ROWS
  if only one row is actually updated.

Helper changes:

1. The grammar in analyze_stmt_command was changed to have
  LEX::analyze_stmt set to true earlier, so
  LEX::set_returning_into_result() already knows if this
  is an ANALYZE statement.

2. The Sql_cmd_update constructor is now called earlier in the grammar,
  to be able to call Sql_cmd_update::set_with_old_value_items()
  in the SET and RETURNING clauses.

3. Sql_cmd_dml::lex is now set during the constructor time.
  It makes things easier:
  - Sql_cmd_update::returns_result_set() needs the lex.
  - Sql_cmd_delete::orig_multitable and Sql_cmd_update::orig_multitable
    are not needed any more.
    They were used only in Sql_cmd_delete::sql_command_code() and
    Sql_cmd_update::sql_command_code().
    Sql_cmd_dml::sql_command_code() now returns lex->sql_command.
    The overrides Sql_cmd_delete::sql_command_code() and
    Sql_cmd_update::sql_command_code() were removed.

This commit also fixes bugs found during testing:
- MDEV-41262 ER_TOO_MANY_ROWS should be checked after CHECK OPTION in view
  while Update Returning Into
- MDEV-41265 SELECT/ UPDATE RETURNING INTO a single row-field fails with
  ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT, even though the column count matches
  This bug was also fixed in 12.3.4.
- MDEV-41260 Misleading message text "uses a LIMIT clause" after Update
  Returning Into
- MDEV-42212 UPDATE ... RETURNING ... INTO raises ER_TOO_MANY_ROWS on InnoDB
  when the second found row needs no update
bsrikanth-mariadb
MDEV-42044: Do the table privilege check once for trace and recorder

Run opt_trace_disable_if_no_tables_access() once in
mysql_execute_command(), after the recorder is created, instead of
separately at trace start and in the recorder.

Remove opt_ctx_can_read_all_columns(). The recorder now relies on its
missing_priv flag and skips recording when it is set.
Sergei Petrunia
MDEV-42044: I_S.OPTIMIZER_CONTEXT exposes rows, DDL and statistics ...

Optimizer Context has DDLs of used tables and VIEWs, table statistics,
and even captured table rows which include all, even the columns that
the query doesn't read.

The user running the query might not have access to some of this
information. Making it available in the optimizer context would create
an opportunity to bypass the security controls.

There is a similar issue in the Optimizer Trace. It is solved by not
producing optimizer trace if it would expose data that's not available
otherwise.

Piggy-back on the Optimizer Trace security checks and do the same:
disallow saving Optimizer Context if it can contain information that
the caller would not have access to.

In addition to Optimizer Trace's check, add
opt_ctx_can_read_all_columns() and check that when we're about to
dump a full table row into the optimizer context.
Elena Stepanova
MDEV-42200 main.mysqlbinlog_stmt_compressed depends on previous tests
Hemant Dangi
MDEV-41388: Avoid causal-wait timeout in galera.MDEV-34117

Issue: After re-enabling wsrep_on, the test's local session-variable
checks (SET/SELECT @@wsrep_trx_fragment_unit/size) pay the suite's
default causal-read wait (wsrep_sync_wait=15). On loaded/slow CI
builders (aarch64-debian-12, s390x-ubuntu-2204) this occasionally
exceeds the 90s causal_read_timeout and fails with
ER_LOCK_WAIT_TIMEOUT, even though none of these checks depend on
cross-node consistency.

Solution: Disable wsrep_sync_wait for this narrow window of
local-only checks, matching the existing on/off pattern used in
galera_concurrent_test.inc and galera_mdev38999_cleanup.inc, and
restore it before the later statements that do read data replicated
from node_1.

Assisted-by: Claude:claude-sonnet-5
Marko Mäkelä
Merge
Mohammad Tafzeel Shams
MDEV-37467: InnoDB Instant ALTER TABLE is not crash safe

The hidden metadata record of instant ALTER TABLE was not written
crash-safely, and recovery could fail to roll it back. These are
independent problems.

First, the metadata record may include externally stored BLOB
metadata. The existing BLOB storage path in
btr_store_big_rec_extern_fields() writes the clustered index record
first, with zero BLOB pointers, and only fills in the BLOB pointers
afterwards. If the server is killed after the mini-transaction that
wrote the (incomplete) metadata record was durably committed, but
before the BLOB pointers were written, the table could become
inaccessible on recovery.

Make metadata BLOB storage crash-safe by writing the BLOB pages and
computing their pointers before the metadata record itself is
inserted or updated, so that the record is always written with
complete BLOB pointers. If the server is killed before the metadata
record is written, the already-written BLOB pages are merely
orphaned, which is safe.

Second, trx_undo_report_row_operation() writes the undo log record in
a mini-transaction of its own, which is committed before the
mini-transaction that writes the metadata record. Because
innobase_instant_try() had already updated SYS_COLUMNS and SYS_TABLES
in earlier mini-transactions, a kill in between left a durable undo
log record for the table while the metadata record was unchanged. On
recovery, trx_resurrect_table_locks() would then load the table
definition before the incomplete transaction was rolled back. The
data dictionary described the table as it would be after the
operation, while the metadata record still described it as it was
before, and btr_cur_instant_init() failed on that disagreement.

Write the undo log record of the metadata record in the same
mini-transaction that inserts or updates the record, so that the two
cannot be separated by a crash: until that mini-transaction is
committed, neither of them is durable.

An undo log record is never split between pages. If the DEFAULT
values of the columns being added are large enough that the undo log
record for updating the metadata record would not fit on one page,
innobase_instant_try() would fail. Determine this before the operation
starts, so that it can be performed by another algorithm instead.

Third, the table definition that recovery loads need not correspond to
the metadata record. dict_load_table_one() reads the committed version
of the SYS_TABLES record, and escalates to READ UNCOMMITTED only when
it finds a SYS_COLUMNS record that was written by a transaction that is
still active. The number of SYS_COLUMNS records that dict_load_columns()
reads is derived from SYS_TABLES.N_COLS, which was read from the
committed version. The record of a column that the operation appended is
located after that many records, so it is never read and the operation
goes unnoticed. Only an instant ALTER TABLE that merely appends columns
can escape this way: ADD COLUMN ... FIRST, DROP COLUMN and column
reordering rewrite the SYS_COLUMNS records of already existing columns.

Load the committed table definition first, and the uncommitted one only
if btr_cur_instant_init() reports that the committed definition does not
describe the metadata record. Reading the uncommitted definition
unconditionally would be wrong in the opposite case: if the operation
had not updated the metadata record yet, the definition would describe
columns that the record does not comprise, and btr_cur_instant_init()
would request the default value of a column that does not have one.

Fourth, the rollback writes a metadata record that comprises fewer
fields than the table definition describes, because
btr_cur_trim_alter_metadata() shortens it to the number of fields that
it comprised before the operation. That number determines the size of
the null flag bitmap, and hence the position of the array of field
lengths. rec_init_offsets_comp_ordinary() derives it from the record,
while the two functions that write the record derived it from the table
definition and asserted that the two agree.

- btr_store_big_rec_metadata():
  New function to store the off-page columns of a metadata record
  ahead of time. Each BLOB page is allocated and linked in its own
  mini-transaction, and the resulting BLOB pointers are written
  directly into the (heap-resident) index entry. On failure, it frees
  any pages it already allocated and resets the pointers to zero.

- btr_free_big_rec_metadata():
  New helper to free the BLOB pages written by
  btr_store_big_rec_metadata() and reset the entry's BLOB pointers
  to zero, used both on failure inside that function and by its
  callers when the metadata record ends up not being written.

- row_ins_clust_index_entry_low():
  For a metadata entry that needs external storage, convert it to a
  big record and call btr_store_big_rec_metadata() (with
  log_free_check() allowed, since no latches are held yet) before
  inserting the record. On failure, free the metadata BLOBs and
  convert the entry back.

- btr_cur_pessimistic_update():
  When updating a metadata record that requires external storage,
  call btr_store_big_rec_metadata() (without log_free_check(),
  since index and page latches are held) before modifying the record,
  and free the temporary big_rec vector via btr_free_big_rec_metadata()
  or dtuple_big_rec_free() on the various failure/success paths.

- btr_cur_optimistic_insert():
  Remove the special-cased jump to convert_big_rec for metadata
  entries, since their BLOBs are now always stored ahead of time by
  the caller; assert that a metadata entry never needs external
  storage at this point.

- innobase_instant_try():
  Since btr_cur_pessimistic_update() now stores metadata BLOBs
  before updating the record, big_rec is always NULL here; assert
  this instead of calling btr_store_big_rec_extern_fields().

- trx_undo_report_row_operation():
  New parameter caller_mtr. If it is specified, the undo log record
  is written in that mini-transaction, which is never committed or
  restarted here. An undo log page is added within the same
  mini-transaction if the record does not fit on the current one. A
  temporary table never uses the caller's mini-transaction, because
  that would require changing its logging mode. All other callers
  pass NULL and are unaffected.
  Encapsulate the parameters that describe the row change
  (clust_entry, update, cmpl_info, rec, offsets) in the new type
  trx_undo_row_op, which of the fields are set depends on the
  operation, which the type documents.

- btr_cur_ins_lock_and_undo(), btr_cur_upd_lock_and_undo():
  For an instant ALTER TABLE metadata record, pass the
  mini-transaction that is going to insert or modify the record.

- trx_undo_max_rec_size():
  New function to determine the maximum size of an undo log record,
  that is, the space available on an empty undo log page.

- ha_innobase::check_if_supported_inplace_alter():
  Refuse ALGORITHM=INSTANT if the metadata record already exists and
  the undo log record for updating it would exceed
  trx_undo_max_rec_size(). trx_undo_page_report_modify() stores the
  DEFAULT value of each column that is being added in that record in
  full, inline. No such limit applies when the metadata record is
  being inserted, because trx_undo_page_report_insert() writes
  TRX_UNDO_INSERT_METADATA and no field data.

- dict_load_table_one():
  Load the committed table definition first, and the uncommitted one
  only if btr_cur_instant_init() reports that the committed definition
  does not describe the clustered index metadata record.
  dict_load_columns() cannot detect this, because the number of
  SYS_COLUMNS records that it reads is derived from SYS_TABLES.N_COLS,
  and a column that the operation appended is located after that many
  records. A table that an uncommitted transaction is rebuilding is
  excluded, because the committed definition is the one that
  corresponds to its clustered index.

- btr_cur_instant_init(), btr_cur_instant_init_low():
  Determine the number of fields of the metadata record in the same way
  as rec_init_offsets_comp_ordinary() does, and refuse the table if it
  disagrees with the table definition. rec_get_offsets() would otherwise
  request the default value of a column that does not have one. New
  parameter quiet for a caller that is going to try another table
  definition, so that an attempt which is not the final one is not
  reported. Mark the table as unreadable on these failures, like the
  other ones in that function do, because dict_load_table_one() asserts
  that a readable table is not corrupted.

- dict_sys_tables_rec_read():
  Store the fields that are read in the new type dict_sys_tables_rec,
  instead of in separate output parameters. A caller that does not want
  a delete-marked record to be reported as not found used to indicate
  that by specifying trx_id as nullptr; that is now the parameter
  skip_deleted.

- trx_undo_add_page():
  Correct the documented restriction on the mini-transaction of the
  caller.

- rec_get_converted_size_comp_prefix_low(),
  rec_convert_dtuple_to_rec_comp():
  For a record that includes a metadata BLOB, determine the number of
  nullable fields from the tuple, by way of
  dict_index_t::get_n_nullable(), and not from
  dict_index_t::n_nullable. This is what
  rec_init_offsets_comp_ordinary() does, and it is equivalent for a
  tuple that comprises all fields of the index. Relax the assertions
  that required the tuple to comprise all of them.

- Added test in innodb.instant_alter and innodb.instant_alter_crash
  to test normal working of INSTANT ALTER, crash safety and full table.
Hemant Dangi
MDEV-41388: Avoid causal-wait timeout in galera.MDEV-34117

Issue: After re-enabling wsrep_on, the test's local session-variable
checks (SET/SELECT @@wsrep_trx_fragment_unit/size) pay the suite's
default causal-read wait (wsrep_sync_wait=15). On loaded/slow CI
builders (aarch64-debian-12, s390x-ubuntu-2204) this occasionally
exceeds the 90s causal_read_timeout and fails with
ER_LOCK_WAIT_TIMEOUT, even though none of these checks depend on
cross-node consistency.

Solution: Disable wsrep_sync_wait for this narrow window of
local-only checks, matching the existing on/off pattern used in
galera_concurrent_test.inc and galera_mdev38999_cleanup.inc, and
restore it before the later statements that do read data replicated
from node_1.

Assisted-by: Claude:claude-sonnet-5
Elena Stepanova
MDEV-41085 Enable MTR tests on Windows: rpl suite

rpl.rpl_read_old_relay_log_info fails because the test overrrides
relay-log.info with the Linux-style ./slave-relay-bin.000001,
while Windows uses the format with backslashes, .\slave-relay-bin.000001
bsrikanth-mariadb
MDEV-42186: Info leak with optimizer_replay_context

Replaying a context for a query on a view made the server push
warnings naming the underlying tables, their indexes and the view's
hidden range constants, even if the user could not read those tables.

On the first use of the replay, check that the invoker can read all
columns of every base table in the statement. If any table fails the
check, drop the context, so nothing is replayed and no warnings are
produced.
Jan Lindström
MDEV-41996 galera.galera_change_user fails: extra change_user line

The test calls change_user three times. The result file recorded the
echoed "change_user user1,,;" line for the first two calls but not
for the third one, added by MDEV-41385. The test output has the line
after "# After COM_CHANGE_USER".

Add the missing line to the result file.

Assisted-by: Claude:claude-4.6-sonnet
Alexander Barkov
MDEV-39563 Implement UPDATE ... RETURNING ... INTO

Adding support for UPDATE .. RETURNING .. INTO queries.

For example:

  UPDATE t1 SET a=10,b=20 RETURNING a,b INTO va,vb;
  UPDATE t1 SET a=10,b=20 RETURNING a,b INTO @a,@b;

Limitations:
1. These types of queries:
  - REPLACE .. RETURNING .. INTO
  - DELETE .. RETURNING .. INTO
  - INSERT .. RETURNING .. INTO
  do not work - they return an error.
  They will be implemented separately, when needed.

2. UPDATE..RETURNING..INTO with --binlog_format=statement is not allowed
  and an error is raised.

3. Using OLD_VALUE(col) inside UPDATE..RETURNING..INTO is not allowed
  and an error is raised.

4. Multi-table updates, as well as single table updates with a subquery
  to the same table in WHERE (which get converted to multi-table) do
  not work and an error is raised.

5. UPDATE IGNORE .. RETURNING .. INTO is not supported for storage engines
  that can send updates later (Spider), because it is not known if the row
  was rejected. ER_NOT_SUPPORTED_YET is raised.

Notes:

1. ANALYZE and EXPLAIN
  Both
    ANALYZE UPDATE .. RETURNING .. INTO ..
    EXPLAIN UPDATE .. RETURNING .. INTO ..
  return this error:
    'RETURNING..INTO' is not allowed in this context

2. Behavior on no data and on multiple rows

  Only the rows that were actually changed are processed. A row that matches
  the WHERE condition but needs no update is not changed, so it is not
  returned by plain RETURNING either.

  Situation                    | RETURNING        | RETURNING .. INTO
  -----------------------------+------------------+-----------------------------
  Empty table, WHERE matches  | empty set        | Warning ER_SP_FETCH_NO_DATA,
  nothing, WHERE 1=0, LIMIT 0  |                  | target is not changed

  One row matches, needs no    | empty set        | Warning ER_SP_FETCH_NO_DATA,
  update                      |                  | target is not changed

  Several rows match, none    | empty set        | Warning ER_SP_FETCH_NO_DATA,
  needs an update              |                  | target is not changed
                              |                  | (no ER_TOO_MANY_ROWS)

  One row matches and is      | that row        | Target is assigned
  changed                      |                  |

  Several rows match, exactly  | that row        | Target is assigned from
  one changes                  |                  | that row

  Two or more rows change      | all changed rows | ER_TOO_MANY_ROWS at the 2nd
                              |                  | changed row (not updated)

  Notes:
  - The warning is never an error: not in the strict mode, not with
    sql_mode='', not with IGNORE. The INTO targets keep their old values.
    In stored routines the warning activates NOT FOUND handlers.
  - This is the same for all storage engines, including those that quickly
    know the table is empty and use a degenerated plan (e.g. MyISAM).
  - After ER_TOO_MANY_ROWS, transactional engines roll back the statement,
    non-transactional engines keep the rows updated before the error
    (the second changed row is not updated).
  - The targets can be user variables, SP variables, ROW variables
    and ROW fields.

3. Behavior on VIEW with CHECK OPTION

  The "too many rows" check is done after the view's CHECK OPTION check.
  With UPDATE IGNORE, a row rejected by WITH CHECK OPTION is skipped
  (with a warning) and does not count as an updated row, so
  UPDATE IGNORE .. RETURNING .. INTO does not raise ER_TOO_MANY_ROWS
  if only one row is actually updated.

4. Behavior of UPDATE IGNORE .. RETURNING .. INTO

  With IGNORE, a row rejected by the storage engine (a duplicate key,
  no partition for the new values, a foreign key violation) is not changed,
  so it is not counted as a changed row, in the same way as for plain
  UPDATE IGNORE .. RETURNING. The engine decides about this in
  ha_update_row(), so the check for the second changed row is done after it:
  - Transactional engines: ER_TOO_MANY_ROWS rolls back the statement.
  - Non-transactional engines: the second row is updated back (including
    its BLOB values) before ER_TOO_MANY_ROWS is raised. Both updates are
    written to the binary log.
  Without IGNORE the check is done before the second row is updated.

Helper changes:

1. The grammar in analyze_stmt_command was changed to have
  LEX::analyze_stmt set to true earlier, so
  LEX::set_returning_into_result() already knows if this
  is an ANALYZE statement.

2. The Sql_cmd_update constructor is now called earlier in the grammar,
  to be able to call Sql_cmd_update::set_with_old_value_items()
  in the SET and RETURNING clauses.

3. Sql_cmd_dml::lex is now set during the constructor time.
  It makes things easier:
  - Sql_cmd_update::returns_result_set() needs the lex.
  - Sql_cmd_delete::orig_multitable and Sql_cmd_update::orig_multitable
    are not needed any more.
    They were used only in Sql_cmd_delete::sql_command_code() and
    Sql_cmd_update::sql_command_code().
    Sql_cmd_dml::sql_command_code() now returns lex->sql_command.
    The overrides Sql_cmd_delete::sql_command_code() and
    Sql_cmd_update::sql_command_code() were removed.

4. A new virtual method handler::update_may_be_deferred() tells if
  ha_update_row() can return success for a row that the engine rejects
  later. It is overridden in Spider and in ha_partition.

This commit also fixes bugs found during testing:
- MDEV-41262 ER_TOO_MANY_ROWS should be checked after CHECK OPTION in view
  while Update Returning Into
- MDEV-41265 SELECT/ UPDATE RETURNING INTO a single row-field fails with
  ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT, even though the column count matches
  This bug was also fixed in 12.3.4.
- MDEV-41260 Misleading message text "uses a LIMIT clause" after Update
  Returning Into
- MDEV-42212 UPDATE ... RETURNING ... INTO raises ER_TOO_MANY_ROWS on InnoDB
  when the second found row needs no update
- MDEV-42156 UPDATE IGNORE ... RETURNING ... INTO fails with
  ER_TOO_MANY_ROWS when the second row is skipped by IGNORE (duplicate key)
- MDEV-41448 Update Returning Into expected to produce warning/error for
  zero-row plan (a test was added; the warning is now raised consistently)
- MDEV-41443 Update Returning into produces error when values don't change
  (a test was added; a warning is raised instead of an error)
bsrikanth-mariadb
MDEV-42186: Info leak with optimizer_replay_context

Replaying a context for a query on a view made the server push
warnings naming the underlying tables, their indexes and the view's
hidden range constants, even if the user could not read those tables.

On the first use of the replay, check that the invoker can read all
columns of every base table in the statement. If any table fails the
check, drop the context, so nothing is replayed and no warnings are
produced.
Sergei Petrunia
Fixup: opt_ctx_can_read_all_columns() is not used for VIEWs.
Marko Mäkelä
fixup! 7cfefd08e195bda8e03b0687632953656128ce7d

InnoDB_backup::stream(): Correctly write the dummy blocks after DROP TABLE
Oleksandr Byelkin
MDEV-41843 Forcing rotation of Aria log files

Backup needs to switch Aria to a new log file so that the finished
files can be copied without blocking commits.

Added translog_rotate() and handlerton::rotate_logs (ha_rotate_logs()),
implemented for Aria. Nothing in the server calls it yet (BACKUP SERVER
will), so it is tested by the unit test ma_test_loghandler_rotate-t.

Rotation of a log without records makes files with no records, which
were not handled:
- the header of such a file got max LSN 0, which purge takes for a file
  still in writing and never passes; now it gets the last address of
  the file
- the scan for the first record (recovery without a checkpoint,
  aria_read_log) stopped at the filler of the empty file and found no
  records; now it goes on to the next page
- the log start left a page of the empty log pinned

Assisted-by: Claude:claude-opus-5-5
Jan Lindström
MDEV-42140 require galera >= 26.4.29 in galera_wsrep_schema_detached

Add a galera library version check and the resulting .result line.
Requires a galera library with the MDEV-42140 IST allowlist fix.

Assisted-by: Claude:claude-4.6-sonnet
Elena Stepanova
MDEV-42202 perfschema.relaylog fails when run after other replication tests

The test checks file I/O instrumentation accumulated since server
startup, so it relied on getting freshly started servers. With
duplicate options removed, mtr may now reuse servers left by
a previous replication test, and the test sees binary/relay log
files and statistics from it.

Restart both servers at the beginning of the test, removing
binary and relay logs while the servers are down. RESET MASTER
and RESET SLAVE are not sufficient, as performance schema keeps
instances of files deleted by them, and a restart opens a new
binary log anyway.

Assisted-by: Claude:claude-opus-5-5
Elena Stepanova
MDEV-41085 Enable MTR tests on Windows: rpl suite

rpl.rpl_change_master_long_channel_name fails on Windows because it
expects a 252-character name (base name, excluding the path) to be
valid; on Windows the whole path is limited to 260 characters, so
252-character name already fails
Jan Lindström
MDEV-42141 tolerate ER_NO_SUCH_TABLE in GCF-1018B's reap

wsrep_sync_wait=0 lets node_2's DELETE run before node_1's CREATE
TABLE replicates, so the first iteration of the test's 500-iteration
INSERT/DELETE loop can legitimately race a not-yet-existing t1. The
--error list on node_2's reap did not accept ER_NO_SUCH_TABLE, even
though it already tolerates other non-deterministic races (lock wait,
deadlock, duplicate key) for the same reason, matching the pattern
used for the same race in GCF-1060 (MDEV-41923).