Console View
|
Categories: connectors experimental galera main |
|
| connectors | experimental | galera | main | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Thirunarayanan Balathandayuthapani
thiru@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-41666 Corruption on statement rollback when ON UPDATE SET NULL affects the base column Problem: ======= - When a foreign key column is the base column of a virtual column that is indexed together with other virtual columns, a cascaded update (ON UPDATE/DELETE SET NULL) computed the old value of only the dependent virtual column. The other virtual key parts of the index stayed NULL in update->old_vrow. If the statement was rolled back, row_upd_store_v_row() used those NULLs, so row_upd_sec_index_entry() searched the secondary index for a record that did not exist and hit the "Record in index was not found on update" assertion. Solution: ========= dict_mem_fill_vcol_set_for_base_col(): Add every virtual key part of each index that contains the dependent virtual column to dict_foreign_t::v_cols, as dict_mem_fill_vcol_from_v_indexes() already does. row_ins_foreign_fill_virtual() then computes the old values of all of them. Based on mysql/mysql-server@c48fa1e57a8e810f89b43d3e94bcbefa1fd69806 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Oleksandr Byelkin
sanja@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Fix sporadic failure of main.charset_client_win_utf8mb4 The test set the password via "chcp 850 && echo ...", but the console codepage is shared by all parallel mtr workers, so another process could switch it to UTF8 and the password got stored as UTF8. Write the cp850 password byte to a file and feed it to the client instead. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Aleksey Midenkov
midenok@gmail.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-39306 Index corruption on UPDATE when using versioned InnoDB table (on UPDATE) Duplicated by: MDEV-39711 UPDATE on System-Versioned Tables uses the after-value in Row-format Binlog's before-image MDEV-24646 ASAN heap-use-after-free in Field_blob::pack / THD::binlog_update_row upon DML on table with virtual column vers_update_fields() recomputed virtual fields with VCOL_UPDATE_FOR_READ. For BLOB virtual columns this mode swaps Field_blob::value and read_value after the computation (swap_values). After the swap, Field_blob::value holds the buffer that record[1] (the old row image) points to. The next VCOL_UPDATE_FOR_WRITE computation, done by fill_record() right after vers_update_fields(), stores the new value into that buffer and so overwrites the old row image. As a result, InnoDB builds the old secondary-index key from the new value (MDEV-39306), and the row-format binlog writes the new value into the before-image (MDEV-39711), or a freed buffer (MDEV-24646). REPLACE had the same problem with record[2]. TABLE::delete_row() saves the new row into record[2] and turns the conflicting row into history with vers_update_end(). Its VCOL_UPDATE_FOR_WRITE computation stored the virtual blobs of the old row into Field_blob::value, the buffer record[2] points to, so the new row was written with them. Versioned DELETE had the same problem with record[1]: it points to the virtual blobs computed with VCOL_UPDATE_FOR_DELETE in Field_blob::value, and vers_update_end() overwrote them. The fix removes the virtual fields computation from vers_update_fields(). Its callers now recompute virtual fields with VCOL_UPDATE_FOR_WRITE after the system fields are set: fill_record() already did, while update_generated_fields(), multi_update::do_updates() and the RBR appliers do it explicitly. multi_update::do_updates() still computes virtual fields twice per row: before BEFORE triggers and after vers_update_fields(), since the system fields cannot be set before compare_record(). For REPLACE and DELETE, TABLE::delete_row() keeps Field_blob::value with remember_blob_values() while it updates the history row. In the RBR appliers no VCOL_UPDATE_FOR_WRITE followed vers_update_fields(), so record[1] was not overwritten there. Their explicit computation replaces the one removed from vers_update_fields(). It uses VCOL_UPDATE_FOR_WRITE, so an error in a virtual field expression now stops the slave instead of being turned into a warning. In the Update_rows applier, vers_insert_history_row() also overwrote the error of ha_update_row(), so a failed update on the slave was ignored and its history row was written. The history row is now written only when the update succeeded. Based on the MDEV-24646/MDEV-39711 fix by ParadoxV5 (0c2f3de1a2d), which switched vers_update_fields() to VCOL_UPDATE_FOR_WRITE. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Oleksandr Byelkin
sanja@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| New HeidiSQL v12.21 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Daniel Black
daniel@mariadb.org |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-40386: DuckDB - pass through linker launcher flags With the linker flags previously pushed, the rpm build requires the linker launcher to set the RPM_ARCH and other environment flags on which MDEV-32686 depends. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Aleksey Midenkov
midenok@gmail.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-41621 Stored generated BLOB column is wrong on REPLACE into versioned table REPLACE into a system-versioned table turns the conflicting row into history in TABLE::delete_row(): it saves the new row into record[2], restores the conflicting row from record[1] and sets its row_end with vers_update_end(). The VCOL_UPDATE_FOR_WRITE computation in vers_update_end() also recomputes stored generated columns. When Field_blob::store() copies the value into Field_blob::value (e.g. on a character set conversion), it overwrote the buffer that the stored generated blob of the new row in record[2] points to, and the new row was written with the value of the history row. The index on the column holds the same value, so CHECK TABLE does not detect it. remember_blob_values(), which keeps Field_blob::value around vers_update_end() in TABLE::delete_row() and vers_insert_history_row() and around update_generated_fields() in period_make_insert(), covered only virtual columns. The fix adds the with_stored parameter to remember_blob_values(), restore_blob_values() and free_blob_values(), which also covers stored generated blob columns. TABLE::delete_row(), vers_insert_history_row() and period_make_insert() use it and size the storage by TABLE_SHARE::virtual_fields, the number of all generated columns. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Vladislav Vaintroub
vvaintroub@gmail.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-39150 Some data conversion macros fail to use memcpy() MDEV-37788 converted the uintNkorr() and intNstore() macros to use memcpy() and byte swap intrinsics, but the floating point and short/long conversion macros in big_endian.h and myisampack.h still accessed data one byte at a time, and those in little_endian.h were a mix of both. Compilers may emit slow byte-at-a-time loads and stores for such code. Reimplement the macros with memcpy(), and with MY_BSWAP32/MY_BSWAP64 where the byte order differs from the host. big_endian.h and little_endian.h no longer differ, so move the macros to my_byteorder.h and remove the two headers, which are no longer installed. Implement mi_float4store() etc. in myisampack.h with the same helper macros. Remove the unused ulongget() macro, and the code for the mixed-endian floating point layout (a little-endian CPU with big-endian floating point word order) from the macros, change_double_for_sort() and dtoa.c. It only applied to the obsolete ARM FPA format. Reimplement mach_double_read(), mach_double_write(), mach_float_read() and mach_float_write() in InnoDB with float8get(), float8store(), float4get() and float4store(), instead of copying bytes in a loop. The stored formats do not change. The unit test byte_order-t now checks the byte layout of the floating point macros and the sign extension of the native byte order macros, so no MTR test is added. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Aleksey Midenkov
midenok@gmail.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-41493 AFTER UPDATE trigger reads wrong NEW value of BLOB/TEXT virtual column in system-versioned table UPDATE, multi-table UPDATE, INSERT ... ON DUPLICATE KEY UPDATE and the RBR Update_rows applier save the new row into record[2] and call vers_insert_history_row(), which restores the old row from record[1] and sets its row_end with vers_update_end(). The VCOL_UPDATE_FOR_WRITE computation in vers_update_end() stored the virtual blobs of the old row into Field_blob::value, the buffer that the virtual blobs of the new row in record[2] point to, or reallocated it when the old value was longer. After restore_record(record[2]), AFTER UPDATE triggers read the old value, or freed memory, as NEW. remember_blob_values() and restore_blob_values() skipped virtual GEOMETRY columns: they selected MYSQL_TYPE_BLOB, while virtual_not_stored_blob_fields counts all fields with BLOB_FLAG. So GEOMETRY had the same problem also in TABLE::delete_row() for REPLACE and DELETE. UPDATE ... FOR PORTION OF has the same problem in period_make_insert(), which computes the inserted leftover rows into record[0] while the new row is saved in record[2], also for tables without system versioning. The fix saves Field_blob::value with remember_blob_values() before the history row in vers_insert_history_row() or the leftover row in period_make_insert() is computed, and puts it back with restore_blob_values() afterwards, as TABLE::delete_row() already does for REPLACE (for DELETE it frees the saved values instead). remember_blob_values() and restore_blob_values() now select fields by BLOB_FLAG. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
bsrikanth-mariadb
srikanth.bondalapati@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-41293: FederatedX: connection state after a net_read_timeout Problem: When reading the reply of the remote server times out, the client library compiled into the server returns without closing the connection and without setting a client error. FederatedX took the raw ER_NET_READ_INTERRUPTED for an error of the remote server and went on using a connection that still had the reply of the failed statement to arrive. As a result: * the next statement on that connection failed in various ways, either with ER_QUERY_ON_FOREIGN_DATA_SOURCE ("Server has gone away") or with an error packet that mysqltest took for a malformed packet; * inside a transaction, the following statements continued on a new remote session in autocommit mode, so they were committed on the remote server one by one even though the local transaction was later rolled back. The savepoints of the lost session were also still remembered by FederatedX. The same happened when the connection was lost while reading the reply. Fix: * After a timeout FederatedX closes the connection, so that the next statement opens a new one. The client still gets the error of the timeout, ER_NET_READ_INTERRUPTED. * Whenever the connection is gone after a failed statement, timeout or not, the state of the lost session (autocommit mode, savepoints) is forgotten and the local transaction is marked to be rolled back, so a new connection starts the transaction again. The closed connection is also freed, which was leaked before. * Errors of the client library are reported as ER_QUERY_ON_FOREIGN_DATA_SOURCE by ha_federatedx::info() as well, the same way as by the pushed down multi-table UPDATE/DELETE. * The error state of ha_federatedx, read by info(), is initialized. Test: federatedx_pushdown_upd_del covers the timeout of a pushed down multi-table UPDATE and DELETE and of reading a result, the statements after it, the same inside a transaction, a connection killed in the middle of a statement, client library errors in info(), and that an error of the remote server which merely has the code of ER_NET_READ_INTERRUPTED is not taken for a timeout. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Aleksey Midenkov
midenok@gmail.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-41617 Index corruption on UPDATE of table with long unique hash collision and indexed virtual blob handler::check_duplicate_long_entry_key() reads all rows with the same long unique hash. Each read (ha_index_read_map() and every ha_index_next_same() hit) runs TABLE::update_virtual_fields() with VCOL_UPDATE_FOR_READ, which swaps Field_blob::value and read_value of virtual blob columns. The swap was undone only after the first read. Every further read swapped again, so the buffer that record[1] (the old row of UPDATE) points to ended up in value: the next read stored the lookup row into it, or restore_blob_values() freed it. InnoDB then built the old secondary index key from overwritten or freed memory and did not find the record to update. The fix undoes the swap after each read. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
bsrikanth-mariadb
srikanth.bondalapati@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-41293: FederatedX: connection state after a net_read_timeout Problem: When reading the reply of the remote server times out, the client library compiled into the server returns without closing the connection and without setting a client error. FederatedX took the raw ER_NET_READ_INTERRUPTED for an error of the remote server and went on using a connection that still had the reply of the failed statement to arrive. As a result: * the next statement on that connection failed in various ways, either with ER_QUERY_ON_FOREIGN_DATA_SOURCE ("Server has gone away") or with an error packet that mysqltest took for a malformed packet; * inside a transaction, the following statements continued on a new remote session in autocommit mode, so they were committed on the remote server one by one even though the local transaction was later rolled back. The savepoints of the lost session were also still remembered by FederatedX. The same happened when the connection was lost while reading the reply. Fix: * After a timeout FederatedX closes the connection, so that the next statement opens a new one. The client still gets the error of the timeout, ER_NET_READ_INTERRUPTED. * Whenever the connection is gone after a failed statement, timeout or not, the state of the lost session (autocommit mode, savepoints) is forgotten and the local transaction is marked to be rolled back, so a new connection starts the transaction again. The closed connection is also freed, which was leaked before. * Errors of the client library are reported as ER_QUERY_ON_FOREIGN_DATA_SOURCE by ha_federatedx::info() as well, the same way as by the pushed down multi-table UPDATE/DELETE. * The error state of ha_federatedx, read by info(), is initialized. Test: federatedx_pushdown_upd_del covers the timeout of a pushed down multi-table UPDATE and DELETE and of reading a result, the statements after it, the same inside a transaction, a connection killed in the middle of a statement, client library errors in info(), and that an error of the remote server which merely has the code of ER_NET_READ_INTERRUPTED is not taken for a timeout. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Aleksey Midenkov
midenok@gmail.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-41493 AFTER UPDATE trigger reads wrong NEW value of BLOB/TEXT virtual column in system-versioned table UPDATE, multi-table UPDATE, INSERT ... ON DUPLICATE KEY UPDATE and the RBR Update_rows applier save the new row into record[2] and call vers_insert_history_row(), which restores the old row from record[1] and sets its row_end with vers_update_end(). The VCOL_UPDATE_FOR_WRITE computation in vers_update_end() stored the virtual blobs of the old row into Field_blob::value, the buffer that the virtual blobs of the new row in record[2] point to, or reallocated it when the old value was longer. After restore_record(record[2]), AFTER UPDATE triggers read the old value, or freed memory, as NEW. remember_blob_values() and restore_blob_values() skipped virtual GEOMETRY columns: they selected MYSQL_TYPE_BLOB, while virtual_not_stored_blob_fields counts all fields with BLOB_FLAG. So GEOMETRY had the same problem also in TABLE::delete_row() for REPLACE and DELETE. UPDATE ... FOR PORTION OF has the same problem in period_make_insert(), which computes the inserted leftover rows into record[0] while the new row is saved in record[2], also for tables without system versioning. The fix saves Field_blob::value with remember_blob_values() before the history row in vers_insert_history_row() or the leftover row in period_make_insert() is computed, and puts it back with restore_blob_values() afterwards, as TABLE::delete_row() already does for REPLACE (for DELETE it frees the saved values instead). remember_blob_values() and restore_blob_values() now select fields by BLOB_FLAG. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Aleksey Midenkov
midenok@gmail.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| MDEV-39306 Comments on update_virtual_fields() modes | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Khaled Riyad
khaled57.dev@gmail.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-31567 SIGSEGV in reinit_stmt_before_use | Prepared_statement::execute If the first execution of a prepared statement was killed (for example by max_statement_time) after the top-level JOIN had done the once-per-statement semi-join rewrite of the nested subqueries, but before the nested selects saved their rewritten WHERE into prep_where, the statement was left half-transformed. A later execution then used a freed Item from prep_where or an unfixed Item_field and crashed. Set LEX::needs_reprepare when JOIN::optimize() fails during the select's first optimization, so the statement is re-prepared before it runs again. Also make the handling of needs_reprepare safe when the re-prepare fails: keep the flag so it is tried again, do not skip a pending long data error, and invalidate the SP instruction so that a failed re-parse is retried. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Oleksandr Byelkin
sanja@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| new wolfssl v5.9.4-stable | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Aleksey Midenkov
midenok@gmail.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-39306 Index corruption on UPDATE when using versioned InnoDB table (on UPDATE) Duplicated by: MDEV-39711 UPDATE on System-Versioned Tables uses the after-value in Row-format Binlog's before-image MDEV-24646 ASAN heap-use-after-free in Field_blob::pack / THD::binlog_update_row upon DML on table with virtual column vers_update_fields() recomputed virtual fields with VCOL_UPDATE_FOR_READ. For BLOB virtual columns this mode swaps Field_blob::value and read_value after the computation (swap_values). After the swap, Field_blob::value holds the buffer that record[1] (the old row image) points to. The next VCOL_UPDATE_FOR_WRITE computation, done by fill_record() right after vers_update_fields(), stores the new value into that buffer and so overwrites the old row image. As a result, InnoDB builds the old secondary-index key from the new value (MDEV-39306), and the row-format binlog writes the new value into the before-image (MDEV-39711), or a freed buffer (MDEV-24646). REPLACE had the same problem with record[2]. TABLE::delete_row() saves the new row into record[2] and turns the conflicting row into history with vers_update_end(). Its VCOL_UPDATE_FOR_WRITE computation stored the virtual blobs of the old row into Field_blob::value, the buffer record[2] points to, so the new row was written with them. Versioned DELETE had the same problem with record[1]: it points to the virtual blobs computed with VCOL_UPDATE_FOR_DELETE in Field_blob::value, and vers_update_end() overwrote them. The fix removes the virtual fields computation from vers_update_fields(). Its callers now recompute virtual fields with VCOL_UPDATE_FOR_WRITE after the system fields are set: fill_record() already did, while update_generated_fields(), multi_update::do_updates() and the RBR appliers do it explicitly. multi_update::do_updates() still computes virtual fields twice per row: before BEFORE triggers and after vers_update_fields(), since the system fields cannot be set before compare_record(). For REPLACE and DELETE, TABLE::delete_row() keeps Field_blob::value with remember_blob_values() while it updates the history row. In the RBR appliers no VCOL_UPDATE_FOR_WRITE followed vers_update_fields(), so record[1] was not overwritten there. Their explicit computation replaces the one removed from vers_update_fields(). It uses VCOL_UPDATE_FOR_WRITE, so an error in a virtual field expression now stops the slave instead of being turned into a warning. In the Update_rows applier, vers_insert_history_row() also overwrote the error of ha_update_row(), so a failed update on the slave was ignored and its history row was written. The history row is now written only when the update succeeded. Based on the MDEV-24646/MDEV-39711 fix by ParadoxV5 (0c2f3de1a2d), which switched vers_update_fields() to VCOL_UPDATE_FOR_WRITE. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Oleksandr Byelkin
sanja@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| new PCRE2 10.49 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Aleksey Midenkov
midenok@gmail.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-40854 Use of uninitialized table_will_be_deleted in federated engine MemorySanitizer report: ==851408==WARNING: MemorySanitizer: use-of-uninitialized-value #0 ha_federated::end_bulk_insert() storage/federated/ha_federated.cc:2035:30 #1 mysql_insert(THD*, ...) sql/sql_insert.cc:1258:11 ... Memory was marked as uninitialized #0 __msan_allocated_memory #1 my_malloc mysys/my_malloc.c:116:7 SUMMARY: MemorySanitizer: use-of-uninitialized-value ... end_bulk_insert() table_will_be_deleted is a handler member with no in-class initializer, and the handler object itself is heap-allocated via my_malloc(), so it starts out as garbage. It was only ever set in extra(HA_EXTRA_PREPARE_FOR_DROP) and in external_lock(). For a TEMPORARY table, statement execution can reach end_bulk_insert(), which reads the flag, without external_lock() having run first, so the read sees uninitialized memory. The fix initializes table_will_be_deleted in reset(). Both ha_federated::open() and ha_federatedx::open() call reset(), so the flag is initialized on first open and cleared after every statement. That also covers the first statement after open (e.g. CREATE TEMPORARY TABLE ... ENGINE=FEDERATED ... SELECT, where external_lock() is not called). |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Aleksey Midenkov
midenok@gmail.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-40854 Use of uninitialized table_will_be_deleted in federated engine MemorySanitizer report: ==851408==WARNING: MemorySanitizer: use-of-uninitialized-value #0 ha_federated::end_bulk_insert() storage/federated/ha_federated.cc:2035:30 #1 mysql_insert(THD*, ...) sql/sql_insert.cc:1258:11 ... Memory was marked as uninitialized #0 __msan_allocated_memory #1 my_malloc mysys/my_malloc.c:116:7 SUMMARY: MemorySanitizer: use-of-uninitialized-value ... end_bulk_insert() table_will_be_deleted is a handler member with no in-class initializer, and the handler object itself is heap-allocated via my_malloc(), so it starts out as garbage. It was only ever set in extra(HA_EXTRA_PREPARE_FOR_DROP) and in external_lock(). For a TEMPORARY table, statement execution can reach end_bulk_insert(), which reads the flag, without external_lock() having run first, so the read sees uninitialized memory. The fix initializes table_will_be_deleted in reset(). Both ha_federated::open() and ha_federatedx::open() call reset(), so the flag is initialized on first open and cleared after every statement. That also covers the first statement after open (e.g. CREATE TEMPORARY TABLE ... ENGINE=FEDERATED ... SELECT, where external_lock() is not called). |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Aleksey Midenkov
midenok@gmail.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-41493 AFTER UPDATE trigger reads wrong NEW value of BLOB/TEXT virtual column in system-versioned table UPDATE, multi-table UPDATE, INSERT ... ON DUPLICATE KEY UPDATE and the RBR Update_rows applier save the new row into record[2] and call vers_insert_history_row(), which restores the old row from record[1] and sets its row_end with vers_update_end(). The VCOL_UPDATE_FOR_WRITE computation in vers_update_end() stored the virtual blobs of the old row into Field_blob::value, the buffer that the virtual blobs of the new row in record[2] point to, or reallocated it when the old value was longer. After restore_record(record[2]), AFTER UPDATE triggers read the old value, or freed memory, as NEW. remember_blob_values() and restore_blob_values() skipped virtual GEOMETRY columns: they selected MYSQL_TYPE_BLOB, while virtual_not_stored_blob_fields counts all fields with BLOB_FLAG. So GEOMETRY had the same problem also in TABLE::delete_row() for REPLACE and DELETE. UPDATE ... FOR PORTION OF has the same problem in period_make_insert(), which computes the inserted leftover rows into record[0] while the new row is saved in record[2], also for tables without system versioning. The fix saves Field_blob::value with remember_blob_values() before the history row in vers_insert_history_row() or the leftover row in period_make_insert() is computed, and puts it back with restore_blob_values() afterwards, as TABLE::delete_row() already does for REPLACE (for DELETE it frees the saved values instead). remember_blob_values() and restore_blob_values() now select fields by BLOB_FLAG. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Aleksey Midenkov
midenok@gmail.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-39306 Index corruption on UPDATE when using versioned InnoDB table (on UPDATE) Duplicated by: MDEV-39711 UPDATE on System-Versioned Tables uses the after-value in Row-format Binlog's before-image MDEV-24646 ASAN heap-use-after-free in Field_blob::pack / THD::binlog_update_row upon DML on table with virtual column vers_update_fields() recomputed virtual fields with VCOL_UPDATE_FOR_READ. For BLOB virtual columns this mode swaps Field_blob::value and read_value after the computation (swap_values). After the swap, Field_blob::value holds the buffer that record[1] (the old row image) points to. The next VCOL_UPDATE_FOR_WRITE computation, done by fill_record() right after vers_update_fields(), stores the new value into that buffer and so overwrites the old row image. As a result, InnoDB builds the old secondary-index key from the new value (MDEV-39306), and the row-format binlog writes the new value into the before-image (MDEV-39711), or a freed buffer (MDEV-24646). REPLACE had the same problem with record[2]. TABLE::delete_row() saves the new row into record[2] and turns the conflicting row into history with vers_update_end(). Its VCOL_UPDATE_FOR_WRITE computation stored the virtual blobs of the old row into Field_blob::value, the buffer record[2] points to, so the new row was written with them. Versioned DELETE had the same problem with record[1]: it points to the virtual blobs computed with VCOL_UPDATE_FOR_DELETE in Field_blob::value, and vers_update_end() overwrote them. The fix removes the virtual fields computation from vers_update_fields(). Its callers now recompute virtual fields with VCOL_UPDATE_FOR_WRITE after the system fields are set: fill_record() already did, while update_generated_fields(), multi_update::do_updates() and the RBR appliers do it explicitly. multi_update::do_updates() still computes virtual fields twice per row: before BEFORE triggers and after vers_update_fields(), since the system fields cannot be set before compare_record(). For REPLACE and DELETE, TABLE::delete_row() keeps Field_blob::value with remember_blob_values() while it updates the history row. In the RBR appliers no VCOL_UPDATE_FOR_WRITE followed vers_update_fields(), so record[1] was not overwritten there. Their explicit computation replaces the one removed from vers_update_fields(). It uses VCOL_UPDATE_FOR_WRITE, so an error in a virtual field expression now stops the slave instead of being turned into a warning. In the Update_rows applier, vers_insert_history_row() also overwrote the error of ha_update_row(), so a failed update on the slave was ignored and its history row was written. The history row is now written only when the update succeeded. Based on the MDEV-24646/MDEV-39711 fix by ParadoxV5 (0c2f3de1a2d), which switched vers_update_fields() to VCOL_UPDATE_FOR_WRITE. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Sergei Petrunia
sergey@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Squash with previous: assume that thd->free_list == item_copy. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Oleksandr Byelkin
sanja@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Merge branch '11.4' into 11.8 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Khaled Riyad
khaled57.dev@gmail.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-37563 Crash on a FOR loop with a row comparison in the upper bound Both bounds of a FOR loop, and all parameters of a cursor FOR loop, are parsed before their instructions are added. add_instr() then gave all their items to the first instruction, and in a trigger also all NEW and OLD fields. So a row comparison used by a later instruction was cleaned up by the wrong one, on the next CALL, after its memory had already been freed. This crashed in Arg_comparator::cleanup(). Give each instruction only the items of its own expression, and its own trigger fields. To find them, cut THD::free_list at the newest item of each expression, starting with the oldest expression. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Aleksey Midenkov
midenok@gmail.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-41621 Stored generated BLOB column is wrong on REPLACE into versioned table REPLACE into a system-versioned table turns the conflicting row into history in TABLE::delete_row(): it saves the new row into record[2], restores the conflicting row from record[1] and sets its row_end with vers_update_end(). The VCOL_UPDATE_FOR_WRITE computation in vers_update_end() also recomputes stored generated columns. When Field_blob::store() copies the value into Field_blob::value (e.g. on a character set conversion), it overwrote the buffer that the stored generated blob of the new row in record[2] points to, and the new row was written with the value of the history row. The index on the column holds the same value, so CHECK TABLE does not detect it. remember_blob_values(), which keeps Field_blob::value around vers_update_end() in TABLE::delete_row() and vers_insert_history_row() and around update_generated_fields() in period_make_insert(), covered only virtual columns. The fix adds the with_stored parameter to remember_blob_values(), restore_blob_values() and free_blob_values(), which also covers stored generated blob columns. TABLE::delete_row(), vers_insert_history_row() and period_make_insert() use it and size the storage by TABLE_SHARE::virtual_fields, the number of all generated columns. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Kristian Nielsen
knielsen@knielsen-hq.org |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Merge branch 'knielsen_log_event_read_validation_base_12.3' into 13.1 This merges the patch series that fixes a lot of missing validation checks for read_log_event(). The merge includes a few added fixes that are needed in new code introduced in 13.1. Signed-off-by: Kristian Nielsen <[email protected]> |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Aleksey Midenkov
midenok@gmail.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-41617 Index corruption on UPDATE of table with long unique hash collision and indexed virtual blob handler::check_duplicate_long_entry_key() reads all rows with the same long unique hash. Each read (ha_index_read_map() and every ha_index_next_same() hit) runs TABLE::update_virtual_fields() with VCOL_UPDATE_FOR_READ, which swaps Field_blob::value and read_value of virtual blob columns. The swap was undone only after the first read. Every further read swapped again, so the buffer that record[1] (the old row of UPDATE) points to ended up in value: the next read stored the lookup row into it, or restore_blob_values() freed it. InnoDB then built the old secondary index key from overwritten or freed memory and did not find the record to update. The fix undoes the swap after each read. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Sergei Petrunia
sergey@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-36057: Assertion failure on 2nd execution of parameterized PS Followup to fix for MDEV-35318: In Prepared_statement::execute_loop(), if we enter this function with lex->needs_reprepare=true, we need to re-prepare the statement. We also need to call set_parameters() to get PS parameter values. We failed to do this and that's the bug. Note that we need to also handle the other reprepare scenario: when we get into Prepared_statement::execute_loop(), call set_parameters() and then hit a "DDL was changed" error with reprepare_observer, we should NOT call set_parameters() again. The parameters have already been transferred to the reprepared statement in Prepared_statement::reprepare()|swap_parameter_array(). (cherry picked from commit 80067a69feaeb5df30abb1bfaf7d4e713ccbf027) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Aleksey Midenkov
midenok@gmail.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-41621 Stored generated BLOB column is wrong on REPLACE into versioned table REPLACE into a system-versioned table turns the conflicting row into history in TABLE::delete_row(): it saves the new row into record[2], restores the conflicting row from record[1] and sets its row_end with vers_update_end(). The VCOL_UPDATE_FOR_WRITE computation in vers_update_end() also recomputes stored generated columns. When Field_blob::store() copies the value into Field_blob::value (e.g. on a character set conversion), it overwrote the buffer that the stored generated blob of the new row in record[2] points to, and the new row was written with the value of the history row. The index on the column holds the same value, so CHECK TABLE does not detect it. remember_blob_values(), which keeps Field_blob::value around vers_update_end() in TABLE::delete_row() and vers_insert_history_row() and around update_generated_fields() in period_make_insert(), covered only virtual columns. The fix adds the with_stored parameter to remember_blob_values(), restore_blob_values() and free_blob_values(), which also covers stored generated blob columns. TABLE::delete_row(), vers_insert_history_row() and period_make_insert() use it and size the storage by TABLE_SHARE::virtual_fields, the number of all generated columns. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Oleksandr Byelkin
sanja@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Fix MSAN failure in mysqltest with --cursor-protocol after CC update CONC-821 in Connector/C 3.3.21 no longer resets *length for string binds, so for NULL values the length array in append_stmt_result() stayed uninitialized. Zero-fill it on allocation. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Thirunarayanan Balathandayuthapani
thiru@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-41667 InnoDB: Failing assertion: buf <= (byte*) original_upd_buff + buff_len Problem: ======= An UPDATE on an InnoDB table with several indexed virtual columns could corrupt the heap in calc_row_difference() because the write pointer went past the end of the update buffer. ha_innobase::update_row() sized the buffer from the row length, the maximum key length and fixed padding. That did not allow for the extra packed values calc_row_difference() stores for indexed virtual columns for both the new value and the old value. Solution: ======== When allocating the update buffer in ha_innobase::update_row(), add pack_length() of every virtual column. The row length already counts each virtual column once, so the buffer can now hold both the new and old packed values. All virtual columns are counted, not only the indexed ones, because the buffer is reused and a column may become indexed after it is allocated. Based on mysql/mysql-server@12655140610674db615547cdf86af1f7cbf563c1 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Raghunandan Bhat
raghunandan.bhat96@gmail.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-40616: MSAN - use-of-uninitialized-value in extract_date_time() Problem: STR_TO_DATE(str, format) with %., %@ and %# format specifiers could read past the end of str, because the loops in extract_date_time() read a byte before checking for the end of str. When str was not NUL-terminated, that byte was uninitialized, causing the MSAN error. Fix: Check for the end of str before reading the next byte. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Oleg Smirnov
olernov@gmail.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-38819 Wrong result of 'Range checked for each record' after pushdown from HAVING When a condition was pushed from HAVING into WHERE, its fields were unwrapped in place. The pushed condition then shared field items with the SELECT list. Creating the GROUP BY temporary table later bound those items to the temporary table. With a 'Range checked for each record' plan, range analysis took the value of the outer table's field from the not yet filled temporary table. It built an impossible range, and the query returned no rows. The pushed condition is now cloned before its fields are unwrapped, so it gets its own field items. Items that cannot be cloned (e.g. subqueries) are still unwrapped in place, to keep the pushdown. Such conditions are unlikely to get a 'Range checked for each record' plan. Cloning can also fail with an error, which the pushdown did not handle properly. It modifies HAVING before all of its steps have succeeded, yet on a failure it emptied the list of pushed conditions and let the query continue, so the conditions already removed from HAVING were not checked at all. pushdown_from_having_into_where() now returns an error status, and the query errors out if the pushdown fails after it may have modified HAVING. Based on a contribution by Omar Gamal (PR #4815). Co-authored-by: OmarGamal10 <[email protected]> |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Aleksey Midenkov
midenok@gmail.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| MDEV-39306 Comments on update_virtual_fields() modes | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Sergei Petrunia
sergey@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-35318 Assertion `tl->jtbm_subselect' failed in JOIN::calc_allowed_top_level_tables Alternative, more general fix, Variant 2. The problem was as follows: Suppose we are running a PS/SP statement and we get an error while doing optimization that is done once per statement life. This may leave the statement data structures in an undefined state, where it is not safe to execute it again. The fix: introduce LEX::needs_reprepare and set it in such cases. Make PS and SP runtime check it and re-prepare the statement before executing it again. We do not use Reprepare_observer, because it turns out it is tightly tied to watching versions of statement's objects. For example, it must not be used when running the statement for the first time, exactly when the once-per-statement-lifetime optimizations are done. (cherry picked from commit 0e21ff8ca47ab637564b4c120322215caa70835d) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Aleksey Midenkov
midenok@gmail.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-40821 Wrong result after DELETE HISTORY or PORTION OF (10.11) The parser assigned versioning conditions of DELETE HISTORY ... BEFORE SYSTEM_TIME and period conditions of DELETE ... FOR PORTION OF to the table pointed by last_table(). When the BEFORE SYSTEM_TIME or FOR PORTION OF expression references another table (e.g. via a subquery or a sequence function), last_table() is already switched to that table, and the DELETE target gets no conditions. DELETE HISTORY then deletes current rows permanently instead of history, keeps the history it had to purge, and is checked for DELETE privilege instead of DELETE HISTORY. DELETE HISTORY from a non-versioned table is not rejected with ER_VERS_NOT_VERSIONED. DELETE ... FOR PORTION OF deletes all rows of the table, ignoring the period. The fix assigns the conditions to the TABLE_LIST returned by delete_single_table, i.e. the DELETE target itself, regardless of tables added later in the statement. DBUG_ASSERT in TABLE::vers_switch_partition() is removed. It checked delete_history on last_table() and assumed no other table is opened for write by DELETE HISTORY, which is false for the underlying table of a view or a table locked by SELECT ... FOR UPDATE in the history point. The DELETE HISTORY target is already skipped there by its own delete_history check. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Oleksandr Byelkin
sanja@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Merge branch '10.11' into 11.4 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Sergei Petrunia
sergey@mariadb.com |
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MDEV-36080: Assertion on 2nd PS execution with error and Array Binding The fix for MDEV-35318 has introduced LEX::needs_reprepare and logic in Prepared_statement::execute_loop() and sp_lex_keeper:: validate_lex_and_exec_core() to re-prepare the statement if it has hit an error when doing once-per-statement-life optimizations. But there is also third code path: PS with Array Binding is handled in Prepared_statement::execute_bulk_loop(). Add handling there as well. (cherry picked from commit 33e0796e7a154e02a5e53c55cefc5d6feb4f5e6d) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||