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
DerZc
MDEV-40673 CONCAT drops the first argument from JSON_TYPE or GET_FORMAT

CONCAT uses String::alloc() when its result has zero allocated capacity.
Such a string can still reference external data, which alloc() discards.

Remove the zero-capacity special case so the existing growth calculation
and String::realloc() preserve the prefix for all strings. Explain why
realloc() is required and cover both JSON_TYPE() and GET_FORMAT() in the
10.11 section of main.func_concat.
sjaakola
MDEV-41385 wsrep_sync_wait has no effect after COM_CHANGE_USER

Also reported as: https://github.com/mariadb-corporation/galera/issues/613.

THD::cleanup() cleared THD::wsrep_client_thread. Besides connection
close, THD::cleanup() is also called from THD::change_user() when
handling COM_CHANGE_USER and COM_RESET_CONNECTION. THD::init() does
not set the flag back, and the only place that sets it is
thd_prepare_connection(). After either command the session was no
longer treated as a wsrep client connection: WSREP_CLIENT() returned
false for the rest of the session.

As a result wsrep_sync_wait was silently ignored, so causal reads
could return stale data. Such connections were also skipped by
wsrep_close_client_connections() and
wsrep_wait_committing_connections_close(). Connection pools issue
COM_RESET_CONNECTION whenever a connection is reused, so in practice
most pooled sessions were affected.

Fix by moving the reset of wsrep_client_thread from THD::cleanup()
to end_connection(), after wsrep_close().

The galera.galera_change_user test is extended to do a causal read
on a fresh connection, after COM_CHANGE_USER and after
COM_RESET_CONNECTION. Each read must increase the provider's
wsrep_causal_reads status counter.
Aleksey Midenkov
MDEV-40462 Move innodb.innodb-virtual-columns-debug into gcol.innodb_virtual_debug

innodb.innodb-virtual-columns-debug contained only the MDEV-17005 test
case. It is about InnoDB virtual column templates, so it belongs with
the other InnoDB virtual column debug tests in gcol.innodb_virtual_debug.

Rationale

Adding a separate test file for every single bugfix tends to grow the
number of MTR tests by tens of thousands (as there are already 40k
MDEV tickets). Each test file carries a fixed overhead that does not
depend on its size: before and after every test MTR runs
check-testcase to compare the server state, checks the error log for
warnings, and may restart the server when the options differ from the
previous test.

For tiny test files this overhead dominates the time of the test
itself, so the total time of MTR runs on buildbot and in local testing
grows considerably.

Besides that, every test is at least two files (.test and .result,
often also .opt or .combinations). Tens of thousands of extra small
files bloat the test directories, which slows down MTR test collection
and any filesystem traversal of the source tree, and they enlarge the
git index and tree objects, which makes git status, checkout, clone
and merges between branches slower.
Oleksandr Byelkin
MDEV-41099 HANDLER READ missing column privilege check

HANDLER OPEN accepted column-level SELECT grants as table access, but
HANDLER READ returns all columns and never checked column privileges.
Reopen of a handler table (after FLUSH/ALTER) did no checks at all.

Require SELECT on every column (as for SELECT *) when the user has no
table-level SELECT, and redo the privilege checks on reopen.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
KhaledR57
MDEV-32383 Server crashes in Item_func_match::init_search on 2nd execution of PS

Item_func_match::master points at an equal MATCH item that owns the
shared ft_handler. setup_ftfuncs() sets it only when it is still unset,
and cleanup() never reset it.

A mergeable view is merged once. On re-execution mysql_derived_prepare()
returns early because TABLE_LIST::merged is set, so the view's own MATCH
item is never re-fixed and keeps the NULL table left by cleanup().
init_ftfuncs() skips unfixed items in ftfunc_list, but init_search()
follows master without that check and dereferenced the NULL table.

Reset master in cleanup(), after the ft_handler ownership check that
reads it, so the link is rebuilt from scratch on every execution.
Jan Lindström
MDEV-37269 : kill_galera.inc does not wait for the killed process to exit

There were two compatible copies of kill_galera.inc and which one a test got
depended on its suite, so tests outside the galera suite still used the copy
with the non-portable "kill -9". Neither waited for the process to exit: both
ended in wait_until_disconnected.inc, which only says the server stopped
serving the connection, while the process can hold its pid file, ports and
data directory for a while after that. Tests that restart the node or read
its grastate right away worked around it with a --sleep.

Keep one copy, under include, and wait for the process with a kill(0) probe.
mysqld does not remove its pid file when killed by a signal, so
wait_until_no_pidfile.inc cannot be used here, but my_safe_process is in
waitpid() on it and reaps it as soon as it exits. Drop the seven --sleeps
that only waited for the process, and the six wait_until_disconnected.inc
calls the include already does.

Waiting for the rest of the cluster to notice is a separate thing which the
include cannot do for the caller, so the tests polling wsrep_cluster_size or
wsrep_cluster_status on a surviving node keep doing that.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Oleksandr Byelkin
MDEV-41144 Assertion `scale <= precision' failed in decimal_bin_size

dynamic_column_decimal_read() derived intg/frac from an unbounded
var-uint and only checked scale>precision in int domain, so a crafted
value could still overflow decimal_bin_size()'s uint16 parameters,
tripping its scale<=precision assert (an out-of-bounds array read in
release builds).

Bound intg/frac against DECIMAL_MAX_POSSIBLE_PRECISION before use, and
reject the var-uint decoder's error signal, as the sibling
dynamic_column_string_read() already does. Validate the decoded
ulonglong before narrowing it to int, so a value wrapping around on
narrowing cannot bypass the bound.
Sergei Golubchik
Merge branch '10.11' into 11.4
Jan Lindström
MDEV-37269 : galera.mysql-wsrep#198 test failure

The test polled INFORMATION_SCHEMA.PROCESSLIST for one of three thread states
to know that its two TOI DDLs were parked. None of them is reliable:
"acquiring total order isolation" is overwritten by THD_STAGE_INFO() two lines
after it is set and never reaches the process list, and while waiting for a
metadata lock the state alternates once per second between "Waiting for table
metadata lock" and the stage restored when the wait is left, which for a
statement that already holds total order isolation is "Waiting for TOI DDL"
and was not accepted. Both DDLs are in that state here, and the wait that
requires the two to match at the same poll is the one that timed out.

Use the mdl_acquire_lock_wait and wsrep_before_toi_begin debug sync points
instead. The test needs a debug build from now on.

On timeout wait_condition_with_debug_and_kill.inc killed the node but did not
abort the test, which then ran UNLOCK TABLES against the dead server and
failed with an unrelated error that hid the timeout. Abort after the kill.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Aleksey Midenkov
MDEV-38758 vcol.vcol_partition_innodb fails on buildbot

TABLE_ROWS in INFORMATION_SCHEMA.PARTITIONS for InnoDB is
dict_table_t::stat_n_rows. Each INSERT puts the record into the
clustered index and only afterwards increments stat_n_rows without
any latch. The second INSERT into a fresh partition schedules a
background persistent stats recalc, which is not throttled because
stats_last_recalc is still 0. If the recalc scans the leaf page
after the next INSERT has added its record but before that INSERT
increments stat_n_rows, the recalc stores the exact count and the
increment then adds one more, so p2 shows 4 rows instead of 3.

The fix disables innodb_stats_auto_recalc for the duration of
inc/vcol_partition.inc in the InnoDB variant of the test, so
stat_n_rows is maintained only by the per-row increments and is
exact.
Maximilian Krög
MDEV-40417 A column with compression enabled automatically adds DEFAULT ''

Compression is stored in unireg_check as Field::TMYSQL_COMPRESSED, but
has_default_function() treated any unireg_check other than Field::NONE as a
default function.  A COMPRESSED NOT NULL column without an explicit DEFAULT
therefore never got NO_DEFAULT_VALUE_FLAG, the FRM was written without
FIELDFLAG_NO_DEFAULT, and the column silently became optional while
SHOW CREATE TABLE displayed a phantom DEFAULT ''.

Exclude TMYSQL_COMPRESSED in has_default_function() and use that method in
Column_definition::check() as well, so that both places which set
NO_DEFAULT_VALUE_FLAG stay in sync.

Tables created before the fix keep the wrong implicit DEFAULT '' in their
FRM and are not repaired automatically, the affected columns need an
explicit ALTER TABLE ... MODIFY.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Vladislav Vaintroub
MDEV-33480 Windows MSI installer, convert from WIX v3 to supported versions

WiX v3 is out of support. Support legacy WiX v3.x (default) and modern
WiX (wix.exe, newer than v3). WXS sources stay in v3 format, modern WiX
(-DWITH_WIX3=OFF) builds them after on-the-fly 'wix convert'.

Two WXS edits make the converted sources valid: ALLUSERS property is
replaced by InstallScope='perMachine', and ProgramMenuFolder is moved
from under INSTALLDIR to TARGETDIR.

WIX_ACCEPT_EULA=ON accepts the EULA of WiX 7 and later, if WiX asks for it.

A failed WiX step is reported by name.
PranavKTiwari
MDEV-39245: Added ASCII validation at two points using my_string_repertoire():

1. Built-in plugins (plugin_init):
  A non-ASCII builtin name is a developer error. Added a check
  using my_string_repertoire() that prints an error via
  print_init_failed_error() and returns 1 to abort server startup.

2. Dynamically loaded plugins (plugin_add):
  Added a pre-validation loop before the registration loop. If any
  plugin name in the .so is non-ASCII, the entire .so is rejected
  before any plugin is registered, preventing partial state where
  valid plugins from the same .so get left INACTIVE in the hash.

Added test plugins and MTR tests to verify both rejection of
non-ASCII named plugins and successful loading of ASCII named plugins.
Aleksey Midenkov
MDEV-40462 innodb.innodb-virtual-columns-debug failed in buildbot with wrong result

The test sporadically fails because DELETE does not reach the
ib_open_after_dict_open sync point:

  SET debug_sync= "now WAIT_FOR delete_open";
  +Warnings:
  +Warning 1639 debug sync point wait timed out
  SELECT a FROM t1;
  a
  -NULL
  -NULL

The sync point is in ha_innobase::open(), which is called only when a
new TABLE is created from the share. After ALTER TABLE ... ALGORITHM=COPY
no TABLE for t1 is cached, but t1 has indexed virtual columns, so the
purge thread opens it via open_purge_table() and on close_thread_tables()
leaves the TABLE in the table cache. If that happens before DELETE, the
DELETE reuses the cached TABLE, does not call ha_innobase::open() and
completes without signalling delete_open.

The fix waits for purge with innodb_max_purge_lag_wait=0 and then does
FLUSH TABLES t1 before arming the sync point, so DELETE always opens a
new TABLE.
Aleksey Midenkov
MDEV-30441 ASAN heap-use-after-free in Field_blob::pack/pack_row

When InnoDB computes an indexed virtual column (e.g. the long unique
hash), TABLE::update_virtual_field() walked its expression with
update_vcol_processor() and recomputed every vcol it referenced,
including STORED ones. innobase_allocate_row_for_vcol() saves and
restores Field_blob::value only for non-stored blob vcols, so
recomputing a STORED blob vcol in Field_blob::store_field() did
val_str(&value) and freed the buffer that record[0] still pointed to.
The row-format binlog then packed record[0] from freed memory.

The buffer is allocated only when the value is converted, so the bug
needs a character set conversion (e.g. BLOB to utf8mb3 TEXT).

The fix skips STORED vcols in update_vcol_processor(). Their values are
already in the record: InnoDB copies them as base columns of the
virtual column, and the SQL layer computes them before writing.

The test cases detect the bug only under ASAN or Valgrind.
PranavKTiwari
MDEV-36896 Assertion 'marked_for_read()' failed in virtual String *Field_varstring::val_str(String *, String *)

Problem: Executing queries that require virtual/generated column
evaluation during filesort trigger debug assertions due to missing
columns in read_set. Release builds return wrong results: rows that do
not match the WHERE, or missing rows that do.

Cause: find_all_keys() temporarily assigns TABLE::tmp_set as both
read_set and write_set (keyread does the same). InnoDB calls
TABLE::update_virtual_field() in the middle of the
scan (row_sel_sec_rec_is_for_clust_rec() ->
innobase_get_computed_value()) when it checks a secondary index record
against an older row version, a delete-marked record, or at READ
UNCOMMITTED. TABLE::update_virtual_field() calls
bitmap_clear_all(&tmp_set) before evaluating virtual column
dependencies. Since all three pointers share the same underlying
bitmap buffer, clearing tmp_set also clears the active
read_set/write_set, causing required columns to appear missing during
execution and triggering the assertion.

Fix: The fix uses a local bitmap instead of tmp_set for the virtual
column dependency walk in TABLE::update_virtual_field(), so the active
read_set/write_set is not touched.

Test: vcol.vcol_keys_innodb covers READ UNCOMMITTED (MDEV-36896) and a
concurrent uncommitted update under REPEATABLE READ (MDEV-41365).

Duplicated by MDEV-41365.
Thirunarayanan Balathandayuthapani
MDEV-38942: Fix memory leak in dict_sys_tables_rec_read()

- Free the heap before returning READ_NOT_FOUND for a
delete-marked SYS_TABLES record.
Vladislav Vaintroub
MDEV-40955  mysql_client_test needs a resolvable DNS on Linux.

The tests test_proxy_header_connect_errors_reset() and
test_proxy_header_host_denied_not_counted() rely on their client IPs
(192.0.2.x test IPs, per RFC 5737) failing reverse DNS lookup permanently,
which is what a real, working resolver reports for them. Linux's resolver
isn't so RFC-compliant, when it has no route to any nameserver at all: it
reports EAI_AGAIN (temporary) instead, which is deliberately excluded from
connect-error accounting to avoid blocking hosts during a DNS outage.
That silently defeats the max_connect_errors check these tests exercise.

Fix by forcing the deterministic "permanent failure" outcome via the
existing getnameinfo_error_noname debug instrumentation, same as its
sibling tests. Debug-only, like those siblings, since the workaround
needs DBUG_EXECUTE_IF.

Assisted-By: Claude Sonnet 5 <[email protected]>
Dave Gosselin
MDEV-24907:  Empty the source list after merging an Item_equal

With save_merged false, Item_equal::merge_into_list() merges this
object's Item_equal instances into another, linking *this object's
items into the target.  However this allowed callers to free an
item via one list but later read it through the other; a case of
use-after-free.

If save_merged is false then delete the items from the source.
Aleksey Midenkov
MDEV-40311 Fix mysqldump-nl leaving slave connection behind

The trailing CHANGE MASTER left master.info in the datadir, so a
later test that restarts the server auto-started the slave and broke
its check-testcase. Use RESET SLAVE ALL to drop the connection.

MTR's internal check of the test case 'sys_vars.default_master_connection_basic' failed.
This means that the test case does not preserve the state that existed
before the test case was executed.  Most likely the test case did not
do a proper clean-up. It could also be caused by the previous test run
by this thread, if the server wasn't restarted.
This is the diff of the states of the servers before and after the
test case was executed:
-Slave_IO_Running No
-Slave_SQL_Running No
+Slave_IO_Running Connecting
+Slave_SQL_Running Yes
...
-Last_IO_Errno 0
-Last_IO_Error
+Last_IO_Errno 1045
+Last_IO_Error error connecting to master '[email protected]:3306' - retry-time: 60  maximum-retries: 100000  message: Access denied for user 'root'@'localhost' (using password: NO)
Khaled Riyad
MDEV-40377 Change Server source code to point to new docs (10.11 part)

Replace the remaining Knowledge Base links with their MariaDB
Documentation equivalents, and fix the 14 help table URLs pointing at
/README pages that do not exist. Only URLs change in
fill_help_tables.sql.

Merging upward: fill_help_tables.sql conflicts at 10.11->11.4 and
11.8->12.3. At those two merges keep the target branch's version,
since 11.4, 11.8 and 12.3 each carry their own URL fix. From 12.3 to
13.1 and 13.1 to main it merges cleanly; take the incoming change.
.github/pull_request_template.md is deleted in 12.3; keep the deletion.
Khaled Riyad
MDEV-41408 MTR prepared statement protocol skipping statements starting with '('

With --ps-protocol, mysqltest runs a SELECT a second time and compares
the results. The regex ps2_re only matched a leading SELECT, so a
statement starting with '(' was executed only once.

Allow any number of '(', each optionally followed by spaces, before
SELECT in ps2_re.
PranavKTiwari
MDEV-28610 : Assertion  marked_for_read() failed upon range select with virtual column in index.
Problem:
Executing a range select using an index that includes virtual/generated columns
(e.g. SELECT ... WHERE c BETWEEN ... ORDER BY d) could trigger:

Assertion 'marked_for_read()' failed in Field access during execution.

Cause:
The keyread initialization path was populating table->read_set using
mark_index_columns(), which follows the non-recursive index marking path.
This only marks direct index fields and does not resolve dependencies of
virtual/generated columns.

As a result, when an index contained virtual columns, their dependent base
columns were not included in read_set, leading to invalid access during
later evaluation of virtual columns.

Fix:
Replace mark_index_columns() with mark_index_columns_for_read() in the
keyread initialization path. This ensures the recursive read-marking logic is
used, so virtual/generated column dependencies are correctly propagated into
read_set before execution.
Vladislav Vaintroub
MDEV-33480 Windows MSI installer, convert from WIX v3 to supported versions

Custom actions : get rid of wcautil and dutil library dependencies
They are not an official part of WiX distribution anymore.

Replace the functionality with native MSI api, the Wix helpers
we used were thin wrappers anyway.

Also replace the VBScript FakeFailure custom action with a native
one, VBScript is deprecated in Windows and scheduled for removal.

Read MSI properties with a helper that handles any length and reports
errors. Values are no longer silently truncated to MAX_PATH, e.g a long
data directory could be cut to its parent, and then removed.

A custom action that fails to read a property or to call a Windows API
returns ERROR_INSTALL_FAILURE, it was silently ignored before.
greypilgrim-083
MDEV-40995 concurrent INSERT ... SELECT on a partitioned InnoDB table can leave the table-level AUTO_INCREMENT counter behind MAX(pk), so later inserts are handed ids that already exist and fail with ER_DUP_ENTRY on the PRIMARY KEY

For a partitioned InnoDB table with AUTO_INCREMENT as the leftmost PK
column, values are issued by the partitioning layer from the shared
counter Partition_share::next_auto_inc_val, reserved in doubling blocks
(1, 2, 4, 8 ... values per reservation).

At end-of-statement, ha_partition::release_auto_increment() returns
unused tail values to the shared counter. When a row fails mid-statement,
handler::restore_auto_increment() rolls next_insert_id back to the
boundary of an earlier block. The guard in release_auto_increment()
inspects only the last interval, so it passes even when the returned
value is already in use by concurrent sessions.

Fix: extend the guard to also verify that next_insert_id is within the
statement's own reservation interval, rejecting a lowering caused by
restore_auto_increment() rolling back across a block boundary.
Marko Mäkelä
MDEV-41318 Incorrect recovery of FILE_CREATE after FILE_RENAME

recv_recovery_from_checkpoint_start(): Before applying any page-level
log records by invoking recv_scan_log(true, parser), invoke
recv_rename_files() to replay FILE_RENAME records. In this way,
recv_sys_t::recover_deferred() will not overwrite any old data files
that had been renamed before a new file was created.

recv_sys_t::validate_checkpoint(): Refer to recv_sys.scanned_lsn
rather than recv_sys.lsn, because recv_scan_log(false, parser)
may reset the latter to rewound_lsn in case we run out of memory for
recv_sys.pages. In any case, the second call to recv_scan_log() will
proceed to the end of the log and parse all records.

Reviewed by: Thirunarayanan Balathandayuthapani
Vladislav Vaintroub
MDEV-28746 follow-up: missed relative paths overflowing MAX_PATH

my_win_sopen() only checked the length of the raw path it was given, but
the server opens table files via paths relative to its data directory,
so a short relative path can still overflow MAX_PATH once
resolved against a long enough datadir. That case was misreported as
ER_BAD_DB_ERROR instead of ER_CANT_CREATE_TABLE/ENAMETOOLONG.

Resolve the path via GetFullPathName() before deciding whether the path
was too long, factored into resolved_path_too_long(). A failed resolve
is only treated as too-long when GetLastError() is
ERROR_FILENAME_EXCED_RANGE, so unrelated resolution failures keep
mapping to the original CreateFile error.

Also fix the global errtable mapping of ERROR_FILENAME_EXCED_RANGE: it
was mapped to ENOENT, so any Win32 call that got that error code
directly (not via ERROR_PATH_NOT_FOUND) was misreported the same way.

Assisted-by: Claude:claude-sonnet-5
Hemant Dangi
MDEV-41230: shipped wsrep_notify.sh reparses credentials through eval

Issue: wsrep_notify.sh builds the mysql client invocation as text with
values wrapped in '...', then re-parses it via eval. A configured
password (or SSL path) containing a single quote breaks out of that
quoting, splitting into extra arguments; the unquoted SSL_PARAM splice
also let ssl_* values undergo pathname (glob) expansion before eval
ever ran.

Solution: escape embedded single quotes before interpolating USER,
PSWD, HOST and the ssl_* values into the eval'd string, and quote the
SSL_PARAM splice so it isn't glob/word-split before eval runs. Applied
identically to the std_data test copies, and added a galera regression
test reproducing the reported password-splitting.
Aleksey Midenkov
MDEV-29566 parts.partition_special_innodb unstable DROP TABLE fix

The test sporadically fails with ER_LOCK_WAIT_TIMEOUT on DROP TABLE t1
of the Bug#53676 test case (see MDEV-29566).

  mysqltest: At line 119: query 'DROP TABLE t1' failed:
  ER_LOCK_WAIT_TIMEOUT (1205): Lock wait timeout exceeded; try restarting transaction

The DROP TABLE is executed by con2 with lock_wait_timeout=0. The INSERT
puts two rows into each partition, which exceeds the auto recalc
threshold of persistent statistics, so the partitions are added to the
recalc pool. The statistics background thread opens the partitions with
a shared MDL on t1, and if it does so at the moment of DROP TABLE, the
MDL request fails instantly.

The fix creates the table with STATS_PERSISTENT=0. The test case is not
about statistics; this also avoids locking mysql.innodb_table_stats and
mysql.innodb_index_stats in ha_innobase::delete_table() when the failed
ALTER TABLE ... ADD PARTITION rolls back the new partitions.
Oleksandr Byelkin
MDEV-41175 Fix stack-buffer-overflow in backup_log_ddl()

backup_log_ddl() built its log record in a fixed-size stack buffer,
but add_name_to_buffer() can expand each identifier character to 5
bytes when re-encoding it into my_charset_filename, so a RENAME TABLE
with long, special-character names overflowed the buffer.

Fixed by building the record in a growable String, converting names
directly into it, and setting backup_log_error instead of writing a
partial record if an allocation fails.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
PranavKTiwari
MDEV-30297 Server crash / assertion failure in Compare_identifiers::operator upon dropping period with empty name

Problem:
ALTER TABLE ... DROP PERIOD IF EXISTS FOR can trigger an assertion failure in debug builds and crash in non-debug builds.

Cause:
Lex_cstring_with_compare::streq() may invoke Compare_identifiers on default-constructed Lex_cstring objects (str == NULL, length == 0). Compare_identifiers assumes non-null string pointers and asserts or crashes when called with a null pointer.

Fix:
Add null-pointer handling to Lex_cstring_with_compare::streq() and avoid calling Compare_identifiers when either string pointer is null. This prevents invalid comparisons while preserving existing behavior for initialized strings.
Marko Mäkelä
MDEV-40950: Crash after memory pressure event

buf_pool_t::garbage_collect(): Correctly handle the SHRINK_ABORT
return value of buf_pool_t::shrink().

Reviewed by: Daniel Black
Jan Lindström
MDEV-41073: server aborts after "Unknown error" is logged for FK key exceeding 3500

Failure:
- wsrep_rec_get_foreign_key() returned DB_ERROR when a write set key
  exceeded WSREP_MAX_SUPPORTED_KEY_LENGTH; the caller does not know
  DB_ERROR and calls ib::fatal().
- wsrep_fk_key_space_left() needed two bytes for a NULL column instead
  of one; only the flag byte is ever written for NULL.
- Cutting a whole number, float or double to fit the remaining buffer
  produces a different value, not a shorter one, and for a float or
  double not even a valid one: mach_float_read()/mach_double_read()
  read a fixed 4 or 8 bytes regardless, past an assertion in a debug
  build and past the buffer itself in a release one.
- wsrep_store_key_val_for_row()'s equivalent fixed-length branch had
  the same unchecked copy, reachable only in theory given InnoDB's own
  index length limit, but inconsistent with every other branch in that
  function.
- The same function normalized a VARCHAR column's collation weights up
  to 3072 bytes while wsrep_rec_get_foreign_key() normalized it up to
  3500, so the two produced a different key for a value whose
  normalized form falls between the two limits.
- wsrep_store_key_val_for_row() kept iterating columns after one did
  not fit, relying on every later branch clamping to zero rather than
  stopping outright.
- MW-292 matched its two debug sync waiters by substring, not an exact
  match, independent of wait order.

Fix:
- wsrep_rec_get_foreign_key() now cuts the key the same way
  wsrep_store_key_val_for_row() does, reports the cut as a warning
  (ER_TOO_LONG_KEY under strict mode), and returns DB_TOO_BIG_RECORD.
- wsrep_fk_key_space_left() takes a fixed_len flag: a whole number,
  float or double must fit in full or is left out of the key entirely,
  the same way a value that does not fit even one byte already was.
- wsrep_store_key_val_for_row() applies the same all-or-nothing rule to
  its own fixed-length branch, reusing get_innobase_type_from_mysql_type()
  so both functions agree on which types that covers, and now stops
  storing further columns as soon as one does not fit, in every branch.
- wsrep_store_key_val_for_row()'s VARCHAR branch normalizes up to
  WSREP_MAX_SUPPORTED_KEY_LENGTH, matching wsrep_rec_get_foreign_key(),
  with its buffer grown to match.

Test:
- galera_ws_datatypes.test and galera_ws_datatypes_plugin.test cover
  every MariaDB data type in a primary key, unique key, plain key and
  foreign key (referencing a primary or unique key), including NULL
  foreign key columns.
- galera_ws_datatypes_fixed_length.test covers a foreign key column cut
  to fewer bytes than a whole number, float or double needs.
- galera_ws_datatypes_varchar_cap.test covers a VARCHAR foreign key
  column whose normalized form falls between the two limits above.

Assisted-by: https://mariadb.org/governance/governance-ai-policy/
GoldenEmperor1177
MDEV-34215 Fix DATE_FORMAT result length for negative TIME

DATE_FORMAT calculated its maximum result length solely from the format
string. Formatting a negative TIME also prepends a minus sign, so the
cursor protocol trusted an undersized result and truncated -01 to -0.

Account for the possible sign in format_length() for TIME_FORMAT() and
DATE_FORMAT() with a native TIME argument. Enable the existing cursor
protocol regression cases for binary, latin1, and utf32 result character
sets.
Khaled Riyad
MDEV-38004 Double free on re-execution of prepared aggregate function

Between two executions of a prepared statement, Item_sp::cleanup() freed
the stored function's memory root but left the arena's free list pointing
into it. That list is filled when the function call returns and the active
arena is restored.

On the next execution Item_sum_sp::clear() walked the stale list and
destroyed already freed items.

Free the items before the memory they live in.  The sequence is now
in Item_sp::free_call_ctx(), so the three places that repeat it
cannot drift apart again.
Rex Johnston
MDEV-41179 MAX_KEY_PARTS ranges in select causing SEGV

When a select containing 32 ranges is made on a table containing a
compound key with 32 parts, the range optimizer can run off the end
of a stack variable, invalidly overwriting subsequent stack variables.

In the struct st_sel_arg_range_seq, we have an array
  RANGE_SEQ_ENTRY stack[MAX_REF_PARTS];

MAX_REF_PARTS is 32.

check_quick_select
  / sel_arg_range_seq_init
    initialises stack[0] as NOT a key part
  / sel_arg_range_seq_next
    iterates through the key parts, adding key part n to stack[n+1]

key part #32 gets referenced by step_down_to(), setting seq->i off the
end of the array.

Fix: RANGE_SEQ_ENTRY stack[MAX_REF_PARTS+1];

The above change exposed an issue with key length calculation on
MS Windows.  Calling make_prev_keypart_map(32) caused the resultant
bitmap to be calculated as (1UL << 32) - 1.  Using the MSVC compiler
this resulted in an empty key length calculation during
handler::index_read_map, causing an assertion in ha_innobase::index_read().

As we only need 32 bits to represent our key map, we change the type thus
-typedef ulong key_part_map;
+typedef uint32 key_part_map;

We correct make_keypart_map() and make_prev_keypart_map() to call our
overflow safe my_set_bits().  We also correct bka_range_seq_next()
and bkah_range_seq_next() to use make_prev_keypart_map().

We also add some DBUG_ASSERTS in key_part_map processing elsewhere,
exposing some issues in our BNLH implementation.  We cap the number of
keyuse parts here, altering the explain output of 2 of our tests.

Numerous places needed bit shift operations altered to use
make*keymap_part and various format strings needed to be corrected.
Aleksey Midenkov
handlersocket.basic unstable result fix

The test fails on random secret with backslash.

The random handlersocket_plain_secret is generated from the '0'..'z'
range, which includes the backslash. The test masked the secret with
--replace_result $HS_SECRET, and mysqltest parses --replace_result
arguments with backslash escapes, so the search string lost the
backslash and did not match the output. The unmasked secret then
appeared in the result (about 19% of runs).

The fix masks the secret in SQL: IF(variable_name LIKE
'handlersocket_plain_secret%', 'HS_SECRET', variable_value), which does
not depend on the secret value.
PranavKTiwari
MDEV-26820 Assertion 'marked_for_read()' failed upon SELECT with VALUE(virtual column)
Problem:
Item_insert_value::fix_fields() created a temporary field
without preserving vcol_info. As a result, VALUE()/VALUES()
on virtual columns lost dependency metadata and could trigger:

Assertion `marked_for_read()' failed during virtual column evaluation.

Cause:
The temporary Field_string copied field_index but did not copy virtual column metadata from the original field.

Fix:
Preserve vcol_info when creating temporary fields in Item_insert_value::fix_fields() so virtual column dependency
tracking remains intact.
Oleksandr Byelkin
MDEV-41186 Fix stack-buffer-overflow in make_unique_constraint_name

A multi-byte PERIOD name at the 64-character limit (192 bytes) filled
the name buffer exactly, leaving no room for the '_N' suffix appended
when generating a unique name for the implicit CHECK constraint.

Truncate on a character boundary, but only once a suffix is actually
needed (mirroring make_unique_key_name), so a non-colliding name is
never altered.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Rex Johnston
MDEV-41225 Parse the ORDER BY tail of a wrapped parenthesized query in the wrapping select

A parenthesized query expression that already has its own ORDER BY or
LIMIT and is followed by another ORDER BY, e.g.

  (SELECT c1 FROM t1 ORDER BY c1 LIMIT 2) ORDER BY <expr> LIMIT 1

is wrapped into a derived table, and the outer ORDER BY/LIMIT is attached
to the wrapping select.  The grammar pushed the inner select before
parsing the tail, and add_tail_to_query_expression_body_ext_parens()
created the wrapper only after the tail had been parsed.  Anything that
is attached to the current select while the tail is being parsed was
therefore attached to the inner select, while the ORDER BY list itself
was moved to the wrapper:

- Window functions and their window specs were added to the inner
  select's window_funcs/window_specs.  The same Item_window_func was then
  in the wrapper's ORDER BY and in the inner select's window function
  list, which triggers the original assertion reported in MDEV-41225.

  (SELECT 1 FROM t1 LIMIT 1)
    ORDER BY PERCENTILE_DISC(1) WITHIN GROUP(ORDER BY TIME'0') OVER();

  The function is computed by the inner select over the rows before its
  LIMIT, so the outer ORDER BY sorts on wrong values
  (e.g. COUNT(*) OVER () returned 3 for a 2-row result).

- Subqueries were registered as units of the inner select.  An
  uncorrelated subquery in the tail crashed the server with SIGSEGV when
  it was executed by the outer filesort.  A correlated one resolved its
  outer references in the inner select (t1.c1) instead of the derived
  table.

The decision to wrap depends only on whether the inner select already
has a tail and on whether the outer tail has ORDER BY.  LIMIT and locking
clauses cannot contain window functions or subqueries.
We replace query_expression_tail with
query_expression_tail_with_order and query_expression_tail_no_order
so the mid-rule action knows whether an ORDER BY follows.
The new LEX::push_select_for_ext_parens_tail() creates the wrapper before
an ORDER BY tail is parsed when wrapping is required, and pushes it instead
of the inner select.  The tail's items are then created in the wrapper's
context, and window functions and subqueries are attached to the wrapper.
add_tail_to_query_expression_body_ext_parens() takes the pushed select and
skips wrapping when it has already happened; the other cases keep the
previous logic.  The grammar has the same number of conflicts as before.

A subquery in such a tail can no longer refer to the tables of the wrapped
query expression (e.g. t1.c1 above) and gets ER_BAD_FIELD_ERROR,
as those tables are not visible outside the derived table.

This commit was prepared with Claude Code (Opus 5.5). It traced the
wrong-result and crash cases to the parse-time registration of window
functions and subqueries in the inner select, tested the grammar split
with bison, wrote the code change and the brackets test.