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
Sergei Golubchik
MDEV-42025 Unauthenticated handshake converts an unbounded CLIENT_CONNECT_WITH_DB database name

cut the database name to SAFE_NAME_LEN+1 characters before converting
it, a longer name is invalid anyway and stays invalid after the cut.

Assisted-by: Claude:claude-opus-5-5
Yuchen Pei
MDEV-25848 Range optimizer support for JSON_OVERLAPS and JSON_CONTAINS

Implemented get_mm_tree for JSON_OVERLAPS and JSON_CONTAINS.

For each JSON_OVERLAPS/JSON_CONTAINS(field, value), parse the array or
scalar element into a list. Map with get_mm_parts over the list and
tree_or/tree_and the results. At leaf level uses a helper extracted
from MEMBER OF.

Also moved JSON_OVERLAPS to inherit from Item_bool_func2_with_rev due
to its symmetry.
Alessandro Vetere
MDEV-41844 Test innodb.buf_pool_resize_pcur_restore is flaky

The procedure read_into_first_new_block() requires that the page of a
table is read into the first block that a buffer pool grow adds. While
history exists, the purge coordinator runs once per second. It reads
undo log pages, and purge_truncation_callback() reads the header page
of each rollback segment. On a slow builder, these reads can take the
first new block in all 5 attempts.

Stop purge for the duration of the test with FLUSH TABLES ... FOR
EXPORT on a separate connection. A read view does not stop these reads.
Remove the wait for purge between the two cases, because purge is
stopped.

purge_sys_t::stop() waits only for the purge coordinator. Runs of
purge_truncation_callback() that the coordinator submitted before can
still read pages after FLUSH TABLES ... FOR EXPORT returns. Add the
debug keyword purge_stop_wait_truncation, which makes
purge_sys_t::stop() also wait for these runs, and set it in the test.

Assisted-by: Claude:claude-opus-5-5
Rex Johnston
MDEV-39492 PQ: leave a condition the workers cannot evaluate to the manager

A conjunct of a table's condition that no worker can evaluate kept the
whole query serial. The common one is a correlated subquery: its JOIN
belongs to the manager's thread, so there is no clone of it to hand a
worker, and TPC-H Q21's NOT EXISTS over LINEITEM was enough to refuse a
plan whose driving table the optimizer had already costed as a parallel
scan.

The gate now divides each table's condition instead of refusing it
(pwt_split_table_cond). The conjuncts a worker can evaluate stay with the
table, as the worker's select_cond, and the rest are ANDed into
JOIN::parallel_residual_cond for the manager to apply to every row it
drains, after copy_back_row() has put the shipped columns back into the
manager's own records, where the residual's items already look. A
correlated subquery among them runs on the manager's thread through the
manager's own handlers exactly as it would have run serially. A conjunct
of an inner join may be applied anywhere after its tables have been
read, so the answer is the same; what changes is the number of rows it
is asked of, which is the finished join's rather than this table's.

For the residual to be answerable from a drained row, every field it
reads from a join table has to be a shipped column, which
pwt_row_layout::build() takes from the read_set. The split checks that,
walking into subqueries for their outer references, and refuses the plan
if a conjunct can be evaluated on neither side. The split is taken by
the gate and taken again by init_parallel_workers() from the plan as it
stands when the workers are built (pwt_split_plan_conditions), because it
names the plan's own items.

A plan with a residual ships joined rows rather than pre-aggregating:
the filter has to run before any grouping, so pwt_row_layout::build()
takes a ship_rows argument that keeps 'grouped' off while
'plan_aggregates' stays on, which is the fall-back shape the drain
already handles, with the plan's own terminal grouping what the manager
lets through. The non-aggregating drain applies the residual before
sending a row, and before collecting it when the sort is the manager's.
The optimizer trace records the manager's share under
parallel_scan_manager_evaluates.

On TPC-H SF1 Q21 the serial plan evaluates the NOT EXISTS once per late
LINEITEM row of a finished order, 1.8M times, and the manager once per
row of the finished join, 77k times, since the NATION filter has run by
then. With a FirstMatch semijoin admitted to the workers in the next
commit, Q21 goes from 2.9 s serially to 0.85 s with four workers and
0.68 s with eight, with the same result.

main.parallel_query_residual pins the four shapes: whole-table
aggregation, GROUP BY, a plain select, and a select whose sort the
manager performs, each with a correlated subquery in the WHERE clause,
each run in the workers and each giving the serial answer.

This commit was prepared with Claude Code (Fable 5.1), which diagnosed
the refusal from the optimizer trace, measured that applying the
subqueries after the join was cheaper even serially, designed and wrote
the split, the layout change and the drain-side filter, and wrote the
test.
Oleksandr Byelkin
Merge branch 'bb-10.11-release' into bb-11.4-release
Oleksandr Byelkin
MDEV-41258 Crash in Item_func_nextval on prepared re-execution

Sequence prelocking entries were matched across re-executions by
db.str/table_name.str pointer identity, aliasing memory on the TABLE's
own mem_root. Once the owning table was closed and reopened, those
pointers went stale, leaving a dangling duplicate entry that still got
opened and crashed.
Fix: match entries by owning TABLE_LIST and position, deep-copied onto
the statement's own arena.

The relink was gated by has_prelocking_list, which stays true forever
once a trigger is involved, so it silently stopped running after the
first execution for such statements.
Fix: moved it into its own function, called unconditionally per table,
keeping the original gating, scoped to DML statements only.

A stale entry's linked_table pointer could survive its owner's open
being skipped, or a mid-statement open_tables() backoff
(close_tables_for_reopen()), leaving open_table()'s backlink write to
land on freed memory.
Fix: clear it in TABLE_LIST::reinit_before_use() and in
close_tables_for_reopen().

set_parameters() overwrote lex->default_used from each execution's own
bound parameters only, losing a literal DEFAULT written in the
statement text itself.
Fix: also record default_used at prepare time and OR it in.

A mid-execute_loop() reprepare() swaps in a freshly re-parsed lex,
losing "EXECUTE ... USING DEFAULT" already folded into default_used by
set_parameters() for this execution.
Fix: save that bit before reprepare() and OR it back in afterwards.

Assisted-by: Claude:claude-opus-5-5
Oleksandr Byelkin
Merge branch 'bb-10.11-release' into bb-11.4-release
Alexey Yurchenko
MDEV-35940, MDEV-35964 reenable MTR tests

As MDEV-35940, MDEV-35964 have been fixed, reenable tests disabled
because of them
Sergei Petrunia
Merge: MDEV-39226: Push whole multi-table update/delete down into engines
Oleksandr Byelkin
MDEV-41258 Crash in Item_func_nextval on prepared re-execution

Sequence prelocking entries were matched across re-executions by
db.str/table_name.str pointer identity, aliasing memory on the TABLE's
own mem_root. Once the owning table was closed and reopened, those
pointers went stale, leaving a dangling duplicate entry that still got
opened and crashed.
Fix: match entries by owning TABLE_LIST and position, deep-copied onto
the statement's own arena.

The relink was gated by has_prelocking_list, which stays true forever
once a trigger is involved, so it silently stopped running after the
first execution for such statements.
Fix: moved it into its own function, called unconditionally per table,
keeping the original gating, scoped to DML statements only.

A stale entry's linked_table pointer could survive its owner's open
being skipped, or a mid-statement open_tables() backoff
(close_tables_for_reopen()), leaving open_table()'s backlink write to
land on freed memory.
Fix: clear it in TABLE_LIST::reinit_before_use() and in
close_tables_for_reopen().

set_parameters() overwrote lex->default_used from each execution's own
bound parameters only, losing a literal DEFAULT written in the
statement text itself.
Fix: also record default_used at prepare time and OR it in.

A mid-execute_loop() reprepare() swaps in a freshly re-parsed lex,
losing "EXECUTE ... USING DEFAULT" already folded into default_used by
set_parameters() for this execution.
Fix: save that bit before reprepare() and OR it back in afterwards.

Assisted-By: Claude Opus 5.5 <[email protected]>
Daniel Black
MDEV-38913 Debian not installed file pam_mariadb_mtr.so creates test gap (postfix)

The architecture dependent pam_mariadb_mtr.so is mean to be in
the mariadb-test (which is per architecture), rather than
mariadb-test-data, which is architecture independent.

Breaks, is there to highlight they both control the same file,
and Replaces is so that the new mariadb-test can can ownership
fo the previous.

Thanks Elena for noticing.
Oleksandr Byelkin
MDEV-41258 Crash in Item_func_nextval on prepared re-execution

Sequence prelocking entries were matched across re-executions by
db.str/table_name.str pointer identity, aliasing memory on the TABLE's
own mem_root. Once the owning table was closed and reopened, those
pointers went stale, leaving a dangling duplicate entry that still got
opened and crashed.
Fix: match entries by owning TABLE_LIST and position, deep-copied onto
the statement's own arena.

The relink was gated by has_prelocking_list, which stays true forever
once a trigger is involved, so it silently stopped running after the
first execution for such statements.
Fix: moved it into its own function, called unconditionally per table,
keeping the original gating, scoped to DML statements only.

A stale entry's linked_table pointer could survive its owner's open
being skipped, or a mid-statement open_tables() backoff
(close_tables_for_reopen()), leaving open_table()'s backlink write to
land on freed memory.
Fix: clear it in TABLE_LIST::reinit_before_use() and in
close_tables_for_reopen().

set_parameters() overwrote lex->default_used from each execution's own
bound parameters only, losing a literal DEFAULT written in the
statement text itself.
Fix: also record default_used at prepare time and OR it in.

A mid-execute_loop() reprepare() swaps in a freshly re-parsed lex,
losing "EXECUTE ... USING DEFAULT" already folded into default_used by
set_parameters() for this execution.
Fix: save that bit before reprepare() and OR it back in afterwards.

Assisted-By: Claude Opus 5.5 <[email protected]>
Sergei Golubchik
MDEV-40847 Server crash on EXPLAIN EXTENDED or CREATE VIEW of a deeply nested JSON_TABLE

* check the stack in Json_table_nested_path::print(), it recurses
  once per NESTED PATH level
* don't save a view definition if printing it failed
* don't push the EXPLAIN EXTENDED note if printing it failed

Assisted-by: Claude:claude-opus-5-5
Yuchen Pei
MDEV-25848 Range optimizer support for JSON_OVERLAPS and JSON_CONTAINS

Implemented get_mm_tree for JSON_OVERLAPS and JSON_CONTAINS.

For each JSON_OVERLAPS/JSON_CONTAINS(field, value), parse the array or
scalar element into a list. Map with get_mm_parts over the list and
tree_or/tree_and the results. At leaf level uses a helper extracted
from MEMBER OF.

Also moved JSON_OVERLAPS to inherit from Item_bool_func2_with_rev due
to its symmetry.
Marko Mäkelä
MDEV-41813 OPTIMIZE TABLE makes tables grow

PageBulk::init(): Add a parameter for a hint page number, so that we will
try to allocate adjacent pages for the index.

After this change, the innodb_alter_copy_bulk=ON code path may actually
produce smaller files than the legacy code path.

Based on mysql/mysql-server@a3e2dbddec48ec229484bdf082b8c2f34ccf8c0b

Reviewed by: Thirunarayanan Balathandayuthapani
Yuchen Pei
MDEV-25848 one range slot per ARRAY index

Before, every MEMBER OF / JSON_OVERLAPS / JSON_CONTAINS point got its
own cloned KEY_PART and key slot, and points were combined only through
index_merge (OR) or by picking one slot (AND).

Now all points on an ARRAY key part share the original slot:

* SEL_ARG_ARRAY holds a list of make_key() points ("the array contains
  any of them") and the summed records_in_range() estimate and cost,
  taken once when the point is built.
* key_or() of two ARRAY ranges takes the union of the points;
  key_and() keeps the operand with the lower estimate, the WHERE
  condition checks the rest.
* KEY_PART cloning (get_claimed_key_part()) is now RTREE-only, so
  ARRAY-only queries size SEL_TREE::keys by param->keys again.
* QUICK_RANGE_SELECT_ARRAY gets one QUICK_RANGE per point and passes
  all points to hlindex_read_first(); json_index reads them in turn
  and skips trefs it has already returned.
* check_quick_select_array() uses the stored estimate, and rejects
  non-ARRAY SEL_ARGs (e.g. IS NULL) on the ARRAY key part.

ORed MEMBER OF and JSON_OVERLAPS now give a single range scan instead
of index_merge sort_union, with no MAX_KEY limit on the number of
points.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Yuchen Pei
MDEV-25848 one range slot per ARRAY index

Before, every MEMBER OF / JSON_OVERLAPS / JSON_CONTAINS point got its
own cloned KEY_PART and key slot, and points were combined only through
index_merge (OR) or by picking one slot (AND).

Now all points on an ARRAY key part share the original slot:

* SEL_ARG_ARRAY holds a list of make_key() points ("the array contains
  any of them") and the summed records_in_range() estimate and cost,
  taken once when the point is built.
* key_or() of two ARRAY ranges takes the union of the points;
  key_and() keeps the operand with the lower estimate, the WHERE
  condition checks the rest.
* KEY_PART cloning (get_claimed_key_part()) is now RTREE-only, so
  ARRAY-only queries size SEL_TREE::keys by param->keys again.
* QUICK_RANGE_SELECT_ARRAY gets one QUICK_RANGE per point and passes
  all points to hlindex_read_first(); json_index reads them in turn
  and skips trefs it has already returned.
* check_quick_select_array() uses the stored estimate, and rejects
  non-ARRAY SEL_ARGs (e.g. IS NULL) on the ARRAY key part.

ORed MEMBER OF and JSON_OVERLAPS now give a single range scan instead
of index_merge sort_union, with no MAX_KEY limit on the number of
points.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Rex Johnston
MDEV-40012 PQ: refuse a plan that reads a table through a join buffer

A worker has no join buffer. setup_worker_jointabs() stripped the cache off
every worker JOIN_TAB and joined a row at a time, and pwt_table_conds() handed
the worker the buffer's scan filter (cache_select->cond) as well as
select_cond so that it still rejected what the buffer would have. The result
was correct, but it was not the plan the optimizer costed: BNL, BNLH, BKA and
BKAH were chosen for scanning the inner table once per buffer-full of outer
rows, and a worker scanned it once per driving row instead. For a full-scan
inner table that can be orders of magnitude more work than the serial plan
the parallel one is meant to beat.

So the gate now refuses the plan, as the prototype did. The check sits in
can_run_query_in_workers() beside the other per-table refusals, on
tab->cache or tab->use_join_cache, both of which make_join_readinfo() has
settled by the time parallel_join_check() runs in optimize_stage2(). The
refusal names the table in the optimizer trace.

The worker-side handling of a buffered table goes with it:

- pwt_table_conds() becomes pwt_table_cond() and no longer reports
  cache_select->cond. remove_redundant_bnl_scan_conds() only moves conjuncts
  out of select_cond when the tab has a BNL/BNLH cache, so for every tab the
  gate now admits select_cond is already the whole condition. A tab can still
  carry a cache_select without a buffer, because make_join_select() builds the
  scan filter before check_join_cache_usage() decides, but its cond is then a
  copy of conjuncts select_cond still holds. The gate no longer asks whether
  that copy is worker-safe, since no worker evaluates it.
- pwt_clone_table_conds(), which cloned both halves and ANDed them, is gone;
  setup_worker_jointabs() clones the one condition with pwt_clone_rebind().
- setup_worker_jointabs() no longer clears cache, use_join_cache and
  jbuf_tracker on the worker's copy; pwt_assert_tab_inert() asserts that the
  manager's tab has no cache instead. The copy's cache_select is still
  cleared, as it can be set on a tab without a buffer.

parallel_query_join: the BNL case now expects the query to run serially,
with the same rows. The full-scan inner table case (d3) was getting a BNL
buffer under the default join_cache_level, so it runs with
join_cache_level=0 to keep covering a worker-side full scan of an inner
table. parallel_query_why pins the new refusal reason.

This commit was prepared with Claude Code (Opus 5.5), which wrote the gate
check, removed the worker-side join buffer handling it made unreachable,
updated the tests, reconfigured and rebuilt the worktree, and ran the
parallel_query tests in normal and --ps-protocol modes.
Sergei Golubchik
MDEV-41432 CONVERT TABLE ... TO PARTITION does not check privileges on the table it moves in

The table being moved in got grant.privilege copied from the
partitioned table, so check_grant() verified ALTER, DROP on it against
the wrong database. Run check_access() on its own database instead.

Assisted-by: Claude:claude-opus-5-5
Yuchen Pei
MDEV-25848 one range slot per ARRAY index

Before, every MEMBER OF / JSON_OVERLAPS / JSON_CONTAINS point got its
own cloned KEY_PART and key slot, and points were combined only through
index_merge (OR) or by picking one slot (AND).

Now all points on an ARRAY key part share the original slot:

* SEL_ARG_ARRAY holds a list of make_key() points ("the array contains
  any of them") and the summed records_in_range() estimate and cost,
  taken once when the point is built.
* key_or() of two ARRAY ranges takes the union of the points;
  key_and() keeps the operand with the lower estimate, the WHERE
  condition checks the rest.
* KEY_PART cloning (get_claimed_key_part()) is now RTREE-only, so
  ARRAY-only queries size SEL_TREE::keys by param->keys again.
* QUICK_RANGE_SELECT_ARRAY gets one QUICK_RANGE per point and passes
  all points to hlindex_read_first(); json_index reads them in turn
  and skips trefs it has already returned.
* check_quick_select_array() uses the stored estimate, and rejects
  non-ARRAY SEL_ARGs (e.g. IS NULL) on the ARRAY key part.

ORed MEMBER OF and JSON_OVERLAPS now give a single range scan instead
of index_merge sort_union, with no MAX_KEY limit on the number of
points.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Sergei Golubchik
MDEV-40826 Server Crash in JSON_SCHEMA_VALID on a Deeply Nested Schema

check stack overrun in Json_schema_keyword::validate_schema_items(),
nested "items" and other subschema keywords recurse through it.

Assisted-by: Claude:claude-opus-5-5
Oleksandr Byelkin
Merge branch 'bb-11.4-release' into bb-11.8-release
Rex Johnston
MDEV-39492 PQ: run a FirstMatch semijoin in the workers

The gate refused every semijoin duplicate-elimination strategy, on the
grounds that a worker's nested loop implements none of them. For
FirstMatch that was not true. FirstMatch is the nested loop backing out
early: when the last inner table of the semijoin nest matches, the
executor sets join->return_tab to the outer table the nest follows
(JOIN_TAB::do_firstmatch) and sub_select() unwinds to it rather than
looking for further matches that would only duplicate the row. A worker
runs sub_select() over its own JOIN and its own JOIN_TABs, so it does
the same -- provided its copy of do_firstmatch names a tab of its own
array, since return_tab is only ever compared with the tabs of the
array being walked. setup_worker_jointabs() now remaps do_firstmatch,
first_sj_inner_tab and last_sj_inner_tab from the manager's array onto
the worker's, and the gate admits SJ_OPT_FIRST_MATCH, refusing a nest
whose return tab is a const table, which no worker holds. LooseScan and
DuplicateWeedout keep state that no copy carries -- a match flag, a
weed-out table -- and stay refused, as does materialization.

This is the second half of what TPC-H Q21 needed: its EXISTS over
LINEITEM is flattened to a FirstMatch nest after NATION, and with its
NOT EXISTS left to the manager by the previous commit, the plan the
optimizer had costed as a parallel scan of ORDERS now runs in the
workers.

main.parallel_query_firstmatch runs an EXISTS flattened to FirstMatch
under whole-table aggregation, GROUP BY and a manager-side sort, with
two matching inner rows per outer row so that a nested loop without the
early return would double every count, and shows DuplicateWeedout still
refused.

This commit was prepared with Claude Code (Fable 5.1), which read what
sub_select() and evaluate_join_record() consult for FirstMatch, wrote
the remap and the gate change, and wrote the test.
Sergei Golubchik
MDEV-42048 stack overrun on normalizing deeply nested json

use my_string_stack_guard() in json_norm_value_comp() when recursing.
Thirunarayanan Balathandayuthapani
MDEV-42037 Assertion failure bpage->oldest_modification() when ALTER TABLE … DISCARD TABLESPACE races with the page cleaner

Problem:
=======
The page cleaner holds the latch of a dirty page while
buf_flush_space() has released buf_pool.mutex. DISCARD TABLESPACE
meanwhile runs buf_flush_remove_pages(), which removes the page from
buf_pool.flush_list without taking the page latch. When the cleaner
resumes, buf_flush_discard_page() asserts oldest_modification()

Solution:
========
buf_flush_discard_page(): remove the page from the flush list only if
oldest_modification() is nonzero. Always release the latch and free
the page, and return whether it was freed.
Daniel Black
MDEV-38913 Debian not installed file pam_mariadb_mtr.so creates test gap (postfix)

The architecture dependent pam_mariadb_mtr.so is mean to be in
the mariadb-test (which is per architecture), rather than
mariadb-test-data, which is architecture independent.

Thanks Elena for noticing.
Rex Johnston
MDEV-40012 PQ: end a worker's scan before close(); refuse DEFAULT() in workers

Two defects found by running the main suite under ASAN with
--parallel-worker-threads=4.

A worker's handler was destroyed with its parallel scan still open.
exec() and scan_only() jump to their exit labels when
parallel_init_worker() fails, and the commonest failure is
HA_ERR_END_OF_FILE: no chunk was left for this worker, which happens all
the time on small tables. InnoDB has allocated m_pscan_worker by then, so
the scan was left for ~ha_innobase() -> parallel_scan_free(), which runs
after close() has freed m_prebuilt. parallel_scan_free() says it drops the
worker without end() for exactly that reason, but ~Parallel_scan_worker()
called end() anyway, and end() writes m_prebuilt->pscan_chunk_clamp: a
heap-use-after-free that ASAN reports on every such worker. In a build
without ASAN the write lands in freed memory, and it is the likely cause of
the intermittent SIGSEGV in free() inside pthread_create() when a later
worker reused a cached thread stack whose DTV had been overwritten. Both
exit labels now call parallel_end_worker() while the handler is still
open, which is harmless when the scan was already ended or never begun,
and ~Parallel_scan_worker() no longer calls end().

DEFAULT(col) was evaluated against the worker's row. Item_default_value is
an Item_field whose field is a private copy made by make_default_field(),
reading the share's default_values but carrying the column's own table.
Its deep_copy() shares that field, and Pwt_field_rebinder, seeing the
manager's table, repointed it at the worker's real column. DEFAULT(col)
then read the current row's value, and for an expression default
calculate() called set_default() and wrote the default into the row --
wrong results in a release build, a marked_for_write assertion in a debug
one. It shows only when the expression also names the column some other
way; alone, DEFAULT(col) is table-independent and evaluated at optimize
time. The gate now refuses any expression holding a DEFAULT(), found with
check_func_default_processor, which only Item_default_value answers.
parallel_query_clone covers a lost row, a gained row and the expression
default that crashed, and checks that none of them ran in the workers.

This commit was prepared with Claude Code (Opus 5.5), which reproduced the
pthread_create() crash under ASAN, traced it and the DEFAULT() wrong result
from a main-suite sweep with workers enabled, wrote both fixes and the
test, and ran the parallel_query tests in normal and --ps-protocol modes.
Oleksandr Byelkin
new CC 3.3