mariadb-binlog --verify-binlog-checksum --force-read fixes - #5519
Open
ParadoxV5 wants to merge 2870 commits into
Open
mariadb-binlog --verify-binlog-checksum --force-read fixes#5519ParadoxV5 wants to merge 2870 commits into
mariadb-binlog --verify-binlog-checksum --force-read fixes#5519ParadoxV5 wants to merge 2870 commits into
Conversation
Problem: When `$HOME` is set to `~/` (or any string starting with `~/`), the `home_dir` is initialized to that value. When `test_if_hard_path` is called on a path starting with `~/`, it replaces the `~/` prefix by recursively calling `test_if_hard_path(home_dir)` leading to infinite recursion and a crash. Fix: Add a check in `test_if_hard_path` to see if `home_dir` itself begins with `~/`. If it does, skip the recursive call to prevent the infinite loop.
json_get_path_start() set p->last_step to p->steps - 1, creating a pointer before the beginning of the steps[] array. This is undefined behavior flagged by UBSAN as "index -1 out of bounds for type json_path_step_t[32]". Use NULL as the sentinel value instead, and check for NULL in json_get_path_next() rather than comparing against p->steps. Signed-off-by: Varun Deep Saini <varun.23bcs10048@ms.sst.scaler.com> Signed-off-by: Varun Deep Saini <deepsainivarun@gmail.com>
Similar to ER_LOCK_DEADLOCK and ER_LOCK_WAIT_TIMEOUT, let the ER_CHECKREAD message suggest that the transaction needs to be restarted. When this error is reported by InnoDB (only if innodb_snapshot_isolation=ON), the transaction will be rolled back. Reviewed by: Sergei Golubchik
Added --galera-info parameter for mysqldump tool and this will add SET GLOBAL wsrep_start_position line at the end of the dump. This line is based on added wsrep status variable wsrep-checkpoint-position. Added also status variable wsrep-se-checkpoint.
…d Timestamps Row-based Replication did not validate serialized timestamps, which allows (pre-11.5) slaves to accept “negative” timestamps (between the Year 2038 limit and the 4-byte limit) via replication. In particular, a completely valid source of those timestamps is 11.5.1+ masters, where MDEV-32188 has increased the upper limit of timestamps to Year 2106 by utilizing this previously invalid range. This commit fills in this pre-processing: swap the Year 2106 max with the Year 2038 max, or throw an “Incorrect timestamp value” error for the others. Reviewed-by: Brandon Nesterenko <brandon.nesterenko@mariadb.com>
Update prepare_linux_info() to use /etc/os-release (PRETTY_NAME) as the primary source for OS detection. Retain fallback support for /etc/lsb-release and /etc/*-release for older systems. Add MTR regression test feedback_os_release. Signed-off-by: Anway Durge <124391429+itzanway@users.noreply.github.com>
…/NVL2 Item_func_ifnull and Item_func_case_abbreviation2 did not propagate collation errors when used inside DEFAULT expressions, causing a diagnostics area assertion instead of returning ER_CANT_AGGREGATE_2COLLATIONS. Test cases added for IFNULL, IF, and NVL2 in mysql-test/main/create.test. Reviewed by: Alexander Barkov Reviewed by: Joro Kodinov
Function calls in INTERVAL expression of DDL have little sense. SETVAL() fails because sequences require opened tables and vers_set_interval() is called at earlier stage. The fix throws ER_SUBQUERIES_NOT_SUPPORTED for sequence functions SETVAL(), NEXTVAL(), LASTVAL() when the context does not allow subselect (determined by clause_that_disallows_subselect).
Fix formatting inconsistencies in CONTRIBUTING.md: - Standardize header underlines to use 3 dashes consistently - Remove double spaces before links - Add missing space after period on line 22 - Update http://mariadb.meetup.com/ to https:// for security These changes improve document readability and follow markdown best practices.
Until MDEV-32188 on 11.5, both `my_time_t` and the literal behind the `UINT_MAX32` macro are `signed long`. But on platforms whose `long` is 32-bit, the value of `UINT_MAX32` exceeds the range of `signed long`, and so the macro instead has the next closest data type, `unsigned long`.
Problem:for example SELECT.1 treated as identifier instead of keyword + 0.1
from starting identifiers after dot
my_realpath() uses my_load_path() as a fallback. my_load_path() replaces empty string with a current directory. But my_realpath() didn't do it itself so the result was inconsistent: empty string was replaced with a current directory, but if the current directory was symlinked, symlinks were not resolved (as they were for any other, non-empty, path, including "."). Fix my_realpath() to treat empty string consisently with all other paths - replace with a current dir and resolve symlinks too.
The data in MEMORY tables is temporary and is lost when the server restarts. Thus, it is well-intentioned to record TRUNCATE statements to the binary log when these tables are rediscovered empty. However, as entries with no explicit user query associated (especially the lack of SHUTDOWN on crashes), those unaware of this mechanism can find them unexpected, not to mention their significance downstream in replication. This commit adds a comment to these automatically generated TRUNCATE entries to briefly self-describe their source and purpose. As a part of the generated query, this comment is visible together with the TRUNCATE itself in SHOW BINLOG EVENTS and `mariadb-binlog`, while maintaining seamlessness in replication. There are no other changes in behaviour or storage engine API. Reviewed-by: Andrei Elkin <andrei.elkin@mariadb.com>
The data in MEMORY tables is temporary and is lost when the server restarts. Thus, when these tables are rediscovered empty, it’s well-intentioned to record TRUNCATE statements to the binary log, complete with an increment to the `@@gtid_binlog_pos`. However, those unaware of this mechanism may not expect this increment and its sign of replication divergence, namely in `@@gtid_strict_mode`. This commit adds a binary log warning when such a table is found `implicit_emptied`. Since general uses of memory tables may already expect this effect, to avoid unnecessary verbosity, this warning only emits from `@@read_only` servers with CHANGE MASTER configured. `@@read_only` indicates that the server should not receive changes; for a slave, it means it only expects replication to binlog changes with GTID. Reviewed-by: Brandon Nesterenko <brandon.nesterenko@mariadb.com>
Fix HeidiSQL download URL HeidiSQL is now released on github, fix the portable ZIP URL to point to new download location HeidiSQL - prevent stale download by providing expected hash
MDEV-29804: Query_log_event::pack_info() was displaying inverted values for foreign_key_checks, check_constraint_checks and unique_checks flags in SHOW BINLOG EVENTS. MDEV-32447: check_constraint_checks was not included in OPTIONS_WRITTEN_TO_BINLOG, causing replication to break when check_constraint_checks=OFF was used in non-ROW binlog formats. Reviewed-by: Brandon Nesterenko <brandon.nesterenko@mariadb.com> Reviewed-by: Georgi Kodinov <joro@mariadb.org>
`DBUG_EXECUTE_IF` is a macro that uses
the infamous `do {…} while(0)` “idiom”.
This detail causes the `break` in the code block to terminate the
`while(0)` behind the macro instead of the `for (;;)` outside.
Consequently, this fault simulation does not terminate the normal flow,
which in turn overwrites the simulated fault with a non-fault outcome.
Since this fault simulation is the first step of the loop,
this commit fixes the fault injection by moving it before the loop.
due to argument due to hardcoded mariadb.service. Fixes: 649216e
…lumns Problem: ======== A single InnoDB purge worker thread can process undo logs from different tables within the same batch. But get_purge_table(), open_purge_table() incorrectly assumes that a 1:1 relationship between a purge worker thread and a table within a single batch. Based on this wrong assumtion, InnoDB attempts to reuse TABLE objects cached in thd->open_tables for virtual column computation. 1) Purge worker opens Table A and caches the TABLE pointer in thd->open_tables. 2) Same purge worker moves to Table B in the same batch, get_purge_table() retrieves the cached pointer for Table A instead of opening Table B. 3) Because innobase::open() is ignored for Table B, the virtual column template is never initialized. 4) virtual column computation for Table B aborts the server Solution: ======== - Introduced purge_table class which has the following purge_table: Stores either TABLE* (for tables with indexed virtual columns) or MDL_ticket* (for tables without) in a single union using LSB as a flag. For tables with indexed virtual columns: opens TABLE*, accesses MDL_ticket* via TABLE->mdl_ticket For tables without indexed virtual columns: stores only MDL_ticket*. trx_purge_attach_undo_recs(): Coordinator opens both dict_table_t* and TABLE* with proper MDL protection. Workers access cached table pointers from purge_node_t->tables without opening their own handles purge_sys.coordinator_thd: Distinguish coordinator from workers in cleanup logic. Skip innobase_reset_background_thd() for coordinator thread to prevent premature table closure during batch processing. Workers still call cleanup to release their thread-local resources trx_purge_close_tables(): Rewrite for purge coordinator thread 1) Close all dict_table_t* objects first 2) Call close_thread_tables() once for all TABLE* objects 3) Release MDL tickets last, after tables are closed Added table->lock_mutex protection when reading (or) writing vc_templ->mysql_table and mysql_table_query_id. Clear cached TABLE* pointers before closing tables to prevent stale pointer access Declared open_purge_table() and close_thread_tables() in trx0purge.cc Declared reset_thd() in row0purge.cc and dict0stats_bg.cc. Removed innobase_reset_background_thd()
…lumns Problem: ======== Purge threads computing virtual columns could crash due to: 1. Stale TABLE* pointers when tables are flushed/rebuilt during purge 2. open_purge_table() called close_thread_tables() on failure, making MDL tickets invalid before purge could release them 3. Purge coordinator opened TABLE* but workers accessed it with wrong TABLE->in_use 4. No retry mechanism when open_purge_table() failed due to concurrent FLUSH TABLES, BACKUP STAGE, or ALTER TABLE operations Solution: ======== 1. Removed close_thread_tables() from open_purge_table(). Purge coordinator thread should close explicitly in close_and_reopen() 2. Added retry logic: when open_purge_table() returns NULL due to table flush/rebuild, set must_wait() flag and retry in close_and_reopen() 3. Update close_and_reopen() with purge_table parameter to close the failed table. Pass it to trx_purge_close_tables() for proper cleanup 4. Properly set and reset TABLE::in_use during purge operations: - Set to coordinator_thd in row_purge_parse_undo_rec() when opening - Reset in trx_purge_close_table() when closing 5. The auto_increment initialization now happens unconditionally for purge threads , ensuring the auto_increment counter is always properly initialized when purge opens tables with virtual columns
originally (MDEV-23570) the idea was to make it TRUE and deprecate. It cannot be deprecated when it's FALSE, but TRUE breaks mariabackup.aria_backup where a table is altered from Aria to InnoDB during a backup, so both t.MAD/t.MAI and t.ibd gets into a backup. This is MDEV-38866, when it's fixed, keep_files_on_create can be enabled by default and deprecated at last.
Add support for CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA in COM_CHANGE_USER packet parsing, allowing passwords >= 251 bytes. Changes: - Server: parse_com_change_user_packet() now handles LENENC-encoded password length when CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA is set - Server: fix db pointer calculation for old protocol without CLIENT_SECURE_CONNECTION (need +1 to skip null terminator) - Add regression test for COM_CHANGE_USER with long passwords Note: This fix requires a corresponding client-side fix in libmariadb's send_change_user_packet() to send LENENC-encoded passwords.
* update to the fixed libmariadb * update test to match, remove useless INSTALL PLUGIN * address remaining review comments
make sure P_S.{global|session}_status and I_S.feedback plugin table
have a column of the same width as I_S.global_status.
Otherwise long status strings (e.g. Ssl_cipher_list) won't fit
and trigger a data truncation warning (an error in the strict mode)
Item_func_quote is not a null-rejecting function
disable main.show_all_plugins if ASAN and RocksDB. RocksDB has STB_GNU_UNIQUE symbols, so won't be unloaded on dlclose(). Presumably some destructors aren't called, and LSAN doesn't like it.
…rsing Make sure null terminator byte that is added at the end of header is within boundaries of 'hdr' array. This patch is based on #4881 by Uwez Khan
… "-u root" option rewrite mariadb-backup "early" option parsing to use my_getopt + proper handling of values separated from the option by a space (not =) + case insensitive and -/_ insensitive comparison - multiple --defaults-group don't work - multiple --login-path don't work - --incremental-dir overwrites --target-dir, not "whatever comes first"
This variable is unused.
* it's called ROOT_FLAG_VMEM * it does not imply any protection, ROOT_FLAG_MPROTECT was a misnomer * it means that the memory is allocated using my_virtual_mem_commit, not my_malloc, so not on heap * memory allocated this way can be protected with my_virtual_mem_protect() * thus root using ROOT_FLAG_VMEM can be protected with protect_root() Assisted-By: Claude:claude-5-sonnet
user_var_entry objects and their names have a connection lifetime, they exist until the connection ends (or is reset), and then they're all deleted at once. This is exactly the use case for MEM_ROOT, let's store them there. Additionally, let's set MY_ROOT_USE_VMEM flag to keep this memroot off the general heap where user_var_entry values are stored and where heap buffer overflows can happen. The latter makes memory allocations for the MEM_ROOT about 10x more expensive, so let's always start with an empty memroot (= zero overhead if no user variables are used) and on THD cleanup let's retain one memroot block (= zero overhead if the next connection takes THD from the cache and uses user variables up to one block size). Assisted-By: Claude:claude-4.8-opus
Protect all READ_ONLY sysvars from run-time changes. Put them into a separate section and use my_virtual_mem_protect() to make this section read-only before the server starts accepting connections. Verify that they're all protected in the sys_var constructor. One exception: opt_noacl (--skip-grant-tables) can be changed from 1 to 0 on FLUSH PRIVILEGES. Let's briefly drop the protection for this 1->0 change. It can be needed only once in a server lifetime and only if it was started with --skip-grant-tables On shutdown the protection is removed, making variables writable again because shutdown resets some of them during the cleanup Assisted-By: Claude:claude-4.8-opus
Store all READ_ONLY sysvar values in the read_only_root Even though READ_ONLY sysvars are protected, for string variables it usually means that the pointer cannot be changed. The value it points to - the string itself - still can be. Let's store all values of string READ_ONLY sysvars in the read_only_root. sysvars that point directly into argv are copied to read_only_root. sysvars that have their values calculated and allocated now must be explicitly marked with PREALLOCATED to let it know they have to be free()-d. Assisted-By: Claude:claude-4.8-opus
The byteorder field could contain an invalid value (> 1) on a GIS multi_point object where there byteorder was on any of the inner points. This can occur with any of the GIS "*FromWKB" functions that contained a multipoint object. This result in a invalid object being accepted and also potentially trigger undefined behaviour in the processing of the object.
Problem was that wsrep_log_state allocated buffer for String object, but did not set current length. In wsrep_get_state wsrep transaction state values was appended to this object but it current length was same as maximum length allocated leading to fact that nothing happened. Fixed by setting String object current length to 0 as it does not yet contain anything and fixed actual WSREP_DEBUG format. Removed debug only test case from galera_bf_kill because same test is on galera_bf_kill_debug test case. This allows following (1) galera_bf_kill test case can be run on both release and debug builds with same result file (2) galera_bf_kill_debug is run on debug only because it requires debug sync
When equality propagation (build_equal_items()) merges an equality that contains a subquery, such as "t1.a = (SELECT ...)", with an outer join's ON equality, it can inject a reference to that subquery into the ON expression. If the join columns have compatible types the subquery ends up as the constant of a multiple equality (which Item::walk() skips); if they differ (e.g. BIGINT vs INT) the field cannot be merged and the subquery is substituted in as a plain "tbl.col = (SELECT ...)" argument. In the latter case, if that outer join is removed by table elimination, mark_as_eliminated() walks the ON expression and flags the shared Item_subselect as eliminated. The subquery, however, still lives in another part of the query and has to be executed, tripping DBUG_ASSERT(!eliminated) in Item_subselect::exec() (and, in release builds, disabling the subquery cache and hiding it from EXPLAIN). The surviving reference can be: - a WHERE/HAVING/select-list/ORDER/GROUP expression (subquery written there and pushed down into the eliminated ON), or - the ON expression of an outer join that was not eliminated (subquery written in a surviving outer ON and pushed down into an eliminated inner one). Fix: after table elimination, walk the expressions that survive into execution (WHERE, HAVING, select list, ORDER/GROUP BY and the ON expressions of outer joins that were not eliminated) and clear the "eliminated" flag on any subquery still reachable from them. Because a subquery can also be the constant of a multiple equality, and Item::walk() does not visit an Item_equal's constant, Item_equal gets an unmark_as_eliminated_processor() override that descends into its constant explicitly. Assisted by Claude Opus
There's no good reason why undefined behaviour is acceptable in our codebase let alone having a test that triggers this. The thread_stack_basic test because of compulation has a different stack size under UBSAN. With replace_results we can include all values of the default stack size in this test. plugins.multiauth was added in 031f117 before CONC-730 and MDEV-31379 corrected the ref10 implementaiton.
Across a range of JSON functions taking a path argument there are SQL expressions that dont' have a character set. If these expressions don't have a character set fall back to the character set of the argument of the json function that represent the document being operated on. If this doesn't have a character set fall back to my_charset_utf8mb4_bin. This covers the 11.4 JSON_KEY_VALUE function also as it reuses the Json_path_extractor::extract method. Add nonnull and warn_unused_result to the json path functions to facilitate compiler and UBSAN catching of the problem early. As null values of s_p are incompatible with report_path_error, jump directly to a null return which is consistent with the defination of the JSON sql funciton.
never use item->null_value before this item is evaluated followup for 14c16e0
valgrind doesn't like it when a process writes to r/o memory and complains "Bad permissions for mapped region". It's not memcheck, but valgrind core error, cannot be suppressed.
The "is it my own thread" check compared the login user name (Security_context::user) and ignored the host, so u1@localhost could see and kill threads of u1@'127.0.0.1'. Compare the authenticated account instead: * all comparisons are done in sctx->is_priv_user() now * change user_matches() to priv_user_matches(), which uses is_priv_user() * use it in KILL, KILL USER, SHOW PROCESSLIST, I_S.PROCESSLIST, COM_PROCESS_INFO and SHOW EXPLAIN/ANALYZE FOR. * all the remaining places use is_priv_user() directly instead of doing strcmp: SHOW GRANTS, SHOW CREATE PROCEDURE, I_S.VIEWS, the DEFINER clause, optimizer trace and change_security_context(). Assisted-by: Claude:claude-5-opus
…risk to crash database Revert the fix 6ce0682 and implement deduplication differently - we want an array here to return groups in the order of appearence.
don't convert ulonglong max_mem_used to uint32 before the comparison
Let us remove a number of unused variables to suppress -Wunused-but-set-global and other warnings. test_thread(): Instead of incrementing a global counter in a race condition prone fashion, invoke MY_RELAX_CPU() in order to spend some time.
…EFORE INSERT trigger changes its base column On the LOAD DATA path the base columns are filled directly from the input file and fill_record_n_invoke_before_triggers() is then called with an empty field list (there is no SET clause). After the BEFORE INSERT trigger changed a base column, the stored generated columns were not recomputed, so they kept the value derived from the pre-trigger input (e.g. g=24 instead of 40 for g=v*2 with v set to 20 by the trigger). A regular INSERT was unaffected. The recompute was guarded by "fields.elements". That condition is a leftover from the original computed-columns implementation (f7a75b9), where fill_record_n_invoke_before_triggers() had no TABLE* argument and had to reverse-derive the table from the first item of the field list: if (fields.elements) { fld= (Item_field*)f++; item_field= fld->field_for_view_update(); table= item_field->field->table; ... } With an empty field list there was no way to obtain the table, so the recompute was silently skipped. Since bc4a456 (MDEV-452) the function receives TABLE* explicitly, which made the whole derivation dead code (as the in-place DBUG_ASSERT(table == item_field->field->table) confirmed). Recompute the virtual fields unconditionally on table->vfield, the same way the Field** overload of fill_record_n_invoke_before_triggers() already does.
In chain replication (1->2->3), syncing only server_3 after save_master_gtid on server_1 does not guarantee server_2 has committed, because server_2's binlog dump thread can send events to server_3 before commit_ordered() completes on server_2. Fix affected rpl tests by syncing server_2 before server_3, and update result files accordingly. 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.
When an uncommitted transaction inserts rows into a table and another statement locks rows in the same table (SELECT ... FOR UPDATE) while computing a MIN or MAX, then: 1. In a Debug build, the server aborts on an assertion 2. In a Release build, the server returns wrong results These errors occur because, while reading a group of rows for computing a MAX, the transaction timeout error was swallowed. Under the scenario described above and captured in the new test at this commit, QUICK_GROUP_MIN_MAX_SELECT::next_max() emits a lock timeout error during QUICK_GROUP_MIN_MAX_SELECT::get_next() but the error was suppressed if we computed a MIN. The InnoDB storage engine has an unwritten convention that after it has returned a fatal error (which is any error except HA_ERR_END_OF_FILE or HA_ERR_KEY_NOT_FOUND), then the SQL layer should not try to make any further reads. This is because InnoDB might have rolled back the current transaction already. So in the case of an error, return immediately from QUICK_GROUP_MIN_MAX_SELECT::get_next().
This commit reörders code so the checksum is populated after `mariadb-binlog --force` generates `Unknown_log_event` substitutes. Previously, `mariadb-binlog --force` inconsistently omitted those checksums from the output even if the checksum is presumably usable. After merging to 11.4 (MDEV-31273), this commit will also fix « MDEV-40542 MSAN use-of-uninitialized-value on Unknown_log_event::read_checksum_alg », which was exposed by MDEV-31273’s removal of the base `Log_event::checksum_alg` field.
A checksum error in `mariadb-binlog --verify-binlog-checksum --force-read` previously resulted in both an error message and an Unknown event substitute, the latter of which failed an assertion in debug builds or became forgotten (memory leak) in non-debug (release) builds. Since `mariadb-binlog --force-read` outputs “Unknown event”s rather than errors in other invalid event cases, this commit removes the error status from this situation to match.
Member
|
I reviewed the below 3 commits. Looks ok to me.
You can view, comment on, or merge this pull request online at:
#5519
commit c246f4e (origin/MDEV-40542)
Author: ParadoxV5 ***@***.***>
Date: Sun Aug 9 18:29:31 2026 -0600
fixup MDEV-40674: `have_debug.inc`
commit f79eac5
Author: ParadoxV5 ***@***.***>
Date: Sun Aug 9 16:31:00 2026 -0600
MDEV-40544 Assertion fail / Memory leak in `mariadb-binlog --force-read`
commit c440a13
Author: ParadoxV5 ***@***.***>
Date: Fri Aug 7 20:43:51 2026 -0600
MDEV-40674 Include the checksum for non-corrupted Unknown events
Reviewed-by: Kristian Nielsen ***@***.***>
|
Contributor
Author
|
TODO: rebase prior PRs in the stack. nothing to see here~ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
MDEV-40674 Include the checksum for non-corrupted Unknown events
This commit reörders code so the checksum is populated after
mariadb-binlog --forcegeneratesUnknown_log_eventsubstitutes.Previously,
mariadb-binlog --forceinconsistently omitted those checksums from the output even if the checksum is presumably usable.After merging to 11.4 (MDEV-31273), this commit will also fix «MDEV-40542 MSAN use-of-uninitialized-value on Unknown_log_event::read_checksum_alg», which was exposed by MDEV-31273’s removal of the base
Log_event::checksum_algfield.MDEV-40544 Assertion fail / Memory leak in mariadb-binlog --force-read
(needed this to test MDEV-40674’s checksum failure case)
A checksum error in
mariadb-binlog --verify-binlog-checksum --force-readpreviously resulted in both an error message and an Unknown event substitute, the latter of which failed an assertion in debug builds or became forgotten (memory leak) in non-debug (release) builds.Since
mariadb-binlog --force-readoutputs “Unknown event”s rather than errors in other invalid event cases, this commit removes the error status from this situation to match.