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
Rion Bora
MDEV-40545 mariadb-binlog --force-read loops on truncated events

What was wrong:
With --force-read, Log_event::read_log_event() returned a synthetic
"Encrypted event" (Unknown_log_event) for every read error. A
truncated event is such an error, so mariadb-binlog printed a fake
event instead of stopping, and on most truncated binlogs it then never
stopped at all.

How it is fixed:
The synthetic event is meant for encrypted events that mariadb-binlog
cannot decrypt (MDEV-11319). It is now returned only for a decryption
failure. Other read errors, like a truncated event or an out of memory
error, are critical: continuing after them cannot produce meaningful
output, so they are reported and mariadb-binlog stops as it does
without --force-read.

How it is tested:
main.mysqlbinlog_force_read_truncated reads two truncated binlogs from
std_data, one with a truncated event header and one with a truncated
event body. The test loops forever without the fix.
Thirunarayanan Balathandayuthapani
MDEV-41666 Corruption on statement rollback when ON UPDATE SET NULL affects the base column

Problem:
=======
  - When a foreign key column is the base column of a
virtual column that is indexed together with other virtual
columns, a cascaded update (ON UPDATE/DELETE SET NULL)
computed the old value of only the dependent virtual column.
The other virtual key parts of the index stayed NULL in
update->old_vrow. If the statement was rolled back,
row_upd_store_v_row() used those NULLs, so
row_upd_sec_index_entry() searched the secondary
index for a record  that did not exist and hit
the "Record in index was not found on update" assertion.

Solution:
=========
dict_mem_fill_vcol_set_for_base_col():  Add every virtual key part
of each index that contains the dependent virtual column to
dict_foreign_t::v_cols, as dict_mem_fill_vcol_from_v_indexes()
already does. row_ins_foreign_fill_virtual() then computes the
old values of all of them.

Based on mysql/mysql-server@c48fa1e57a8e810f89b43d3e94bcbefa1fd69806
Sergei Golubchik
fixup! cleanup: use a local HTTP server in connect.rest
Oleksandr Byelkin
Merge branch '11.4' into 11.8
Oleksandr Byelkin
bump version
Andrzej Jarzabek
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.
Sergei Golubchik
wip: git-precise
Jan Lindström
MDEV-41490 ignore_db_dirs not working with SST

rsync and mariabackup SST ignored ignore_db_dirs: rsync copied and
deleted such directories like a normal schema dir, and mariabackup's
joiner wiped them during its pre-apply cleanup, failing SST outright
on a read-only mount. A directory name is also unvalidated by the
server, so it was spliced unchecked into an eval'd rsync filter.

Fix both SST scripts to read ignore_db_dirs and exclude those
directories, accepting only safe characters in the name.

Assisted-by: https://mariadb.org/governance/governance-ai-policy/
Aleksey Midenkov
MDEV-41493 AFTER UPDATE trigger reads wrong NEW value of BLOB/TEXT virtual column in system-versioned table

UPDATE, multi-table UPDATE, INSERT ... ON DUPLICATE KEY UPDATE and the
RBR Update_rows applier save the new row into record[2] and call
vers_insert_history_row(), which restores the old row from record[1]
and sets its row_end with vers_update_end(). The
VCOL_UPDATE_FOR_WRITE computation in vers_update_end() stored the
virtual blobs of the old row into Field_blob::value, the buffer that
the virtual blobs of the new row in record[2] point to, or reallocated
it when the old value was longer. After restore_record(record[2]),
AFTER UPDATE triggers read the old value, or freed memory, as NEW.

remember_blob_values() and restore_blob_values() skipped virtual
GEOMETRY columns: they selected MYSQL_TYPE_BLOB, while
virtual_not_stored_blob_fields counts all fields with BLOB_FLAG. So
GEOMETRY had the same problem also in TABLE::delete_row() for REPLACE
and DELETE.

UPDATE ... FOR PORTION OF has the same problem in period_make_insert(),
which computes the inserted leftover rows into record[0] while the new
row is saved in record[2], also for tables without system versioning.

The fix saves Field_blob::value with remember_blob_values() before the
history row in vers_insert_history_row() or the leftover row in
period_make_insert() is computed, and puts it back with
restore_blob_values() afterwards, as TABLE::delete_row() already does
for REPLACE (for DELETE it frees the saved values instead).
remember_blob_values() and restore_blob_values() now select fields by
BLOB_FLAG.
Dave Gosselin
MDEV-41746:  IN subquery accepted with OFFSET clause

OFFSET without LIMIT or FETCH gives a clause with an offset but no row
count.  Several places tested only the row count, so they treated such
a clause as absent.  IN, ALL and ANY subqueries accepted the offset and
ignored it, derived tables were merged into the outer query and lost
the offset, and view definitions were saved without it.  In addition,
DISTINCT and GROUP BY were removed from EXISTS subqueries whose clause
skips rows, as in OFFSET 3 ROWS or LIMIT 3, 1.  Without them the
subquery can return more rows, so EXISTS can find a row past the offset
where there should be none.

Lex_select_limit gains keeps_all_rows() and starts_at_first_row(),
which take the offset into account, and these places now use them.
The error for IN, ALL and ANY names OFFSET when the subquery has no
row count.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Kristian Nielsen
Merge branch 'knielsen_log_event_read_validation_base_11.4' into 11.8

This merges the patch series that fixes a lot of missing validation
checks for read_log_event(). The merge includes a few added fixes that
are needed in new code introduced in 11.8.

Signed-off-by: Kristian Nielsen <[email protected]>
Dave Gosselin
MDEV-41746:  IN subquery accepted with OFFSET clause

OFFSET without LIMIT or FETCH gives a clause with an offset but no row
count.  Several places tested only the row count, so they treated such
a clause as absent.  IN, ALL and ANY subqueries accepted the offset and
ignored it, derived tables were merged into the outer query and lost
the offset, and view definitions were saved without it.  In addition,
DISTINCT and GROUP BY were removed from EXISTS subqueries whose clause
skips rows, as in OFFSET 3 ROWS or LIMIT 3, 1.  Without them the
subquery can return more rows, so EXISTS can find a row past the offset
where there should be none.

Lex_select_limit gains keeps_all_rows() and starts_at_first_row(),
which take the offset into account, and these places now use them.
The error for IN, ALL and ANY names OFFSET when the subquery has no
row count.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Vladislav Vaintroub
MDEV-41691 PROXY protocol v1 header parser is too lenient

Follow the specification: the line is at most 107 bytes including CRLF,
ends with CRLF (not a bare LF), and fields are separated by exactly one
space, with nothing trailing (except after UNKNOWN). Ports are decimal
numbers up to 65535, without signs or leading zeroes. Also reject NUL
bytes and unknown address families (these were accepted before).

test_proxy_header_limits() now checks that malformed headers are
rejected, and also avoid DNS name resolution.

Assisted-by: Claude:claude-sonnet-5-5
Dave Gosselin
MDEV-39173:  Use snprintf in the remaining sprintf calls

Convert all three calls to snprintf.  12.3 already has the same change
for slave.cc, made in merge commit 9f98f82b14a.

MDEV-39173 replaced sprintf with snprintf in 10.11 and removed the
pragma in violite.h that hid deprecation warnings.  Two calls in
slave.cc and one in mysqltest.cc were added after 10.11, so 11.4 was
out of date and produces sprintf deprecation warnings (at least on
macOS).

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Thirunarayanan Balathandayuthapani
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.
Kristian Nielsen
Merge branch 'knielsen_log_event_read_validation_base_11.4' into 11.4
Kristian Nielsen
Merge branch 'knielsen_log_event_read_validation_base_10.11' into 11.4

This merges the patch series that fixes a lot of missing validation
checks for read_log_event(). The merge includes a few added fixes that
are needed in new code introduced in 11.4.

Signed-off-by: Kristian Nielsen <[email protected]>
David Schilling
MDEV-41450 TOI DDL BF-aborts InnoDB purge, purge loops forever

Fix for MDEV-38218 changed MDL conflict handling to allow high priority
cluster threads to BF abort any conflicting MDL lock holder.
With this, the InnoDB purge coordinator became also potential target
for BF aborts.
However, InnoDB purge thread has no statement boundary and could never
reset THD::killed state, after the BF abort. Purge THDs are taken
from a pool of innodb_purge_threads_MAX THDs, so about 32 purge runs
later the killed THD coordinates purge again. From then on every
open_purge_table() for a table with an indexed virtual column fails,
and purge_sys_t::close_and_reopen() retries forever. Purge stops and
server shutdown hangs.

Separately, open_purge_table() allocates a TABLE_LIST on thd->mem_root
and the coordinator THD never freed its mem_root, so it grew with every
purge batch and every close_and_reopen() retry.

Fix:
- wsrep_handle_mdl_conflict(): when the granted thread is a
  SYSTEM_THREAD_GENERIC THD holding explicit MDL, make the BF requestor
  wait instead of aborting it. In practice this covers the InnoDB
  background threads (purge, statistics, FTS optimizer), which release
  their locks on their own. This restores the pre-MDEV-38218 behaviour
  for these threads only.
- open_purge_table(): open with MYSQL_OPEN_IGNORE_KILLED so that a stale
  kill flag cannot block purge.
- trx_purge_close_tables(): call reset_thd() instead of
  close_thread_tables() to free the coordinator's mem_root per batch.

This commit has a new mtr test galera.MDEV-41450

This work is based on pull request https://github.com/MariaDB/server/pull/5854
by David Schilling, which is now rebased to MariaDB 10.11 and extended to
have a mtr test.

Assisted-by: https://mariadb.org/governance/governance-ai-policy/
Kristian Nielsen
Merge branch 'knielsen_log_event_read_validation_base_11.8' into 11.8

Signed-off-by: Kristian Nielsen <[email protected]>
Aleksey Midenkov
MDEV-40854 Use of uninitialized table_will_be_deleted in federated engine

MemorySanitizer report:

==851408==WARNING: MemorySanitizer: use-of-uninitialized-value
    #0 ha_federated::end_bulk_insert() storage/federated/ha_federated.cc:2035:30
    #1 mysql_insert(THD*, ...) sql/sql_insert.cc:1258:11
    ...
  Memory was marked as uninitialized
    #0 __msan_allocated_memory
    #1 my_malloc mysys/my_malloc.c:116:7
SUMMARY: MemorySanitizer: use-of-uninitialized-value ... end_bulk_insert()

table_will_be_deleted is a handler member with no in-class
initializer, and the handler object itself is heap-allocated via
my_malloc(), so it starts out as garbage. It was only ever set in
extra(HA_EXTRA_PREPARE_FOR_DROP) and in external_lock(). For a
TEMPORARY table, statement execution can reach end_bulk_insert(),
which reads the flag, without external_lock() having run first, so the
read sees uninitialized memory.

The fix initializes table_will_be_deleted in reset(). Both
ha_federated::open() and ha_federatedx::open() call reset(), so the
flag is initialized on first open and cleared after every statement.
That also covers the first statement after open (e.g. CREATE TEMPORARY
TABLE ... ENGINE=FEDERATED ... SELECT, where external_lock() is not
called).
Aleksey Midenkov
MDEV-39306 Index corruption on UPDATE when using versioned InnoDB table (on UPDATE)

Duplicated by:

MDEV-39711 UPDATE on System-Versioned Tables uses the after-value
          in Row-format Binlog's before-image
MDEV-24646 ASAN heap-use-after-free in Field_blob::pack /
          THD::binlog_update_row upon DML on table with virtual column

vers_update_fields() recomputed virtual fields with VCOL_UPDATE_FOR_READ.
For BLOB virtual columns this mode swaps Field_blob::value and read_value
after the computation (swap_values). After the swap, Field_blob::value
holds the buffer that record[1] (the old row image) points to. The next
VCOL_UPDATE_FOR_WRITE computation, done by fill_record() right after
vers_update_fields(), stores the new value into that buffer and so
overwrites the old row image. As a result, InnoDB builds the old
secondary-index key from the new value (MDEV-39306), and the row-format
binlog writes the new value into the before-image (MDEV-39711), or a
freed buffer (MDEV-24646).

REPLACE had the same problem with record[2]. TABLE::delete_row() saves
the new row into record[2] and turns the conflicting row into history
with vers_update_end(). Its VCOL_UPDATE_FOR_WRITE computation stored
the virtual blobs of the old row into Field_blob::value, the buffer
record[2] points to, so the new row was written with them. Versioned
DELETE had the same problem with record[1]: it points to the virtual
blobs computed with VCOL_UPDATE_FOR_DELETE in Field_blob::value, and
vers_update_end() overwrote them.

The fix removes the virtual fields computation from vers_update_fields().
Its callers now recompute virtual fields with VCOL_UPDATE_FOR_WRITE after
the system fields are set: fill_record() already did, while
update_generated_fields(), multi_update::do_updates() and the RBR
appliers do it explicitly. multi_update::do_updates() still computes
virtual fields twice per row: before BEFORE triggers and after
vers_update_fields(), since the system fields cannot be set before
compare_record(). For REPLACE and DELETE, TABLE::delete_row() keeps
Field_blob::value with remember_blob_values() while it updates the
history row.

In the RBR appliers no VCOL_UPDATE_FOR_WRITE followed
vers_update_fields(), so record[1] was not overwritten there. Their
explicit computation replaces the one removed from vers_update_fields().
It uses VCOL_UPDATE_FOR_WRITE, so an error in a virtual field
expression now stops the slave instead of being turned into a warning.

In the Update_rows applier, vers_insert_history_row() also overwrote
the error of ha_update_row(), so a failed update on the slave was
ignored and its history row was written. The history row is now
written only when the update succeeded.

Based on the MDEV-24646/MDEV-39711 fix by ParadoxV5 (0c2f3de1a2d),
which switched vers_update_fields() to VCOL_UPDATE_FOR_WRITE.
Oleksandr Byelkin
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).
Sergei Golubchik
MDEV-41496 uservars that are queried and modified can show up differently in PS

This is a documented UB anyway, so as long as it doesn't crash
we can keep it that way.
Aleksey Midenkov
MDEV-41621 Stored generated BLOB column is wrong on REPLACE into versioned table

REPLACE into a system-versioned table turns the conflicting row into
history in TABLE::delete_row(): it saves the new row into record[2],
restores the conflicting row from record[1] and sets its row_end with
vers_update_end(). The VCOL_UPDATE_FOR_WRITE computation in
vers_update_end() also recomputes stored generated columns. When
Field_blob::store() copies the value into Field_blob::value (e.g. on a
character set conversion), it overwrote the buffer that the stored
generated blob of the new row in record[2] points to, and the new row
was written with the value of the history row. The index on the column
holds the same value, so CHECK TABLE does not detect it.

remember_blob_values(), which keeps Field_blob::value around
vers_update_end() in TABLE::delete_row() and vers_insert_history_row()
and around update_generated_fields() in period_make_insert(), covered
only virtual columns.

The fix adds the with_stored parameter to remember_blob_values(),
restore_blob_values() and free_blob_values(), which also covers stored
generated blob columns. TABLE::delete_row(), vers_insert_history_row()
and period_make_insert() use it and size the storage by
TABLE_SHARE::virtual_fields, the number of all generated columns.
Aleksey Midenkov
MDEV-41617 Index corruption on UPDATE of table with long unique hash collision and indexed virtual blob

handler::check_duplicate_long_entry_key() reads all rows with the same
long unique hash. Each read (ha_index_read_map() and every
ha_index_next_same() hit) runs TABLE::update_virtual_fields() with
VCOL_UPDATE_FOR_READ, which swaps Field_blob::value and read_value of
virtual blob columns. The swap was undone only after the first read.
Every further read swapped again, so the buffer that record[1] (the old
row of UPDATE) points to ended up in value: the next read stored the
lookup row into it, or restore_blob_values() freed it. InnoDB then
built the old secondary index key from overwritten or freed memory and
did not find the record to update.

The fix undoes the swap after each read.
Oleksandr Byelkin
Merge branch '10.11' into 11.4
Oleksandr Byelkin
Merge branch '11.8' into bb-11.8-release
Thirunarayanan Balathandayuthapani
MDEV-41667 InnoDB: Failing assertion: buf <= (byte*) original_upd_buff + buff_len

Problem:
=======
An UPDATE on an InnoDB table with several indexed virtual columns
could corrupt the heap in calc_row_difference() because the
write pointer went past the end of the update buffer.

ha_innobase::update_row() sized the buffer from the row length, the
maximum key length and fixed padding. That did not allow for the
extra packed values calc_row_difference() stores for indexed
virtual columns for both the new value and the old value.

Solution:
========
  When allocating the update buffer in ha_innobase::update_row(),
add pack_length() of every virtual column. The row length
already counts each virtual column once, so the buffer can now
hold both the new and old packed values. All virtual columns
are counted, not only the indexed ones, because the buffer
is reused and a column may become indexed after it is allocated.

Based on mysql/mysql-server@12655140610674db615547cdf86af1f7cbf563c1
Oleksandr Byelkin
MDEV-41566 Allow ROW_NUMBER as unquoted column name

MDEV-26611 made ROW_NUMBER an always-recognized keyword (for
GET DIAGNOSTICS / SIGNAL) and put it in the reserved keyword list,
so it could no longer be used as an unquoted identifier.

Make ROW_NUMBER_SYM a non-reserved keyword (keyword_sp_var_and_label,
like LAST_VALUE), so ROW_NUMBER() still parses only as the window
function.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Kristian Nielsen
MDEV-41045: Missing virtual columns in binlog break backwards compat for CDCs

Fix a regression for third-party readers of binlog events, where it was
expected that binlog_row_image=FULL would include also values of virtual
columns.

Virtual column values are not useful on the slave (as they will instead be
re-computed from the other column values), but such recomputation can be
difficult to do outside of the server source. It seems reasonable to allow
these column values to be present in the FULL format (even though they are
redundant), as the FULL format in any case usually contains redundant column
values.

Signed-off-by: Kristian Nielsen <[email protected]>
Oleg Smirnov
MDEV-38819 Wrong result of 'Range checked for each record' after pushdown from HAVING

When a condition was pushed from HAVING into WHERE, its fields were
unwrapped in place. The pushed condition then shared field items with
the SELECT list. Creating the GROUP BY temporary table later bound
those items to the temporary table. With a 'Range checked for each
record' plan, range analysis took the value of the outer table's field
from the not yet filled temporary table. It built an impossible range,
and the query returned no rows.

The pushed condition is now cloned before its fields are unwrapped, so
it gets its own field items. Items that cannot be cloned (e.g.
subqueries) are still unwrapped in place, to keep the pushdown. Such
conditions are unlikely to get a 'Range checked for each record' plan.

Cloning can also fail with an error, which the pushdown did not handle
properly. It modifies HAVING before all of its steps have succeeded,
yet on a failure it emptied the list of pushed conditions and let
the query continue, so the conditions already removed from HAVING were
not checked at all.
pushdown_from_having_into_where() now returns an error status, and
the query errors out if the pushdown fails after it may have modified
HAVING.

Based on a contribution by Omar Gamal (PR #4815).

Co-authored-by: OmarGamal10 <[email protected]>
Aleksey Midenkov
MDEV-39306 Comments on update_virtual_fields() modes