1
0
mirror of https://github.com/MariaDB/server.git synced 2026-10-23 18:49:29 +03:00
Commit Graph

202976 Commits

Author SHA1 Message Date
Rex Johnston
3aad6d5943 MDEV-38347 Debugging functions
Extend current dbug_print* functions in such a way as to facilitate easy
high level debugging.  Introduce a single overloaded print function
defined in dbp.h, DBUG_PRINT_FUNCTION, settable to your preference.
Allow a shell environment variable DBUG_PRINT_FUNCTION to override
this definition
2026-10-23 11:10:55 +13:00
Andrzej Jarzabek
c68fe071c3 MDEV-40239, MDEV-41616: Fix undo log page add failure injection
The debug injection ib_err_ins_undo_page_add_failure in
trx_undo_report_row_operation() cleared undo_block to simulate a
failure of trx_undo_add_page(), but left err as DB_SUCCESS.
The function then returned DB_SUCCESS without writing an undo log
record or setting *roll_ptr, so callers stored an invalid DB_ROLL_PTR
in clustered index records. This caused assertion failures in
trx_undo_page_report_modify() and trx_undo_prev_version_build().

The injection now also sets err=DB_OUT_OF_FILE_SPACE, simulating
running out of tablespace capacity.

MDEV-41616: when that failure was reported, ib_errf() was given the
dberr_t value DB_OUT_OF_FILE_SPACE where an error number was expected,
so the client received an unrelated message. Use
ER_INNODB_UNDO_LOG_FULL.
2026-10-21 20:30:16 +02:00
Thirunarayanan Balathandayuthapani
76590804bf MDEV-41550 MTR doesn't produce core dump or stack trace when a server hangs during startup
Problem:
========
If a server hangs in startup, mtr either waits for its pid file for
--start-timeout seconds and gives up with "Failed to start" (or)
when the test restarts the server, leaves the waiting to mysqltest,
which ends after about 500 seconds with "Server failed to restart".
In both cases the hung server is killed with SIGKILL, so
no core dump and no stack trace is produced, and it is
impossible to find out where the server got stuck.

Solution:
=========
dump_core_for_hung_server(): Sends SIGABRT to a server that is
still alive and waits for it to finish dumping core.
The server's fatal signal handler writes the stack trace
to the error log.

sleep_until_file_created(): call it when the wait for the pid file
times out and the process is still alive. This covers the servers
that mtr starts and waits for itself.

check_expected_crash_and_restart(): when mtr restarts a server on
behalf of the test, remember the time by which the
server must have created its pid file ($opt_start_timeout)

run_testcase() wakes up at that time, and if the server is
still alive without a pid file, it dumps core, fails the test with
"Failed to restart mysqldN, no pid file after N seconds" and kills
mysqltest, instead of waiting for it to give up.

mysql_server_wait(): append the server log of the failed server
to the failure report, as the other failure paths do.

Behavior change:
================
A restart done by the test now has to finish within --start-timeout
(180 seconds by default, MTR_START_TIMEOUT), the same as an initial
start. Before, only the test's own wait applied, about 500 seconds
with restart_mysqld.inc. A slow but healthy restart that needs more
than --start-timeout now fails with a core dump. Raise
MTR_START_TIMEOUT for such tests. Under a debugger the timeouts are
much longer, so nothing changes there.

Servers that are only slow, or that mtr has not waited for yet
are not aborted before the timeout.
2026-10-21 22:42:21 +05:30
Oleksandr Byelkin
54fa15e8ea Remove FILE_OPTIONS_STRING after version bump
FILE_OPTIONS_STRING was disabled for 10.11.20 by MDEV-40484.
Use FILE_OPTIONS_ESTRING for the remaining fields (md5,
charset names never contain escaped characters).
2026-10-21 14:09:00 +02:00
Oleksandr Byelkin
dea436e618 bump version 2026-10-21 14:09:00 +02:00
Oleksandr Byelkin
5fc864ece4 Fix MSAN failure in mysqltest with --cursor-protocol after CC update
CONC-821 in Connector/C 3.3.21 no longer resets *length for string
binds, so for NULL just assume 0.
2026-10-21 14:09:00 +02:00
Oleksandr Byelkin
94cdbdf6d5 Revert "Fix MSAN failure in mysqltest with --cursor-protocol after CC update"
This reverts commit 22270903f1.
2026-10-21 14:09:00 +02:00
Marko Mäkelä
44b576bd49 MDEV-41669 ALTER TABLE…IMPORT TABLESPACE may break MVCC
row_import_for_mysql(): Invalidate any old read views that
may have an old snapshot.

Based on mysql/mysql-server@b1fc1e18b7
2026-10-21 13:54:34 +03:00
Marko Mäkelä
44eec404b3 MDEV-41661: Leak and corruption on btr_page_reorganize_low()
btr_page_reorganize_low(): If corruption is found, release the
backup block that had been allocated. This leak was already fixed
in commit fe0c06a232 (MDEV-40408).
Furthermore, restore the contents of the old page in order not
to introduce further corruption.

This was motivated by
mysql/mysql-server@9e497b0773
which seems to aim to do the opposite of
commit c9498f33de (MDEV-18519)
by introducing an intentional crash on corrupted data.

Reviewed by: Alessandro Vetere
2026-10-21 13:15:45 +03:00
Raghunandan Bhat
120162359b MDEV-40616: MSAN - use-of-uninitialized-value in extract_date_time()
Problem:
  STR_TO_DATE(str, format) with %., %@ and %# format specifiers could
  read past the end of str, because the loops in extract_date_time()
  read a byte before checking for the end of str. When str was not
  NUL-terminated, that byte was uninitialized, causing the MSAN error.

Fix:
  Check for the end of str before reading the next byte.
2026-10-21 11:03:54 +05:30
Oleksandr Byelkin
f5f6a3e1f2 Fix sporadic failure of main.charset_client_win_utf8mb4
The test set the password via "chcp 850 && echo ...", but the console
codepage is shared by all parallel mtr workers, so another process could
switch it to UTF8 and the password got stored as UTF8.

Write the cp850 password byte to a file and feed it to the client instead.
2026-10-20 20:07:05 +02:00
Oleksandr Byelkin
22270903f1 Fix MSAN failure in mysqltest with --cursor-protocol after CC update
CONC-821 in Connector/C 3.3.21 no longer resets *length for string
binds, so for NULL values the length array in append_stmt_result()
stayed uninitialized. Zero-fill it on allocation.
2026-10-20 19:22:57 +02:00
Oleksandr Byelkin
ed2944b960 New HeidiSQL v12.21 2026-10-20 19:11:28 +02:00
Oleksandr Byelkin
72a7635ba6 new PCRE2 10.49 2026-10-20 18:58:35 +02:00
Oleksandr Byelkin
7c28d25227 new wolfssl v5.9.4-stable 2026-10-20 18:58:35 +02:00
Oleksandr Byelkin
515f4dc6c3 MDEV-22374 VIEW with security definer require FILE privilege from definer not invoker in case of INTO OUTFILE
Already fixed by MDEV-39493; add a test for the view case.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 16:49:52 +02:00
Oleksandr Byelkin
4ec6cdd9f8 New 3.3 CC 2026-10-20 16:49:52 +02:00
Jan Lindström
48d70262c1 MDEV-40727 rsync SST symlink coverage gaps
Failure:
- Filesystem flush before transfer only checks symlinks directly under
  the data directory, missing a per-table DATA/INDEX DIRECTORY symlink
  one level deeper (MyISAM, Aria), and missing InnoDB's per-table DATA
  DIRECTORY entirely, since that uses a '.isl' text file, not a symlink.
- The database directory transfer recreates symlinks as symlinks. The
  joiner's rsync daemon cannot keep an absolute symlink target as-is,
  so a MyISAM or Aria table placed by DATA DIRECTORY or INDEX DIRECTORY
  comes out unreadable after the SST.

Fix:
- Extend the flush's symlink search to two levels deep, and add a scan
  for '.isl' files, flushing the filesystem each one points to.
- Transfer the database directories with --copy-links instead of
  --links, so a table file reached through a symlink is copied by
  content instead of recreated as a broken symlink.

Test:
- MDEV-40727.test creates an Aria table with DATA DIRECTORY and INDEX
  DIRECTORY and an InnoDB table with DATA DIRECTORY, forces a full SST,
  then checks the donor's log for the flush of both external
  directories and checksums every table in database test between the
  two nodes.

Assisted-by: https://mariadb.org/governance/governance-ai-policy/
2026-10-20 14:36:07 +03:00
Teemu Ollakka
e554119045 MDEV-40727 rsync SST donor stalls in a whole-host sync()
The rsync SST donor ran a bare sync() between the table flush and the
transfer. sync() flushes every mounted filesystem on the host, so its
duration depends on I/O unrelated to the SST. The donor holds FTWRL,
LOCK_log and a paused provider at that point, so the whole server is
frozen until sync() returns.

Flush only the filesystems that hold the files to transfer: the data
directory, an absolute binlog directory, and each symlinked database
directory.

Use the full sync() where 'sync -f' (syncfs) is not available.
2026-10-20 14:36:07 +03:00
Aleksey Midenkov
493ebf0c3d innodb.innodb_buffer_pool_resize_temporary fails with (0/506)
The test reads innodb_buffer_pool_resize_status while the
SET GLOBAL innodb_buffer_pool_size thread is blocked at
buf_pool_shrink_before_wakeup and expects nothing withdrawn yet:

  Withdrawing blocks. (505/505).

But buf_pool_t::resize() sets n_blocks_to_withdraw and
first_to_withdraw and releases buf_pool.mutex before that sync
point. From then on other threads withdraw blocks: allocate() from
any page allocation, buf_LRU_block_free_non_file_page() on eviction,
and the page cleaner LRU batch which evicts pages from the withdrawn
area while to_withdraw is nonzero. So the first counter can be
anything down to 0:

  Withdrawing blocks. (0/506).

The fix masks the first counter in replace_regex, so the result
does not depend on how many blocks were already withdrawn.

This does not weaken the test: it still checks that the shrink is
reported while in progress. How many blocks are already withdrawn at
that moment depends only on timing.
2026-10-20 12:49:36 +03:00
Sergei Golubchik
8cedfdf7e3 MDEV-34817 perfschema.lowercase_fs_off fails on buildbot
initialize counters when constructing a new PFS_program object

The test fails because a newly created routine can get a performance
schema slot freed by a routine dropped in an earlier test. The counters
of a reused slot are not reset, so the new routine shows the old
routine's statistics.
2026-10-20 12:49:36 +03:00
Alessandro Vetere
c0eea2b8c5 MDEV-41398 Stale optimistic btr_pcur_t restore after buffer pool resize
Problem: btr_pcur_t::restore_position() accepts a stored position
optimistically when the block at the stored descriptor address has the
same page id and the same buf_block_t::modify_clock. When
buf_pool_t::resize() shrinks the buffer pool, the withdrawn block
descriptors are freed. When it grows the buffer pool again, the new
descriptors at the same addresses start with modify_clock=0. A cursor
that was stored before the shrink can then find a different instance of
the page with an equal modify_clock, and it restores to a record that
is no longer correct. In a release build, an UPDATE can change a row
that does not match its WHERE condition and skip the rows that match.

Fix: Add buf_pool_t::withdrawn_modify_clock. buf_pool_t::shrink() sets
it to the maximum modify_clock of the blocks that it withdraws.
buf_pool_t::resize() sets the initial modify_clock of each block that
it adds to one more than this. A relocation in shrink() increments only
the modify_clock of the destination block, so a withdrawn block can
keep the value that a cursor stored. Thus the modify_clock at a block
descriptor address never repeats an earlier value, and a stale
optimistic restore fails. The new member uses a hole before
buf_pool_t::flush_list_mutex, so the layout of the other members does
not change.

The test innodb.buf_pool_resize_pcur_restore reads a page into the
first new block after a grow, and makes a stored cursor for a read and
for an UPDATE restore its position across a page reorganization, a
shrink and a grow.
2026-10-20 09:51:37 +02:00
Vladislav Vaintroub
fb641b0cd1 MDEV-40287 AES_ENCRYPT() and KDF() return NULL with OpenSSL 4.0
MyCTX used an EVP_CIPHER_CTX in a stack buffer instead of allocating it
with EVP_CIPHER_CTX_new(). OpenSSL 4.0 rejects a context that was not
created that way for ciphers that use an IV: EVP_CipherInit_ex() fails
with "invalid iv length", so AES_ENCRYPT() and KDF() in CBC/CTR/GCM
modes return NULL. ECB has no IV and still works, which is why only the
non-ECB modes broke.

Allocate the context with EVP_CIPHER_CTX_new()/EVP_CIPHER_CTX_free(), and
on an init error free and null it, so a later update()/finish() from a
caller that ignored the error is a safe no-op, not a double free. Remove
check_openssl_compatibility() and the EVP_CIPHER_CTX_SIZE and
EVP_CIPHER_CTX_init macros.

my_md5() used the same stack-buffer-sized-by-EVP_MD_CTX_SIZE hack, whose
only guard was check_openssl_compatibility(). MD5_CTX is a concrete struct
in both OpenSSL and WolfSSL, so use it directly with MD5_Init/Update/Final
on a caller-owned context, like my_sha.inl does for SHA*_CTX; this removes
the EVP_MD_CTX hack and EVP_MD_CTX_SIZE. The exception is OpenSSL 1.0.x,
which aborts on the low-level MD5 API in FIPS mode (MDEV-7788): there, and
only there, keep the EVP path with the non-FIPS flag. 1.1.0 removed the
FIPS Object Module and 3.0+ low-level MD5 bypasses the provider, so the
concrete MD5_CTX is correct on every other version. SHA is unaffected, it
already used concrete SHA*_CTX structs.

Verified against OpenSSL 4.0.1: the mysys aes-t test fails on the
CBC/CTR/GCM cases with the stack buffer and passes with
EVP_CIPHER_CTX_new(). The 1.0.x MD5 path verified against a FIPS build of
OpenSSL 1.0.2u: the EVP path computes MD5, the low-level path aborts.

No visible performance degradation: the extra allocation costs
~12 ns/call (WolfSSL) and ~30 ns (OpenSSL) on Windows at a 30-byte
payload, nothing at 16 KB, and nothing on Linux/glibc; sysbench OLTP
over encrypted tables and redo log is unchanged.

Tests main.tlsv13 and main.ssl_crl: OpenSSL 4.0.3 reports TLS alerts as
"tls alert ..." (was "ssl/tls alert ..."), accept both.

Assisted-by: Claude:claude-opus-4-8
2026-10-20 01:59:37 +02:00
Vladislav Vaintroub
9660806dc9 MDEV-41508 Off-by-One Uninitialized Stack Read in Proxy Protocol V2 Port Parsing
parse_v2_header() required only 25 (TCPv4) / 49 (TCPv6) bytes, but then
reads the source port at hdr[25] / hdr[49]. A truncated header could make
it read uninitialized stack.

Require the whole address block: 28 bytes for TCPv4 and 52 for TCPv6.

Also, the declared header length was trusted without checking how many
bytes vio_read() returned. Reject short reads. The spec requires the
sender to send the header at once, and allows the receiver to drop the
connection on a partial header, so a single vio_read() is enough.

The v1 parser had the same problem on EOF: vio_read() returning 0 was
taken for a byte read, so the uninitialized buffer was parsed. Require
exactly one byte.

Extend test_proxy_header_tcp with a header cut short before the port,
and add test_proxy_header_short for a header shorter than it declares.

Light refactoring, to avoid repetition: added connect_tcp() and
init_v2_header(), which are now shared by several proxy header tests.

Assisted-by: Claude:claude-sonnet-5-5
2026-10-19 20:44:49 +02:00
Aleksey Midenkov
e63f94313a MDEV-40380 vcol.races sporadic timeout
After MDEV-39261 purge opens TABLE via open_purge_table() for any
undo record of a table with indexed virtual columns, including the
insert undo record. If purge does that after FLUSH TABLES, the TABLE
is put back into the table cache. Then DELETE from con1 reuses the
cached TABLE, skips open_table_from_share() and never hits the
TABLE_after_field_clone sync point. DELETE completes immediately,
wait_condition times out and SELECT returns an empty set.

The fix waits for purge to complete before FLUSH TABLES.
2026-10-19 14:19:42 +03:00
Aleksey Midenkov
d5815e3843 MDEV-41583 Tests fail on platform-dependent max TIMESTAMP of current row
versioning.partition (MDEV-41543) and main.grant2 (MDEV-41099) print
row_end of the current row. Since MDEV-32188 in 11.5 the max TIMESTAMP
is 2106-02-07 06:28:15.999999 on 64-bit and 2038-01-19 03:14:07.999999
on 32-bit, so the results recorded on 64-bit fail on 32-bit.

The fix prints CURRENT instead of row_end of the current row in
versioning.partition (using current_row_ts() from common.inc) and
replaces row_end with # in main.grant2, where only the privilege to
read it is tested.

Affected since 11.8. The fix is committed to the originating 10.11 to
minimize conflicts.
2026-10-19 14:19:42 +03:00
forkfun
85ecdbe546 MDEV-39146 Fix stack-use-after-return in PROCESSLIST for event threads
Event_job_data::execute() pointed thd->security_ctx at a local
Security_context. A concurrent PROCESSLIST scan captures that pointer
without a lock and can read it after execute() returns.

Make the Security_context a member of Event_job_data, which lives in
Event_worker_thread::run() until after thd is deleted.

Add main.events_debug test
2026-10-19 11:34:03 +02:00
sjaakola
744b2ca998 MDEV-41553 galera_restart_on_unknown_option test regression after MDEV-40023
The problem with the test was that it restarted node 2 by writing
"try:--galera-unknown-option" into the expect file. However, MariaDB mtr has
never supported a "try" command. Instead mtr skipped any expect file line not
starting with "restart", and node 2 was not started with the unknown option
(which was the idea in the test logic). The test only slept and then restarted
node 2 normally.
MDEV-40023 made mtr report unknown expect file commands as errors,
so the test now fails in 13.1 and later.

The fix is to start node 2 with the unknown option directly with --exec.
In cluster, the unknown option is found only after the state transfer has started.
The server should interrupt the state transfer and abort.

Galera version 26.4.25 or later is needed for graceful shutdown, and this is now
required by the test.
2026-10-19 10:51:13 +03:00
Oleksandr Byelkin
f6869f9068 MDEV-41405 ASAN stack-buffer-overflow TDBXML::Initialize/TDBXML::OpenDB after insert into CONNECT table
XmlDB was copied with strcpy/strcat into a 64-byte stack buffer to
build the XPath. Tabname used the same buffer with snprintf, silently
truncating the XPath.

Build the XPath in a buffer allocated by its real length.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 10:58:15 +11:00
Aleksey Midenkov
26823fe344 MDEV-39074 trans_rollback_stmt(THD *): Assertion `! thd->in_sub_stmt' failed.
slave_close_thread_tables() unconditionally called
trans_commit_stmt()/trans_rollback_stmt(), which assert
!thd->in_sub_stmt. A BINLOG statement with malformed base64 payload
executed from an AFTER INSERT trigger hits this: on decode failure,
mysql_client_binlog_statement() sets thd->is_error() and calls
slave_close_thread_tables() from within the trigger's sub-statement.

The fix refuses BINLOG in stored routines, triggers, events and
anonymous blocks with ER_SP_BADSTATEMENT at parse time, like LOCK,
HANDLER etc. Dynamic SQL (EXECUTE IMMEDIATE, EXECUTE) run from a
routine bypasses the parser check, so mysql_client_binlog_statement()
checks spcont as well: in a stored procedure in_sub_stmt is 0, but the
decoded events assert !spcont in reset_for_next_command().

1. BINLOG statement executed from a trigger, SF or SP is disabled
by the patch:

Row events (Rows_log_event) open their target table via a
one-shot check that only fires at the top of a fresh statement.
Inside a trigger, the table is never opened this way. It may be
fixed by reusing query_tables, but:

  - find_locked_table() matches only by table name -- it could return
    the TABLE instance the enclosing statement is actively writing
    through, not an idle one. Reusing it would require pre-saving its
    state: record[0]/bitmaps/handler/etc. (and would bypass
    ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG)

  - set_stmt_row_injection()/set_time() calls would mutate thd->lex,
    which at that point is main_lex -- shared with the enclosing
    statement, not something safe to touch.

Statement events (Query_log_event) run the embedded query via
mysql_parse(): it bundles lex_start(), reset_for_next_command() and
parse_sql() as one unit meant for a genuinely new top-level statement,
not a one-off nested parse.

Calling parse_sql() directly instead avoids that, but then we own
everything mysql_parse() was doing for us: a private LEX and a
private Query_arena (or allocations land on main_lex/whatever arena
is currently active, shared with the enclosing statement), plus
calling mysql_execute_command() ourselves afterwards.

In any case, DML for query_tables cannot be done due to
ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG reasons explained above.

2. PS for BINLOG statement still works and needs a leak fix for
statement events:

A BINLOG statement decoding to a Query_log_event, executed via
PREPARE/EXECUTE, leaked its nested query's allocations onto the PS's
own persistent arena: thd->stmt_arena pointed at it while mysql_parse()
ran the decoded query. Second EXECUTE asserted on ROOT_FLAG_READ_ONLY,
since PROTECT_STATEMENT_MEMROOT marks that arena read-only after a
successful execution.

The fix redirects thd->stmt_arena to thd itself for the duration of
the event application, so stmt_arena->is_conventional() reads
true and activate_stmt_arena_if_needed() (called e.g. from
save_leaf_tables()) never redirects allocations to the PS's arena in
the first place.

Harmless for what it's protecting: leaf_tables_exec is normally cached
on the persistent arena so a repeatedly-executed statement's
SELECT_LEX doesn't rebuild it every time, but our SELECT_LEX is torn
down and reparsed fresh (due to mysql_parse() semantics) on every
EXECUTE, so there's nothing to cache here regardless of which arena is
used.
2026-10-15 19:58:38 +03:00
Sergei Golubchik
29a5c93f5b Revert "MDEV-36832 UPDATE...IN(SELECT) acquires spurious gap locks on FK index"
This reverts commit f4a3b69bdf. As agreed with the contributor.
It breaks 11.4.
2026-10-15 16:01:21 +02:00
Aleksey Midenkov
1716bf8fc9 MDEV-25176 Shutdown hangs if event scheduler is started during shutdown
SET GLOBAL event_scheduler=1 executed by a connection during shutdown
could start the scheduler thread after close_connections() called
Events::stop(). Nothing stops this thread and close_connections()
waits for it forever.

Now it hangs instead of a crash since MDEV-30260 fix: it moved
deinit() from close_connections() to clean_up(), so the scheduler is
not freed under the running thread anymore.

The fix makes Event_scheduler::start() do nothing when abort_loop is
set. abort_loop is set before close_connections() and is checked under
LOCK_scheduler_state, which stop() also takes, so the scheduler is
either started before stop() and stopped by it, or not started at all.
No error needed: the server is shutting down.
2026-10-15 15:17:00 +03:00
Aleksey Midenkov
c4841783cd MDEV-41545 Unchecked get_clone() in ALTER of partitioned table crashes on out-of-memory
get_clone() returns NULL on out-of-memory, but two of its callers in
prep_alter_part_table() dereferenced the result without a check, so the
server crashed:

  changed INTERVAL of SYSTEM_TIME partitioning
  ADD PARTITION under LOCK TABLES

get_clone() itself did not check the allocation of Vers_part_info and
dereferenced it.

handle_alter_part_error() did not check the clone either. The clone only
kept the DDL log entries after the table is closed. In the branch where
DDL log recovery fails, write_log_completed() released the entries
through lpt->part_info, which the table close may have freed, and
release_log_entries() released the same entries again through the
clone. That branch is not reachable now, as ddl_log_execute_entry()
always returns false.

The fix checks the allocation of Vers_part_info in get_clone() and the
result of get_clone() in prep_alter_part_table() like the other callers
there do. handle_alter_part_error() keeps a copy of DDL_LOG_STATE
instead of the clone and passes it to write_log_completed() and
release_log_entries(), which now take DDL_LOG_STATE. The redundant
release_log_entries() after write_log_completed() is removed.
2026-10-15 13:59:19 +03:00
Aleksey Midenkov
101af8ee09 MDEV-41543 Changing INTERVAL of SYSTEM_TIME partitioning does not move history
ALTER TABLE ... PARTITION BY SYSTEM_TIME with a changed INTERVAL or
STARTS on a table already partitioned by SYSTEM_TIME took the fast
ALTER path, which only rewrites the table definition. The history rows
stayed where the old layout put them, so after the ALTER they were in
wrong partitions. An unchanged interval took the copy path instead.

MDEV-29873 replaced memcmp() of the intervals, which is true when they
differ, with interval_t::operator==, which is true when they are equal,
and lost the negation.

The copy path was also broken: it assigned the whole vers_info of the
new partitioning spec to the cloned partition info, now_part and
hist_part included. The ALTER does not list partitions, so now_part
became NULL and check_partition_info() failed with ER_VERS_WRONG_PARTS
for a table with explicit partitions (MDEV-33370 test case).

The fix negates the comparison again (now with interval_t::operator!=),
so a changed interval rebuilds the table and redistributes the history.
It copies only interval, limit and auto_hist from the new spec and keeps
now_part and hist_part of the existing partitions.

Without STARTS the start of the interval defaults to the current time
rounded down to the INTERVAL unit. So ALTER with the same INTERVAL and
no STARTS usually gets a different start and now rebuilds the table.

Vers_part_info::operator=, which copied now_part and hist_part and had
no other callers, is deleted.

Fast ALTER was also chosen when the same statement changed the table
definition, e.g. ADD COLUMN with the same INTERVAL and STARTS, or DROP
COLUMN with LIMIT. It wrote the new .frm, but the partitions kept the
old record layout. Now any change of the table definition
(alter_info->flags) takes the copy path.
2026-10-15 13:59:19 +03:00
Jan Lindström
7ba0776692 MDEV-39056 : sporadic test failures with galera.galera_toi_ddl_nonconflicting
The test sent

  ALTER TABLE t1 ADD COLUMN f3 INTEGER; INSERT INTO t1 VALUES (NULL, 10000, 10000);

from node_2 as a single --send. Nothing ordered that INSERT against the
CREATE UNIQUE INDEX issued from node_1, so the second DDL could reach node_2
while the INSERT was still executing there and BF-abort it. The automatic
autocommit retry then replicated with last_seen_seqno behind the seqno of the
DDL and failed certification against its exclusive key on test.t1. As
wsrep_retry_autocommit defaults to 1 there was no second retry and the client
got ER_LOCK_DEADLOCK.

Send only the ALTER TABLE and execute the INSERT after both DDL statements
have completed on both nodes.

Waiting for the second DDL by polling INFORMATION_SCHEMA.PROCESSLIST did not
prove that it had been ordered either: wsrep_TOI_begin() sets the
"Waiting to execute in isolation" stage before it replicates the writeset, so
that state can be observed before the DDL has reached total order. Wait on
node_2 for the new index to appear instead, which happens only once the DDL
has been ordered behind the parked ALTER TABLE, and record on node_1 that
neither DDL has been applied there while the first one is still parked.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-14 16:08:30 +03:00
Jan Lindström
75fe7a5118 MDEV-41505 : Sql_cmd_show_routine_code::execute does not call wsrep_sync_wait()
There was no wsrep_sync_wait on Sql_cmd_show_routine_code::execute.
2026-10-14 11:31:29 +03:00
DerZc
e331450f1b MDEV-39969: Incorrect result of JSON_TABLE with BIT
Problem: JSON_TABLE maps JSON numbers [0,1] to BIT(1) values [1,1].
The scalar helper passes decimal text to BIT's binary-string store,
so the byte for '0' is 48 and is clipped to 1.

Fix: Add Field::store_numeric() for number literals serialized as text,
including fractions and exponents, and use it for JSON_TABLE numbers.
BIT parses these literals as rounded unsigned integers and applies its
existing range checks. Other fields retain their existing conversion;
JSON strings and booleans retain their existing storage paths.
Preserve the existing distinction between conversion warnings and JSON
structural errors, so numeric overflow does not invoke ON ERROR.
Extend json.json_table to cover BIT widths, unsigned boundaries,
fractions, exponents, boolean/string/null inputs, other field types,
conversion warnings and ON ERROR responses.

Assisted-by: OpenAI Codex:gpt-6
2026-10-14 12:57:43 +05:30
Hemant Dangi
94f80cbfa2 MDEV-35812: generate-ssl-certs.sh: remove bashism
Issue:
generate-ssl-certs.sh is a /bin/sh script but uses process substitution
(<(printf ...)) for -extfile, which fails with plain sh.

Solution:
Write the extensions to a file in gcadir/ and pass it to -extfile.
2026-10-14 10:45:30 +11:00
DerZc
46ea84b186 MDEV-39194: Fix DISTINCT bit and hex aggregation
Problem: SUM(DISTINCT b'1100') returns 9 instead of 12. The hybrid
hex/bit literal handler uses the default DOUBLE temporary field, so
its byte length becomes a DOUBLE(M,0) display width and clips the
numeric value.

Fix: Override numeric DISTINCT field construction for hybrid hex and
bit literals to allocate an unsigned Field_longlong directly. Preserve
argument-based field selection for other types so DISTINCT retains the
input expression's precision and scale, including decimal AVG inputs.
Extend main.sum_distinct to cover bit and hex literals, zero, byte and
unsigned 64-bit boundaries, duplicates, AVG, COUNT and decimal scale.

Recreated-by: Georgi "Joro" Kodinov <joro@mariadb.org>
2026-10-13 19:39:19 +03:00
Thirunarayanan Balathandayuthapani
a466cdb832 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.
2026-10-13 19:04:31 +05:30
Aleksey Midenkov
ac9c38fde0 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.
2026-10-13 15:07:25 +03:00
greypilgrim-083
8226e48ab5 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.
2026-10-13 12:19:46 +03:00
Vladislav Vaintroub
bf6311c49e 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.
2026-10-13 01:26:47 +02:00
Vladislav Vaintroub
8313e576da 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.
2026-10-13 01:26:47 +02:00
Rex Johnston
378d5bd10e 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.
2026-10-13 07:06:17 +13:00
Khaled Riyad
8bee0f3610 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.
2026-10-12 19:38:02 +03:00
Maximilian Krög
ce6b2906ca 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) <noreply@anthropic.com>
2026-10-12 14:16:49 +03:00
PranavKTiwari
b9d4b10954 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.
2026-10-12 12:03:54 +05:30
Marko Mäkelä
7aecfef107 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
2026-10-12 08:28:06 +03:00
PranavKTiwari
507a7217d3 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.
2026-10-12 10:54:50 +05:30