Console View
|
Categories: connectors experimental galera main |
|
| connectors | experimental | galera | main | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Oleksandr Byelkin
sanja@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| new columnstore | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Yuchen Pei
ycp@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-40805 Do not call lock_rec_convert_impl_to_expl if a table S-lock is held lock_clust_rec_read_check_and_lock() skipped the implicit-to-explicit conversion only under a table LOCK_X. When a table LOCK_S is held the conversion is equally pointless: no other transaction can hold an implicit X-lock on the record, because modifying a row requires a table LOCK_IX and LOCK_IX is incompatible with our LOCK_S. lock_table_has() matches stronger modes, so testing LOCK_S subsumes the old LOCK_X test. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Oleksandr Byelkin
sanja@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Merge branch '10.6' into 10.11 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Rex Johnston
rex.johnston@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-40012 Parallel Query: execute the join in the worker threads Each parallel worker now runs the join and the WHERE over its own chunk of the driving table and ships the base-table columns of every row that qualified. The manager copies those columns back into the fields they came from in its own table instances, so that after a row is drained its records hold what a serial scan would have left there, and then evaluates the select list against them and sends the row. This replaces the model where the workers shipped raw source records and the manager ran the join. The transport carries columns rather than projected values because anything the manager does with a row beyond sending it reads a record, and not all of those reads go through Items that could be re-pointed: create_tmp_table() builds Copy_field pairs holding raw Field pointers into the base tables. make_join_readinfo()'s gate, can_run_query_in_workers(), chooses the worker-side path for an inner select-project[-join] over a parallel-scannable driving table: no tmp table, no LIMIT/SQL_CALC_FOUND_ROWS/procedure/aggregate, no outer join, no semijoin strategy the worker's plain nested loop cannot honour, and every non-driving table reached by eq_ref, ref or full scan. Every expression it hands a worker has to deep-copy into something that shares no node with the original and reads no table outside the join, or the copy would carry the manager's own items onto a worker's tables. do_select() then runs run_worker_side_join(); anything ineligible runs serially. Each worker opens a private copy of every non-const table, deep-clones and field-rebinds the conditions and the shipped column list, rebuilds each ref, scans its chunk, runs its own inner nested loop and ships the columns it read for each full match. It runs under the session's query id, so an item holding a value for the statement recomputes it rather than handing out the one it was cloned with. sql_parallel_execution.cc holds all of the above; sql_parallel_workers.cc keeps the worker threads, the batch channel and their lifetime. Tests: parallel_query_worker_side, parallel_query_join and parallel_query_clone compare a parallel result set against a serial one; parallel_query and parallel_query_oom moved to a plain SELECT and were re-recorded. .claude/commits/MDEV-40012.md records what came from the 13.0 branch verbatim, what was adapted to this tree, and what is new here. This commit was prepared with Claude Code: it ported the work from the 13.0 branch onto this tree's refactored structures and renamed scan API, found and fixed the two holes this tree's deeper Item copying opens -- an expression reaching a table the worker does not have, and a statement-lifetime item cached against query id 0 -- split the file, and ran the suites. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Dmitry Shulga
dmitry.shulga@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-40091: ASAN: heap-use-after-free with concurrent create/drop system trigger In case there are 'on shutdown' triggers it could result in abnormal server termination if at the moment server shutdown is in progress the server received the DROP TRIGGER statement for one of 'ON SHUTDOWN' system triggers being already executed as part shutdown process. Another words, there is the race condition between running triggers on shutdown and execution of DROP TRIGGER for system triggers ON SHUTDOWN event. To fix the issue protect running on shutdown triggers and drop/create of system triggers under the lock to avoid race condition. Check under the new lock for the flag that shutdown is in progress and don't add/remove a trigger instance into/from internal array as part of handling CREATE/DROP TRIGGER for ON SHUTDOWN event. That is, add/drop metadata about the trigger but don't modify the internal runtime data structures. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Sergei Golubchik
serg@mariadb.org |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fix debian versioning | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Marko Mäkelä
marko.makela@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fixup! 53ab6144004ffbd12e01a36820fececcdfdb49f7 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Alexander Barkov
bar@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-39563 Implement UPDATE ... RETURNING ... INTO Adding support for UPDATE .. RETURNING .. INTO queries. For example: UPDATE t1 SET a=10,b=20 RETURNING a,b INTO va,vb; UPDATE t1 SET a=10,b=20 RETURNING a,b INTO @a,@b; Note, ANALYZE UPDATE .. RETURNING .. INTO queries work, ignoring the INTO clause. ANALYZE UPDATE t1 SET a=10,b=20 RETURNING a,b INTO va,vb; These types of queries: - REPLACE .. RETURNING .. INTO - DELETE .. RETURNING .. INTO do not work - they return an error. They will be implemented separately, when needed. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Marko Mäkelä
marko.makela@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fixup! b5501deaccc06941352c9980361266e47c09c53f | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Oleksandr Byelkin
sanja@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Merge branch 'br-11.4-merge' into bb-11.8-release | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Daniel Black
daniel@mariadb.org |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-40801 ppc64le ro_after_init isn't pagesize aligned Align ro_after_init using MAXPAGESIZE instead of COMMONPAGESIZE. COMMONPAGESIZE may be smaller than the actual page size supported by the target ABI. This can leave ro_after_init sharing an OS page with adjacent sections, causing mprotect() to change permissions on data outside ro_after_init. Use MAXPAGESIZE so the section boundaries are aligned to the maximum page size required by the target linker/ABI. This is particularly important on architectures such as ppc64le and aarch64, where the runtime page size can differ from COMMONPAGESIZE. Before: .data 0x...1b80000 ro_after_init 0x...1c70000 .bss 0x...1c72000 After: ro_after_init starts and ends on MAXPAGESIZE boundaries, ensuring mprotect() only affects pages belonging to ro_after_init. Co-authored-by: ChatGPT GPT-5.6 Luna <[email protected]> |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Kristian Nielsen
knielsen@knielsen-hq.org |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-40729: Re-use the existing Xid_log_event and my_xid Avoid introducing yet another transaction identifier, instead re-use the internal XID we already use in Xid_log_event and for two-phase commit between binlog and engines. Extend the Xid_log_event so it contains both the connection_id and the commit_id part of my_xid. Use the Xid_log_event to implement client trx_status() searching for a transaction in the binlog. A ToDo for this patch is to put in the new-style transaction ID into thd->transaction->implicit_xid in trans_register_ha(). In this proof-of-concept patch, the transaction id is still supplied by the client and the code falls back to old (query_id, server_id) when not supplied; this should be changed. Note that this change to Xid_log_event will break downgrades if they happen on a crashed server. The new version will write the connection_id into the first part of the Xid_log_event, which is no longer unique amongst all transactions. If the server is restarted on old version after a crash, the old version will only read the first part of the transaction id into old-style my_xid, and it may identify the wrong transaction as committed. Signed-off-by: Kristian Nielsen <[email protected]> |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Daniel Black
daniel@mariadb.org |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-40801 ppc64le ro_after_init isn't pagesize aligned Align ro_after_init using MAXPAGESIZE instead of COMMONPAGESIZE. COMMONPAGESIZE may be smaller than the actual page size supported by the target ABI. This can leave ro_after_init sharing an OS page with adjacent sections, causing mprotect() to change permissions on data outside ro_after_init. Use MAXPAGESIZE so the section boundaries are aligned to the maximum page size required by the target linker/ABI. This is particularly important on architectures such as ppc64le and aarch64, where the runtime page size can differ from COMMONPAGESIZE. Before: .data 0x...1b80000 ro_after_init 0x...1c70000 .bss 0x...1c72000 After: ro_after_init starts and ends on MAXPAGESIZE boundaries, ensuring mprotect() only affects pages belonging to ro_after_init. Co-authored-by: ChatGPT GPT-5.6 Luna <[email protected]> |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Rex Johnston
rex.johnston@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-40012 Parallel Query: execute the join in the worker threads Each parallel worker now runs the join and the WHERE over its own chunk of the driving table and ships the base-table columns of every row that qualified. The manager copies those columns back into the fields they came from in its own table instances, so that after a row is drained its records hold what a serial scan would have left there, and then evaluates the select list against them and sends the row. This replaces the model where the workers shipped raw source records and the manager ran the join. The transport carries columns rather than projected values because anything the manager does with a row beyond sending it reads a record, and not all of those reads go through Items that could be re-pointed: create_tmp_table() builds Copy_field pairs holding raw Field pointers into the base tables. make_join_readinfo()'s gate, can_run_query_in_workers(), chooses the worker-side path for an inner select-project[-join] over a parallel-scannable driving table: no tmp table, no LIMIT/SQL_CALC_FOUND_ROWS/procedure/aggregate, no outer join, no semijoin strategy the worker's plain nested loop cannot honour, and every non-driving table reached by eq_ref, ref or full scan. Every expression it hands a worker has to deep-copy into something that shares no node with the original and reads no table outside the join, or the copy would carry the manager's own items onto a worker's tables. do_select() then runs run_worker_side_join(); anything ineligible runs serially. Each worker opens a private copy of every non-const table, deep-clones and field-rebinds the conditions and the shipped column list, rebuilds each ref, scans its chunk, runs its own inner nested loop and ships the columns it read for each full match. It runs under the session's query id, so an item holding a value for the statement recomputes it rather than handing out the one it was cloned with. sql_parallel_execution.cc holds all of the above; sql_parallel_workers.cc keeps the worker threads, the batch channel and their lifetime. Tests: parallel_query_worker_side, parallel_query_join and parallel_query_clone compare a parallel result set against a serial one; parallel_query and parallel_query_oom moved to a plain SELECT and were re-recorded. .claude/commits/MDEV-40012.md records what came from the 13.0 branch verbatim, what was adapted to this tree, and what is new here. This commit was prepared with Claude Code: it ported the work from the 13.0 branch onto this tree's refactored structures and renamed scan API, found and fixed the two holes this tree's deeper Item copying opens -- an expression reaching a table the worker does not have, and a statement-lifetime item cached against query id 0 -- split the file, and ran the suites. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Daniel Black
daniel@mariadb.org |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-40750 gcc-16.1.0 on ppc64 causes innodb to fail to compile Assembler comes up with the error: unrecognized opcode: `dcbstps' dcbstps is a Power 10 instruction. The default target arch on most platforms is Power 8 or 9. Added the target power10 to the function pmem_phwsync. The execution of this function is gated on the ISA 3.1 in pmem_persist_init so there's no chance of a SIGILL. clang supports this target as arch=pwr10 and gcc as cpu=power10. Revert back to using opcodes for old versions. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Monty
monty@mariadb.org |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-40729 Add functionality to verify if a transaction is committed or not after failure In progress. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
bsrikanth-mariadb
srikanth.bondalapati@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-39226: Push whole multi-table update/delete down into engines Give storage engines a way to take over an entire multi-table UPDATE/DELETE, the way they can already take over a SELECT. Without it the join, the row matching and every modification run in the SQL layer even when an engine could do the whole statement itself in one step; a single-table UPDATE/DELETE already avoids this via direct_update_rows()/direct_delete_rows(), but a multi-table statement has no primary handler object to drive that path. This adds a generic, engine-agnostic pushdown interface: the SQL layer offers the statement to the engine, and if the engine accepts it, it performs the whole thing and reports only the row counts. - Split select_handler into a pushdown_handler base with select_handler (result set) and a new multi_upddel_handler (runs a whole UPDATE/DELETE, reports row counts, reported as PUSHED UPDATE/PUSHED DELETE); add handlerton::create_multi_upddel, looked up in Sql_cmd_dml::execute_inner(). - multi_update/multi_delete gain direct_update_delete_done(), which records the engine's counts so send_eof() binlogs and replies without the SQL-layer loop; it forces statement-format binlogging so the change still replicates under binlog_format=ROW, and errors out instead of silently dropping counts for an unsupported result object. - FederatedX implements the interface as the reference engine used to test correctness: it prints the statement back and runs it remotely, passes the engine's error code/SQLSTATE through, reads the matched count from the remote info string, executes IGNORE locally, and only pushes down when all tables share one remote server (same as SELECT/derived/unit pushdown). Test: federated.federatedx_pushdown_upd_del. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Marko Mäkelä
marko.makela@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-40728 Recovery wrongly fails if FILE_CREATE is followed by FILE_RENAME fil_name_process(): Simplify the logic. If no matching tablespace is found but file_name_t::create_lsn had been set in response to parsing a FILE_CREATE record, try to apply FILE_RENAME to deferred_spaces. deferred_spaces.deferred_dblwr(): Skip newly created tablespaces to avoid a bogus invocation of fil_space_free(). fil_delete_apply(): Wrappers for fil_space_free(). When recovering a log in innodb_log_archive=ON format, we must apply FILE_DELETE records in order to avoid a future clash with FILE_CREATE or FILE_RENAME. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Rex Johnston
rex.johnston@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-40012 PQ: divide the whole join's cost, not the split table's scale_cost_for_parallel_scan() discounted the driving table's scan and nothing else, so every table joined after it was costed at its ull serial price. But a worker does not only scan its chunk: it runs the whole join over that chunk, so the work of each later table is divided between the workers exactly as the scan is. POSITION gains parallel_workers, set on the driving table when the access finally chosen for it was the scan that was costed as parallel, and left at 0 otherwise, including on a driving table whose scan lost to an index, where nothing is parallel. Each table joined after it divides its cost by that number. This commit was prepared with Claude Code |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Kristian Nielsen
knielsen@knielsen-hq.org |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-40729: Add functionality to verify if a transaction is committed or not after failure Basic proof-of-concept patch, only implements the basics to put trx_id into the binlog file and search for it with trx_status(). A test case rpl.rpl_client_trx_id demonstrates the functionality. Some limitations/considerations from this patch: There is no support for MARIADB_TRX_IN_PROGRESS (do we want/need such functionality?). Based on 10.11, however pushing to stable 10.11 will be controversial as it changes GTID event format. Since 10.11 has no GTID indexes, linear scan of at least one entire binlog file will be required. An in-memory cache may be needed to handle client reconnect-storm after a crash or network outage that caused many ongoing commits to fail. When starting gtid is not specified for trx_status(), it is not possible to distinguish between MARIADB_TRX_ABORTED or MARIADB_TRX_UNKNOWN. In this case, we return MARIADB_TRX_ABORTED. Knowing where to start scanning binlogs is important, for performance (to avoid scanning _entire_ binlog history), and to distinguish MARIADB_TRX_ABORTED from MARIADB_TRX_UNKNOWN. It is somewhat tricky though: - A GTID position is multi-dimensional. The starting GTID _must_ be with the same domain_id as the transaction being searched for, otherwise searching on a slave may start too late in the slave's binlog and wrongly return MARIADB_TRX_ABORTED for a committed transaction. - The client will need to obtain a starting GTID for the very first transaction done on the connection. One possible way could be to SELECT @@GLOBAL.gtid_binlog_pos and pick out the one with the domain_id which will be used for subsequent transactions. Signed-off-by: Kristian Nielsen <[email protected]> |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Alexander Barkov
bar@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-39563 Implement UPDATE ... RETURNING ... INTO Adding support for UPDATE .. RETURNING .. INTO queries. For example: UPDATE t1 SET a=10,b=20 RETURNING a,b INTO va,vb; UPDATE t1 SET a=10,b=20 RETURNING a,b INTO @a,@b; Note, ANALYZE UPDATE .. RETURNING .. INTO queries work, ignoring the INTO clause. ANALYZE UPDATE t1 SET a=10,b=20 RETURNING a,b INTO va,vb; These types of queries: - REPLACE .. RETURNING .. INTO - DELETE .. RETURNING .. INTO do not work - they return an error. They will be implemented separately, when needed. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Oleksandr Byelkin
sanja@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Merge branch 'bb-11.8-release' into bb-12.3-release | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Arcadiy Ivanov
arcadiy@ivanov.biz |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-40802 COUNT(DISTINCT <blob>) fails when its tmp table converts `COUNT(DISTINCT)` collects the distinct values in a temporary table with a unique constraint over the aggregate's arguments, and treats a duplicate key error from the write as "value already seen": ```c if (!table->file->is_fatal_error(error, HA_CHECK_DUP)) return FALSE; // duplicate, not an error ``` For a blob argument the record holds only a pointer to the value, so `Aggregator_distinct::setup()` cannot use the `Unique` tree, which compares raw record bytes, and every value goes through that write instead. When such a write overflows the in-memory table, `create_internal_tmp_table_from_heap()` copies the stored rows to an on-disk table and then writes the row that overflowed, which until then was held in `record[0]` alone. Whether a duplicate key error on that last write is fatal is decided by the caller's `ignore_last_dupp_key_error` argument, and `Aggregator_distinct::add()` passed **0** three lines below the code that ignores the very same condition. The statement failed with ERROR 1169 (23000): Can't write, because of unique constraint, to table '(temporary)' Pass **1** instead, so that a duplicate arriving through the conversion is discarded exactly like one arriving through the ordinary write. The result is `table->file->stats.records` of that table, so not storing the duplicate is what makes the count right. The argument is the same upstream, where it is unreachable: a temporary table with a blob column was created on the on-disk engine to begin with, so the conversion was never entered for the only tables whose pending row can be a duplicate. Supporting blob columns in the in-memory engine made the table start in memory and convert. New tests `heap.count_distinct_blob_convert` and `heap.count_distinct_blob_convert_debug`. A write rejected as a duplicate returns its record to the free list and never reaches the allocation of the blob value, so only the first copy of a value makes the in-memory table grow, and the write that finds it full is the second copy of the value stored last. That holds only while a record slot is what the table runs out of first. Blob values come out of the same space, and only a write that is not a duplicate ever allocates one, so when a blob allocation is the one that hits the limit, the pending row is not a duplicate at all. Which of the two runs out first follows from how records and blob values pack together, not from any threshold on the value width. Of 24 measured combinations of width and `max_heap_table_size`, 20 convert but only 8 reach a duplicate pending row, so asserting that the table was converted does not establish that the ignored duplicate was reached. The first test uses widths measured to overflow on a record slot. The second removes the dependency on that measurement, injecting the duplicate through a new debug point in `Tmp_table_default_copier::copy_rows()`, beside the one the row copy loop already carries. Every value is present twice, so whichever copy the injected duplicate discards, the other one is still written and the count does not depend on which write overflowed. The status counter is read with the in-memory limit restored. The status table is materialized into a temporary table of its own, and its VARIABLE_VALUE column is wide enough to be stored as a blob, so under the shrunken limit that table can overflow and be converted as well, and would then report its own conversion. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Sergei Golubchik
serg@mariadb.org |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
disable DBUG in plugins, better deb version detection dbug can be enabled with -UDBUG_OFF, if *really* needed |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Marko Mäkelä
marko.makela@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Fix InnoDB_backup::context::de_hardlink() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Marko Mäkelä
marko.makela@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-40728 Recovery wrongly fails if FILE_CREATE is followed by FILE_RENAME fil_name_process(): Simplify the logic. If no matching tablespace is found but file_name_t::create_lsn had been set in response to parsing a FILE_CREATE record, try to apply FILE_RENAME to deferred_spaces. deferred_spaces.deferred_dblwr(): Skip newly created tablespaces to avoid a bogus invocation of fil_space_free(). fil_delete_apply(): Wrappers for fil_space_free(). When recovering a log in innodb_log_archive=ON format, we must apply FILE_DELETE records in order to avoid a future clash with FILE_CREATE or FILE_RENAME. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Georgi (Joro) Kodinov
joro@mariadb.org |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| day's work: the beginning of the top level structure | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Marko Mäkelä
marko.makela@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Explicit copy_file() shortcuts copy_file_range_try(): A wrapper for Linux copy_file_range(2), which may fail with EOPNOTSUPP or EXDEV and require a fallback. copy_mmap(): Copy from a memory-mapped buffer. copy_file(): The generic file-copying function. On FreeBSD and Microsoft Windows, no alternatives exist. InnoDB_backup::backup(): Implement all alternatives to copy_file(). |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Marko Mäkelä
marko.makela@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
fixup! 5f6f81c1ed080d3469c92da8e12d28cc3e8a10d9 Partially revert a non-working fix. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
KhaledR57
khaled57.dev@gmail.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-40494 KEY_OP_DEL_PREFIX subtracts unchecked length from page_length The KEY_OP_DEL_PREFIX branch of _ma_apply_redo_index() subtracted the logged length from page_length and used the difference as a bmove() size, guarded only by a DBUG_ASSERT, which is compiled out when DBUG_OFF is set. A length larger than the used page underflows that size, and a length larger than page_length wraps page_length itself. Turn the assert into a runtime check, written as an addition rather than the assert's subtraction, which underflows on a page shorter than its own header. A refused record takes the error path that was already there. The test forges the logged length with corrupt_del_prefix, then crashes the server so recovery has to replay the record. The workload splits and merges index pages: this record comes from the underflow path, so plain inserts never produce one. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Oleksandr Byelkin
sanja@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Merge branch '11.4' into 11.8 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Kristian Nielsen
knielsen@knielsen-hq.org |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-40729: Revert extension to GTID event with new transaction id. Since we switched to using the Xid_log_event to have the transaction ID, do not extend the GTID event with the id. Kept as a separate commit for now to better isolate the different changes for easier review and working. Signed-off-by: Kristian Nielsen <[email protected]> |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Arcadiy Ivanov
arcadiy@ivanov.biz |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-40781 Duplicate row despite DISTINCT when tmp table converts `create_internal_tmp_table_from_heap()` writes the pending `record[0]`, the row whose write filled the in-memory table, into the new table. Since **MDEV-40376** (`636f154bb49`) that write happens *before* `ha_end_bulk_insert()` rather than after it. `ha_maria::start_bulk_insert()` disables **all** indexes of an internal temporary table that is about to receive at least `MARIA_MIN_ROWS_TO_DISABLE_INDEXES` (100) rows: ```c if (file->open_flags & HA_OPEN_INTERNAL_TABLE) { /* Internal table; If we get a duplicate something is very wrong */ file->update|= HA_STATE_CHANGED; index_disabled= share->base.keys > 0; maria_clear_all_keys_active(file->s->state.key_map); } ``` `maria_write()` then skips `_ma_check_unique()` entirely, so the unique constraint that implements `DISTINCT` for a key too wide to be an index is not enforced. The rows copied out of the in-memory table are already distinct and need no checking against each other, but the pending row is exactly the row whose duplicate status is unknown, and it was written inside that window. A `SELECT DISTINCT` over wide columns could therefore return a duplicate row. Note that the justification given in `636f154bb49` is not the mechanism at work here. It refers to the bulk insert key *tree*, a different branch of `ha_maria::start_bulk_insert()`; setting `bulk_insert_buffer_size=0` does not avoid the problem. The fix splits the copy in two: 1. `Tmp_table_row_copier` gains a second virtual, `write_pending_row()`, defaulting to a no-op. 2. `copy_rows()` now only copies the rows the in-memory table holds. 3. `create_internal_tmp_table_from_heap()` calls `ha_end_bulk_insert()` and then `write_pending_row()`, so the pending row is written with the indexes of the new table back in place and a duplicate of an already copied row is detected. `Window_rowid_remapper` keeps writing its pending row within `copy_rows()` and inherits the no-op default. Its new position is only known once the rows before it have been written, and nothing is lost by writing it with the indexes still disabled: it replaces a row that is already in the table rather than adding one, and an update of a window function value cannot collide with another row, as a deduplicating key is not built on the columns it changes. The new test covers `SELECT DISTINCT`, `SELECT DISTINCT ... ORDER BY`, `UNION` and `INSERT ... SELECT DISTINCT`, and asserts that the conversion actually happened so that a future sizing change cannot silently void the coverage. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Oleksandr Byelkin
sanja@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Merge branch '11.4' into br-11.4-merge | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Rex Johnston
rex.johnston@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-40012 PQ: divide the whole join's cost, not the split table's scale_cost_for_parallel_scan() discounted the driving table's scan and nothing else, so every table joined after it was costed at its ull serial price. But a worker does not only scan its chunk: it runs the whole join over that chunk, so the work of each later table is divided between the workers exactly as the scan is. POSITION gains parallel_workers, set on the driving table when the access finally chosen for it was the scan that was costed as parallel, and left at 0 otherwise, including on a driving table whose scan lost to an index, where nothing is parallel. Each table joined after it divides its cost by that number. This commit was prepared with Claude Code |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Oleksandr Byelkin
sanja@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Merge branch '10.11' into 11.4 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
bsrikanth-mariadb
srikanth.bondalapati@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-39226: Push whole multi-table update/delete down into engines Give storage engines a way to take over an entire multi-table UPDATE/DELETE, the way they can already take over a SELECT. Without it the join, the row matching and every modification run in the SQL layer even when an engine could do the whole statement itself in one step; a single-table UPDATE/DELETE already avoids this via direct_update_rows()/direct_delete_rows(), but a multi-table statement has no primary handler object to drive that path. This adds a generic, engine-agnostic pushdown interface: the SQL layer offers the statement to the engine, and if the engine accepts it, it performs the whole thing and reports only the row counts. - Split select_handler into a pushdown_handler base with select_handler (result set) and a new multi_upddel_handler (runs a whole UPDATE/DELETE, reports row counts, reported as PUSHED UPDATE/PUSHED DELETE); add handlerton::create_multi_upddel, looked up in Sql_cmd_dml::execute_inner(). - multi_update/multi_delete gain direct_update_delete_done(), which records the engine's counts so send_eof() binlogs and replies without the SQL-layer loop; it forces statement-format binlogging so the change still replicates under binlog_format=ROW, and errors out instead of silently dropping counts for an unsupported result object. - FederatedX implements the interface as the reference engine used to test correctness: it prints the statement back and runs it remotely, passes the engine's error code/SQLSTATE through, reads the matched count from the remote info string, executes IGNORE locally, and only pushes down when all tables share one remote server (same as SELECT/derived/unit pushdown). Test: federated.federatedx_pushdown_upd_del. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Oleksandr Byelkin
sanja@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Merge branch 'br-10.11-merge' into bb-11.4-release | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||