Console View
|
Categories: connectors experimental galera main |
|
| connectors | experimental | galera | main | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Rex Johnston
rex.johnston@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
PQ: a pre-aggregating worker hands over its grouping table A worker that pre-aggregates kept two temporary tables of the same shape: the grouping table its aggregates accumulated into, and the shipping container the manager reads. At end of records flush_groups() walked the first and wrote every row into the second -- a memcpy and a keyed insert per group -- so that the manager could read rows it already had, in a table it could already have been given. The tables hold the same rows because a worker produces one row per group and ships one row per group; there was never anything for the second table to do but hold a copy. So there is one table now. setup_worker_preagg() builds the shipping container itself, from the worker's own item list, and the aggregates accumulate straight into it; flush_groups() is gone, and so is the per-group copy and the second table's memory. What the manager reads is the table end_update() wrote. The batch transport is disabled, which is what makes that possible to say plainly. It carries record images through a buffer rather than handing a table over, so everything that goes through it is copied twice, and a worker with a finished table still has to stream it. pwt_create_transport() now builds the temporary-table transport unconditionally and the debug flag that selected the other one is gone. The classes are kept, compiled out, in case the streaming shape is wanted again. Two things the copy had been hiding had to be fixed before the table could be handed over. A rebuild on disk has to be the cross-thread kind. A container is instantiated cross-thread, because the manager reads and frees what the worker wrote, and the transport's own spill path passes that through. But a pre-aggregating worker's table fills while end_update() is writing it, and end_update() rebuilt it with cross_thread=false: Aria then ties the new handle's allocations to the worker's thread, and the manager frees them after that thread is gone. The decision now travels on TMP_TABLE_PARAM, set where the container is created and read where the rebuild happens. Without it the new test fails with the allocation crossing threads, named: 16416 bytes freed by T@3, allocated by T@71 at maria/ma_bitmap.c:242, ... sql/sql_select.cc:23926, sql/sql_select.cc:26598 And the memory that rebuild allocates has to change hands. The transport already moves the charge from the worker's THD to the manager's for a spill it performs itself, but a spill inside end_update() never passes through the transport. pwt_end_send() now brackets put_record() and hands anything the call left outstanding to the sink: working memory a call allocates and frees nets to nothing there, and the rebuild is what does not. main.parallel_query_spill covers the new path: twenty thousand groups against a 64K heap, asserting the query ran in the workers, that a row per group arrived, that the container really was rebuilt on disk, and that the answer matches the serial one group for group. main.parallel_query_transport loses the halves that exercised the batch transport, and with them its dependency on a debug build. Measured against this tree with the same forced-worker sweep of the main suite (--parallel-worker-threads=4): the same fifty tests fail before and after, the same fifty by name. This commit was prepared with Claude Code (Opus 5), which found that the two tables held the same rows, and identified both the non-cross-thread rebuild and the unaccounted memory before either could reach a test. The we found a bug, we need to close the container's index before handing it to the manager A pre-aggregating worker leaves its container's index open: AGGR_OP::put_record() opens it on its first call and nothing since has closed it. When the copy into a separate shipping container went away, closing it moved to the worker's tidy-up at the end of execute_and_handoff() -- which is after sink->flush(), and flush() is what tells the transport this producer is finished. The manager may claim the container the moment it is marked done. So a manager that got there before the worker reached its tidy-up called ha_rnd_init() on a table whose index was still open, and that asserts: mariadbd: sql/handler.h:3770: int handler::ha_rnd_init(bool): Assertion `inited==NONE || (inited==RND && scan)' failed. handler::ha_rnd_init pwt_tmp_table_source::next_row pwt_manager::drain_and_send Query: SELECT col1, COUNT(col2) FROM t1 GROUP BY col1 ORDER BY NULL Which thread wins is scheduling, so this showed up as main.parallel_query_aggregate failing about one run in eight with the whole parallel set running at --parallel=18, and passing every time on its own. Closing the index is moved to before the flush, where the hand-off is. The tidy-up still closes it, for the paths that reach the end without handing anything over; ha_index_or_rnd_end() on a handler that is already closed does nothing. pwt_tmp_table_sink::flush() now asserts what the ordering is for: that nothing this producer had open on the table is still open when the container becomes the consumer's to read. That turns a race the manager notices only when it wins into a condition the producer checks every time -- with the close put back after the flush, main.parallel_query_aggregate fails on the assertion on every run rather than on one in eight. This commit was prepared with Claude Code (Opus 5). The crash was found by running the parallel test set repeatedly under load rather than once; the producer-side assertion was added so the next mistake of this shape does not need luck to be seen. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Khaled Riyad
khaled57.dev@gmail.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-40377 Change Server source code to point to new docs (12.3 part) Replace the remaining Knowledge Base links with their MariaDB Documentation equivalents, including the 838 URLs in the help tables. Only URLs change in fill_help_tables.sql. fill_help_tables.sql conflicts on merge upward; keep the target branch's version. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Oleg Smirnov
olernov@gmail.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| InnoDB: fix unlatched right-move in the parallel scan partitioner | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Yuchen Pei
ycp@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| MDEV-40168 Add a testcase where the first argument of the MVI cast is an more complex expression not just a column->path | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
drrtuy
drrtuy@gmail.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| feat: MDEV-40672 implement basic support for the pluggable aggregate functions | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Oleg Smirnov
olernov@gmail.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Extract parallel logic from ha_innobase to separate files | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Kristian Nielsen
knielsen@knielsen-hq.org |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Semi-sync: Implement support for using GTID in semi-sync ACKs Implement the necessary logic in class Repl_semi_sync_master_gtid and related code, so that the semi-sync master can request the slave to put the GTID in the reply ACK packet, instead of the filename/offset. In GTID mode, when a slave connects (which it should do using a GTID start position), the latest GTID in the starting position (if any), as determined by the list of transactions pending acks, is used as the point at which to implicit ACK anything pending. The semi-sync logic is otherwise unchanged, in GTID mode it just uses the GTID as the transaction identifier instead of the file/pos of the end of the event group. This patch only enables the GTID-based semisync for binlog-in-engine, but the mode works with old binlog implementation as well, and passes all tests (if enabled by code change). Signed-off-by: Kristian Nielsen <[email protected]> |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Sergei Golubchik
serg@mariadb.org |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| debian, again | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Khaled Riyad
khaled57.dev@gmail.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-40377 Change Server source code to point to new docs (10.11 part) Replace the remaining Knowledge Base links with their MariaDB Documentation equivalents, and fix the 14 help table URLs pointing at /README pages that do not exist. Only URLs change in fill_help_tables.sql. fill_help_tables.sql conflicts on merge upward; keep the target branch's version. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Hemant Dangi
hemant.dangi@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-40501: Assertion `info->type == READ_CACHE || info->type == WRITE_CACHE' failed in reinit_io_cache upon CHANGE MASTER Issue: CHANGE MASTER ... FOR CHANNEL with a channel name within MAX_CONNECTION_NAME can still overflow the OS file name limit once escaped into the relay log file name. Relay_log_info::init() then fails to open the relay log, leaving its index file unopened, but Master_info_index::remove_master_info() unconditionally calls reset_logs() on it during CHANGE MASTER's error cleanup, which hits the assertion in reinit_io_cache(). Solution: Guard the reset_logs() call in remove_master_info() with is_open(), so a relay log that was never opened is never passed to it. Also use MY_SAFE_PATH in open_index_file() so an over-length name fails deterministically instead of silently falling back to a mangled one. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Dave Gosselin
dave.gosselin@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-15066: Filter geometry parts by bounding box before the scan Implements a pre-filtering step to limit the polygons considered by ST_Intersects and ST_Disjoint to those whose bounding box overlaps the other operand. The probe polygon overlaps the bounding box of seven rows in a table of 239 country outlines. Four of those rows are multipolygons of 346, 213, 120 and 21 polygons but not one of those 700 polygons overlaps with the probe. Yet, ST_Intersects stored all 700 into the scan. A polygon whose bounding box does not overlap the other operand cannot intersect it, yet the cost of the scan grows with the number of polygons considered. ST_Intersects and ST_Disjoint now leave such polygons out. Multipoint, multilinestring, multipolygon and geometry collection each count the parts that pass the filter and store only those. A geometry of one part is unchanged. Co-Authored-By: Claude Opus 5 <[email protected]> |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Oleg Smirnov
olernov@gmail.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Incorporate a pointer to the coordinator into worker context | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Khaled Riyad
khaled57.dev@gmail.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-40377 Change Server source code to point to new docs (11.4 part) Replace the remaining Knowledge Base links with their MariaDB Documentation equivalents, including the 838 URLs in the help tables. Only URLs change in fill_help_tables.sql. fill_help_tables.sql conflicts on merge upward; keep the target branch's version. .github/pull_request_template.md is deleted in 12.3; keep the deletion there. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Yuchen Pei
ycp@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-40168 Name the MVI internal column in the table, not in the ALTER add_mvi_key_part() runs in the parser, where make_internal_field_name() can only look for a free name among the columns the statement itself defines. For CREATE TABLE that is every column of the new table, but for ALTER TABLE it is just the columns being added, so ALTER TABLE t ADD KEY ((CAST(j->'$.a' AS CHAR(6) ARRAY))) asks for DB_MVI_1 on a table that already has a DB_MVI_1, and the two collide once mysql_prepare_alter_table() merges the old columns in. Rename in mysql_prepare_alter_table() instead, before the merge, where the table is known: mvi_name_new_vcols() iterates the columns the ALTER adds, and for each internal MVI column whose name is taken -- by a column of the table or by another column of the statement -- picks the first free DB_MVI_<n> and fixes up the key part that names it. Only a multi-valued index has an invisible key, so the key part is found for certain. This runs on the Alter_info copy that ALTER TABLE works on, not on the parser's, so re-executing a prepared statement names the column afresh. multi_valued_index_token_size.test no longer has to drop the index and add it back to make room for the name; what it does instead is rebuild a table that still has a multi-valued index over it. Co-Authored-By: Claude Opus 5 <[email protected]> |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Hemant Dangi
hemant.dangi@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-40501: Assertion `info->type == READ_CACHE || info->type == WRITE_CACHE' failed in reinit_io_cache upon CHANGE MASTER Issue: CHANGE MASTER ... FOR CHANNEL with a channel name within MAX_CONNECTION_NAME can still overflow the OS file name limit once escaped into the relay log file name. Relay_log_info::init() then fails to open the relay log, leaving its index file unopened, but Master_info_index::remove_master_info() unconditionally calls reset_logs() on it during CHANGE MASTER's error cleanup, which hits the assertion in reinit_io_cache(). Solution: Guard the reset_logs() call in remove_master_info() with is_open(), so a relay log that was never opened is never passed to it. Also use MY_SAFE_PATH in open_index_file() so an over-length name fails deterministically instead of silently falling back to a mangled one. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Oleg Smirnov
olernov@gmail.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Refactor for better object names and more accurate comments | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Monty
monty@mariadb.org |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
More query cache optimizations - Added query_cache_type == ALWAYS_OFF to turn of query cache permanently for new open tables. Without this option storage engines has to call query cache for all update querys and invalidate used tables that has a small overhead. When running benchmarks without query cache, this is the option to use! - Updated MyISAM, Aria, MYISAM_MRG and InnoDB to support ALWAYS_OFF. - Setting query_cache_size in a config file will not automatically enable the query cache. - Added query_cache_available() that functions can check if query cache can be used or if it is permanently disabled. - Moved things around in Query_cache::store_query() to get more work done outside of query cache mutex. - Same for Query_cache::send_result_to_client() Co-author: Thirunarayanan Balathandayuthapani <[email protected]> - ÃŒnnoDB changes reviewed and improved |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Yuchen Pei
ycp@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| MDEV-40168 fix embedded build | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Oleg Smirnov
olernov@gmail.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Rename Parallel_coordinator, some other refactorings and clean-up | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Kristian Nielsen
knielsen@knielsen-hq.org |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Implement support for semi-sync with --binlog-storage-engine Call report_binlog_update() when semi-synchronous replication is enabled and using --binlog-storage-engine. Only AFTER_COMMIT is available. The AFTER_SYNC in legacy binlog has the property that changes in a committing transaction does not get visible to other transactions until the slave has acknowledged, avoiding phantom reads if the master fails permanently just after. This requires the two-phase commit between binlog and storage engine so that the binlog is written before the transaction is engine-committed. However, the whole point of --binlog-storage-engine is to avoid the expensive two-phase commit. (The ability to avoid phantom reads could be later implemented as an AFTER_PREPARE option, which would send binlog to slave and await ack before it is written/committed into the engine). Some existing semi-synchronous replication tests are adapted to also run in the binlog_in_engine suite. Signed-off-by: Kristian Nielsen <[email protected]> |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
drrtuy
drrtuy@gmail.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| MDEV-41001: cpack now skips data path that brings symbolic links to fix Windows build. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Monty
monty@mariadb.org |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Added query_cache_use_rw_lock to allow concurrent query cache lookups The query cache protected all operations with one exclusive lock (m_cache_lock_status, guarded by structure_guard_mutex). This serialized every lookup, even though a lookup mainly reads the query cache structures. Added a new global variable, query_cache_use_rw_lock (default OFF). When set, send_result_to_client() takes a shared (read) lock instead of an exclusive one, which allows lookups to run concurrently. Having it as an option makes it possible to benchmark both alternatives with the same binary and then decide which one to keep. Implementation: - try_lock() has a new 'read_lock' argument. The new inline function try_read_lock() sets it from query_cache_use_rw_lock. - Readers are counted in m_readers and leave m_cache_lock_status as UNLOCKED. Writers wait until m_readers is 0 and are counted in m_waiting_writers. Waiting writers have priority over new readers, which ensures that invalidations are not starved by cache hits. - Readers wait on the new COND_cache_read_lock. wake_up_waiters() wakes one waiting writer, or all waiting readers if there is none. - unlock() is split into unlock() and unlock_internal(). The kind of lock to release is deduced from m_cache_lock_status, so none of the unlock() callers had to be changed. - send_result_to_client() updates the query list and the statistics under structure_guard_mutex when it only holds a read lock. With a write lock this is done as before, without taking the mutex. - If an engine requests invalidation during a lookup done with a read lock, the table key is copied and the invalidation is done after the lock is released, as invalidation requires a write lock. - Added the DEBUG_SYNC point "in_query_cache_hit" used by the new test. With query_cache_use_rw_lock=0 the code works as before. Did a simple sysbench run with 64 threads and 200000 simple select queries, all served from query cache. query_cache_use_rw_lock=1 gave a 2.25x speedup. The difference to an unmodied MariaDB version for the same test is 2.3 x faster. Co-Authored-By: Claude Opus 5 <[email protected]> |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
sjaakola
seppo.jaakola@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-41012 Galera appliers hang with foreign key of types UUID, INET4, INET6 For direct row writes, the certification key for MYSQL_TYPE_STRING and MYSQL_TYPE_VARSTRING is built by collating the column value and taking the collation from Field::charset(). The data types implemented on Field_fbt - UUID, INET6 and INET4 report MYSQL_TYPE_STRING, and their charset() is my_charset_numeric, which is latin1. Their values are however plain binary and accordingly innodb maps them to DATA_FIXBINARY. Their keys were therefore run through latin1_swedish_ci, which folds them. That corrupts the key in two ways: 1. A key mismatch for the same row. The FK constraint's referenced key that is appended for the parent of a child INSERT is built from the InnoDB record and is not collated, and it does not match the primary key appended due to the parent row's direct write. Certification saw no dependency between a child INSERT and a concurrent parent UPDATE, and two appliers could apply them in parallel causing a hang or crash. 2. A key collision between distinct rows. The folding is many to one, so different values collapse onto one key, Certification compares keys byte for byte, so unrelated rows were treated as the same row. Concurrent transactions on them certified as a conflict and one was aborted with ER_LOCK_DEADLOCK. Fix is for wsrep_store_key_val_for_row() to skip the collation for fields that InnoDB stores as binary, using the same condition as get_innobase_type_from_mysql_type(). This is a no-op for the types that worked before. This change requires to bump the application protocol version to level 5. The commit has also two mtr tests for regression testing. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Dave Gosselin
dave.gosselin@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-35845: Propagate a constant into an IN predicate SELECT * FROM t1 WHERE v IN ('a','b') AND v = 'b' kept both conjuncts when v is a string column, while the equivalent form written with OR was simplified to v = 'b'. Two mechanisms can perform a rewrite. Multiple equalities handle it when check_simple_equality() builds an Item_equal, which it does only if the field's charset allows constant propagation. Up through 10.5 the default character set was latin1 whose collation handler supports constant propagation. MDEV-19123 made utf8mb4 the default in 11.6, and the utf8 collation handlers report that they do not support constant propagation. The other mechanism is propagate_cond_constants(), which rewrote the OR form under every collation. It descends through change_cond_ref_to_const(), which returns on any node whose eq_cmp_result() is COND_OK. Item_func_in inherits that value, so the IN predicate was skipped. Implement an optimization in change_cond_ref_to_const() that replaces the predicant of an IN predicate with the constant from an equality at the same AND level. The predicant is compared against every value of the list, so the existing per-operand test from MDEV-7152 is applied once for each of them. Only a predicant whose arguments were all aggregated to one comparison data type is replaced. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Jacob Williams
jacob@iakob.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-38757 Fix EXCHANGE PARTITION with generated columns containing AND/OR conditions EXCHANGE PARTITION fails with ERROR 1736 (Tables have different definitions) when tables contain generated columns with AND/OR conditions, even when the expressions are logically equivalent. This occurs because when expressions are re-parsed (e.g., via CREATE TABLE ... LIKE), the order of arguments in AND/OR conditions may change, but the comparison was order-sensitive. The Item_cond::eq() method was implemented to perform set-based comparison for commutative AND/OR operations. The set-based comparison algorithm ensures that two Item_cond expressions are considered equal if they contain the same set of equivalent arguments, regardless of order. Added comprehensive test case covering: - Generated columns with OR conditions - Generated columns with AND conditions - Multiple generated columns with different AND/OR combinations - Nested AND/OR conditions The fix allows EXCHANGE PARTITION to succeed when expressions are logically equivalent but have different argument ordering, which is correct behavior since AND/OR operations are commutative. MDEV-38757 Limit unordered vcol condition comparison to EXCHANGE PARTITION Review follow-up to the previous commit, which made Item_cond::eq() compare AND/OR argument lists as sets for every caller. That changed equality semantics globally and broke main.derived_cond_pushdown, where conditions that eq() started reporting as equal were dropped from attached_condition. Reordering AND/OR operands also changes evaluation order, which is observable when operands are functions, so the relaxed comparison must not be the default. Item::Eq_config gains an unordered_conditions flag, defaulting to false, next to the existing binary_cmp and omit_table_names flags. Item_cond::eq() compares its argument lists as sets only when that flag is set, and otherwise reports two distinct Item_cond objects as unequal, as it did before this patch series. The flag is threaded through Virtual_column_info::is_equal() and a new mysql_compare_tables() parameter, and only Sql_cmd_alter_table_exchange_partition passes it as true, so the relaxed comparison stays confined to the EXCHANGE PARTITION metadata check. The set comparison tests containment in both directions rather than comparing element counts, so an expression also matches a form that repeats one of its terms, for example col1 > 10 and col2 < 100 or col3 > 50 col3 > 50 or col1 > 10 and col2 < 100 or col3 > 50 Test 5 of parts.partition_exchange_generated_columns covers that case. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Sergei Golubchik
serg@mariadb.org |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fix mariadb-plugin-defines.cmake for multi-config | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Alexey (Holyfoot) Botchkov
holyfoot@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-40394 XML schema fails on self-referencing type. Copy XMLSchema_user_type information when the type is used recursively. Copies that were once created are stored in m_c_free and then reused later to avoid memory issues. XMLSchema_item::is_validate_done() replaced with ::end_validation(). XMLSchema_group_def::check_type() now checks for circular groups. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Jacob Williams
jacob@iakob.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-38757 Fix EXCHANGE PARTITION with generated columns containing AND/OR conditions EXCHANGE PARTITION fails with ERROR 1736 (Tables have different definitions) when tables contain generated columns with AND/OR conditions, even when the expressions are logically equivalent. This occurs because when expressions are re-parsed (e.g., via CREATE TABLE ... LIKE), the order of arguments in AND/OR conditions may change, but the comparison was order-sensitive. The Item_cond::eq() method was implemented to perform set-based comparison for commutative AND/OR operations. The set-based comparison algorithm ensures that two Item_cond expressions are considered equal if they contain the same set of equivalent arguments, regardless of order. Added comprehensive test case covering: - Generated columns with OR conditions - Generated columns with AND conditions - Multiple generated columns with different AND/OR combinations - Nested AND/OR conditions The fix allows EXCHANGE PARTITION to succeed when expressions are logically equivalent but have different argument ordering, which is correct behavior since AND/OR operations are commutative. MDEV-38757 Limit unordered vcol condition comparison to EXCHANGE PARTITION Review follow-up to the previous commit, which made Item_cond::eq() compare AND/OR argument lists as sets for every caller. That changed equality semantics globally and broke main.derived_cond_pushdown, where conditions that eq() started reporting as equal were dropped from attached_condition. Reordering AND/OR operands also changes evaluation order, which is observable when operands are functions, so the relaxed comparison must not be the default. Item::Eq_config gains an unordered_conditions flag, defaulting to false, next to the existing binary_cmp and omit_table_names flags. Item_cond::eq() compares its argument lists as sets only when that flag is set, and otherwise reports two distinct Item_cond objects as unequal, as it did before this patch series. The flag is threaded through Virtual_column_info::is_equal() and a new mysql_compare_tables() parameter, and only Sql_cmd_alter_table_exchange_partition passes it as true, so the relaxed comparison stays confined to the EXCHANGE PARTITION metadata check. The set comparison tests containment in both directions rather than comparing element counts, so an expression also matches a form that repeats one of its terms, for example col1 > 10 and col2 < 100 or col3 > 50 col3 > 50 or col1 > 10 and col2 < 100 or col3 > 50 Test 5 of parts.partition_exchange_generated_columns covers that case. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Rex Johnston
rex.johnston@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
PQ: the workers pre-aggregate a query that has no GROUP BY SELECT COUNT(*), SUM(b) FROM t ran serially. The workers could pre-aggregate a GROUP BY, but aggregation over the whole table was refused, because the shape the grouped path merges through is not there: with no group the server materialises nothing, and aggregates in end_send_group() straight off the last join tab -- no aggregation table, no group key, nothing for a partial to be merged into. It turns out neither end needs new machinery, and this commit is mostly the finding of that. The manager already merges these. end_send_group() reaches Item_sum::add(), and add() honours a value left by direct_add() for every aggregate the gate accepts -- COUNT adds a count instead of incrementing, AVG takes a partial sum together with the number of rows behind it. So the drain primes the aggregates and hands the row to the plan's own terminal here exactly as it does through end_update() for a GROUP BY, and the drain needed no case of its own. The workers accumulate into the grouped machinery with a single group in it. The layout gives this shape a group of one constant column, and from there it is the grouped path: a worker keeps one partial in a keyed container, merges into it through end_update(), and ships one row. Beyond costing a column per shipped row -- of which there is one per worker -- that is also what keeps Item_sum_avg::create_tmp_field() packing the count beside the sum, which it does only for a container that has a group. An average built any other way would have arrived without its count. So what is actually new is the gate. The aggregate tests -- the five that can be merged, no DISTINCT, one argument, an argument a worker can evaluate -- are the same for both shapes and move out to pwt_aggregates_can_be_merged(). What is left is the shape question, and which shape to ask about is the query's own grouping rather than the plan's: a query that names a GROUP BY stays the grouped question whatever the optimizer then did with it, so a plan with no group key to merge through is a refusal of that query and not an invitation to read it as aggregating over everything, which would answer something else. Only a query that never grouped reaches the second question. Refused there: a select-list item reading a column outside an aggregate. Its value is whichever row the terminal happened to hold, and a worker holds a different one. An empty result needed nothing. No rows means no groups means no partials shipped, and end_send_group() still sends its one row at end of records: COUNT(*) is 0, SUM is NULL, one row and not one per worker. The new test checks each of those rather than assuming them. main.parallel_query_aggregate_whole is that test: serial against parallel for COUNT, COUNT(col), SUM, MIN, MAX and AVG over integer, decimal and double columns; the empty case; that exactly one row is sent; and that a DISTINCT aggregate, STD, GROUP_CONCAT and a bare column outside an aggregate are still refused and run serially. main.parallel_query_aggregate gains the fall-back case, where the container turns out to have no group index: the constant group reaches the same fall-back, ships plain rows, and the manager aggregates them a row at a time. Known and accepted: adding doubles is not associative, so SUM and AVG over DOUBLE or FLOAT can differ from the serial answer, and between runs, in the last significant bit -- which worker summed which chunk is scheduling. Decimal and integer aggregates are exact and unaffected. The test rounds well clear of the last bit rather than leaving floats uncovered. Under a forced-worker sweep of the main suite (--parallel-worker-threads=4) three more tests differ than before, all of them EXPLAIN text where a query of this shape now says ALL_parallel or range_parallel: main.costs, main.func_group_innodb and main.innodb_full_scan. No value changes in any of them. This commit was prepared with Claude Code (Opus 5), which established that Item_sum::add() already honours a directly added partial -- the fact the whole change rests on -- and found that a container without a group would have dropped an average's count. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Raghunandan Bhat
raghunandan.bhat96@gmail.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-40422: use-of-uninitialized-value in my_convert Problem: CAST(expr AS CHAR) has nothing to convert when the argument already has the requested character set, so it returns a String that reuses the argument's buffer. `Item_copy_string::copy()` compares String objects and not their buffers, so it does not see re-usage of buffer and copies the buffer onto itself. `String::copy()` needs one byte more for the terminating '\0' and adjusting it frees the old buffer before allocating the new one, so the copy reads freed memory. Fix: Make sure the source owns the data before copying it into the destination. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Kristian Nielsen
knielsen@knielsen-hq.org |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Semi-sync: Refactor in preparation for using GTID in semi-sync acks This is a refactor patch that contains no/little logic changes but a lot of mostly mechanic code changes to prepare for allowing to use either old-style filename/offset or new-style GTID to identify an event group in the semi-sync ack. The idea is to replace all explicit filename/offset function arguments with a generic Repl_semi_sync_trx_info *inf to identify an event group (aka "transaction"). This object can then be used to look up in the semi-sync hash table by either file/pos or by GTID. The classes Active_tranx and Repl_semi_sync_master are sub-classed into Active_tranx_file_pos/Active_tranx_gtid and Repl_semi_sync_master_file_pos/Repl_semi_sync_master_gtid. Virtual functions are implemented in each for comparing identifiers and for calculating hash keys, using either the file/pos or the GTID as appropriate. This way, the existing logic can now be used with either (only file/pos is actually used in this patch; adding GTID is for a subsequent patch). For the binlog writing side, report_binlog_update(), wait_after_sync(), and THD::semisync_info are extended to also take the GTID of the event group, which is already available in the calling code. For the dump thread / slave connection side, update_sync_header() is extended to take also the GTID. The dump thread code is extended to keep track of the GTID of the current event group (slightly extending the logic already there to keep track of event groups). Also, the dump thread now only passes the last event of an event group into the semisync layer (the other events are redundant, as they are never semi-sync ack'ed, saving needless semisync locking and hash lookups). Signed-off-by: Kristian Nielsen <[email protected]> |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Kristian Nielsen
knielsen@knielsen-hq.org |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Semi-sync: Some few after-review fixes Signed-off-by: Kristian Nielsen <[email protected]> |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Jan Lindström
jan.lindstrom@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-40903 : query 'reset master' failed: ER_BINLOG_IN_USE (4243) in Galera tests RESET MASTER fails with ER_BINLOG_IN_USE when a binlog dump thread is still lingering after a slave disconnects, causing sporadic failures. Replace direct RESET MASTER in galera, galera_sr and galera_3nodes tests with include/reset_master.inc, which kills leftover dump threads and retries the RESET MASTER. Redundant preceding calls to include/kill_binlog_dump_threads.inc are removed, as reset_master.inc already does that itself. Note that all of affected test cases are not vulnerable of failure, they are here modified for completeness. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Khaled Riyad
khaled57.dev@gmail.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-40377 Change Server source code to point to new docs (11.8 part) Replace the remaining Knowledge Base links with their MariaDB Documentation equivalents, including the 838 URLs in the help tables. Only URLs change in fill_help_tables.sql. fill_help_tables.sql conflicts on merge upward; keep the target branch's version. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Jacob Williams
jacob@iakob.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-38757 Fix EXCHANGE PARTITION with generated columns containing AND/OR conditions EXCHANGE PARTITION fails with ERROR 1736 (Tables have different definitions) when tables contain generated columns with AND/OR conditions, even when the expressions are logically equivalent. This occurs because when expressions are re-parsed (e.g., via CREATE TABLE ... LIKE), the order of arguments in AND/OR conditions may change, but the comparison was order-sensitive. The Item_cond::eq() method was implemented to perform set-based comparison for commutative AND/OR operations. The set-based comparison algorithm ensures that two Item_cond expressions are considered equal if they contain the same set of equivalent arguments, regardless of order. Added comprehensive test case covering: - Generated columns with OR conditions - Generated columns with AND conditions - Multiple generated columns with different AND/OR combinations - Nested AND/OR conditions The fix allows EXCHANGE PARTITION to succeed when expressions are logically equivalent but have different argument ordering, which is correct behavior since AND/OR operations are commutative. MDEV-38757 Limit unordered vcol condition comparison to EXCHANGE PARTITION Review follow-up to the previous commit, which made Item_cond::eq() compare AND/OR argument lists as sets for every caller. That changed equality semantics globally and broke main.derived_cond_pushdown, where conditions that eq() started reporting as equal were dropped from attached_condition. Reordering AND/OR operands also changes evaluation order, which is observable when operands are functions, so the relaxed comparison must not be the default. Item::Eq_config gains an unordered_conditions flag, defaulting to false, next to the existing binary_cmp and omit_table_names flags. Item_cond::eq() compares its argument lists as sets only when that flag is set, and otherwise reports two distinct Item_cond objects as unequal, as it did before this patch series. The flag is threaded through Virtual_column_info::is_equal() and a new mysql_compare_tables() parameter, and only Sql_cmd_alter_table_exchange_partition passes it as true, so the relaxed comparison stays confined to the EXCHANGE PARTITION metadata check. The set comparison tests containment in both directions rather than comparing element counts, so an expression also matches a form that repeats one of its terms, for example col1 > 10 and col2 < 100 or col3 > 50 col3 > 50 or col1 > 10 and col2 < 100 or col3 > 50 Test 5 of parts.partition_exchange_generated_columns covers that case. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Luke Lu
lukeyl@amazon.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-35732 Failed ALTER TABLE leaves cached table metadata corrupted A failed ALTER TABLE ... RENAME INDEX ... ALGORITHM=INSTANT changed the outcome of a subsequent, unrelated ALTER TABLE ... ADD FOREIGN KEY. A failed statement must have no side effects, but here the second statement wrongly succeeded where on a fresh table it correctly fails with ER_DUP_KEYNAME. Root cause: while rebuilding the key list, mysql_prepare_alter_table() handled a RENAME INDEX request by clearing HA_GENERATED_KEY in place on key_info->flags. key_info points into the (possibly cached) TABLE object that is reused across statements. The ALGORITHM=INSTANT incompatibility is only detected later, after mysql_prepare_alter_table() has returned, so the statement fails with ER_ALTER_OPERATION_NOT_SUPPORTED with the cleared flag never restored. The cached generated FK-support index (fk1) was thus left permanently marked as user-defined. That corrupted flag flips the de-duplication tie-break in the next ALTER: adding FOREIGN KEY ind1 (b) creates a generated support index on column b that prefix-matches fk1(b). Normally fk1 (generated) is dropped and the new ind1 survives, colliding by name with the existing user index ind1(a) and raising ER_DUP_KEYNAME. With fk1 no longer marked generated, the new ind1 is dropped instead, so no name collision is reached and the ADD FOREIGN KEY silently succeeds. Fix: do not mutate the cached key_info->flags. Track the "renamed => no longer generated" decision in a per-key local variable (generated_key), initialised from the flag, set to false on rename, and passed to the Key constructor. This preserves the in-statement behaviour while leaving the cached TABLE metadata untouched, so a failed ALTER has no lingering effect. All new code of the whole pull request, including one or several files that are either new files or modified ones, are contributed under the BSD-new license. I am contributing on behalf of my employer Amazon Web Services, Inc. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Sergei Golubchik
serg@mariadb.org |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fix the build for -G "Ninja Multi-Config" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||