Skip to content

Manifest merge local public - #826

Open
surendarchandra wants to merge 2 commits into
mysql:trunkfrom
surendarchandra:manifest-merge-local-public
Open

surendarchandra wants to merge 2 commits into
mysql:trunkfrom
surendarchandra:manifest-merge-local-public

Conversation

@surendarchandra

@surendarchandra surendarchandra commented Oct 7, 2026 •

Copy link
Copy Markdown

What does this change do?

Fixes #827

Stacked PR: this branch is built on #823 ("MTR: preserve a pre-existing component manifest"), and its first commit is that fix. Please review #823 first and this PR after it; only the second commit, "Components: support merge_local_manifest in the global manifest", is new here. Once #823 merges, this branch will be rebased so that only that commit remains.

This change adds a boolean manifest key, merge_local_manifest. When it is true in the global manifest, the global components are loaded first and the local manifest's components are appended after them.

Behaviour:

  • merge_local_manifest defaults to false; manifests that do not use it, including those using read_local_manifest, behave exactly as before.
  • Merged lists are de-duplicated (a URN in both manifests is loaded once, at its global position) and empty tokens such as ,, are ignored. A local manifest that resolves to the global file is not merged into itself.
  • A present local manifest whose components cannot be read is a startup error, as for the global manifest; it is never silently dropped.
  • The component separator is now a single constexpr shared by the splitter and the merge helper, and manifest_version_1_0 is made inline to remove a header-defined-variable ODR violation.
  • MTR: when a preserved deployment manifest declares components, MTR writes a merge stub so those components stay loaded during the run and across restarts; otherwise it writes the plain redirect as before. The saved manifest is decoded as JSON (core JSON::PP) and only its top-level components string is used, as the server's reader does; a non-string value, or malformed JSON that mentions components, stops the run with the original kept.

Why is it needed?

read_local_manifest discards the global manifest reader before its components key is parsed, so the global and local component lists are mutually exclusive. A deployment cannot say "always load these components and let each instance add its own"; the global list must be duplicated in every local manifest, which is error-prone and prevents central management of components such as a keyring or audit log.

How was it tested?

  • Added/updated MTR tests under mysql-test/ (Perl unit test mysql-test/lib/t/manifest.t)
  • scripts/ci/mtr.sh passes locally
  • Ran the relevant full suite (name it): full mysql-test suite, this branch vs the unpatched base; component_keyring_file

Details:

  • gunit manifest-t (merged into merge_small_tests-t): 12 cases, 12/12 pass. Global + local composition, empty inputs, no trailing separator, cross-side and same-side duplicates, local contained in global, empty tokens, merge_local_manifest absent/present, and read_local_manifest unchanged.
  • mysql-test/lib/t/manifest.t: 213 Test::More assertions (185 from MTR: preserve a pre-existing component manifest #823), all pass. Adds merge-stub creation, fallback to the plain stub when there is no components key, an unparseable components value failing loudly with the original intact, crash recovery with the merge stub on disk, and JSON handling: a nested components key is ignored, an escaped key (\u0063omponents) is recognised, the value is re-encoded, and non-string values and malformed JSON are rejected.
  • component_keyring_file suite: all 38 tests successful (37 tests + shutdown report; 22 skipped: 21 need --big-test, 1 is Windows-only).
  • End-to-end: with bin/mysqld.my = {"components":"file://component_keyring_file"}, main.1st and component_keyring_file.encrypt_explicit --big-test pass with component_keyring_file loaded through the merge stub, and the manifest is unchanged afterwards (same inode, mode, size, mtime and checksum; no .mtr_saved/.mtr_stub left, only the persistent .mtr_lock). (--nowarnings was used because the globally loaded keyring has no keyring configuration in this setup and logs an initialisation error.)
  • Full mysql-test suite (Debug, --parallel=16 --retry=0, NDB skipped) on this branch vs the unpatched base: 6/7124 tests failing vs 8/7123 on the base. Five failures are common to both runs; the only failure seen just with the patch, perfschema.system_events_component (it loads its component with INSTALL COMPONENT, not through a manifest), passes 3/3 in isolation on both builds, and the three base-only failures passed with the patch. Zero patch-attributable regressions.

Contributor checklist

  • Code is formatted (scripts/ci/format.sh)
  • Commits are focused with descriptive messages

AI assistance

  • I did not use AI assistance for this contribution
  • I used AI assistance for this contribution

If AI assistance was used, describe the tool(s) and extent of use:

An AI coding assistant was used to draft parts of the implementation, tests and this description. All changes were reviewed, built and tested by the author, who takes responsibility for them.

Areas touched

components / manifest (include/manifest.h, sql/sql_component.cc), mysql-test harness (mysql-test/lib/My/Manifest.pm), tests (unittest/gunit/manifest-t.cc, unittest/gunit/CMakeLists.txt, mysql-test/lib/t/manifest.t).


This contribution is submitted under the corporate Oracle Contributor Agreement that covers the author's submissions to the MySQL project.

mysql-test-run.pl treats <basedir>/bin/mysqld.my as scratch space it
owns.  create_manifest_file truncates whatever is there (using a
two-arg open in write mode) and writes an MTR redirect manifest
{"read_local_manifest": true}; remove_manifest_file then unlinks
the file.  There is no backup and no restore, so a component manifest
that was present before the run is silently destroyed.

The global manifest is the only mechanism that loads components before
InnoDB starts (mysql.component is InnoDB-resident).  A distribution
or administrator who installs a manifest — for example to load a
keyring component for tablespace encryption at rest — loses it the
first time MTR runs against that basedir.

Design
------
Move the manifest aside (<path>.mtr_saved) before the first server
start; a same-directory rename preserves mode and ownership and needs
only directory write permission, so a read-only manifest is handled
without changing its permissions.  Restore it from the single END hook
inside its parent-only guard, which is armed before the manifest is
touched.  The restore is three-state idempotent:

  * pending  — backup exists, rename it back; clear state only on success.
  * done     — no-op (double-restore safe).
  * (unset)  — nothing was saved, nothing to do.

Additional safeguards:

  * A run holds an exclusive flock on <path>.mtr_lock from the backup
    until the restore, so a second run sharing the basedir dies before
    touching anything instead of renaming its stub over the backup.
    The lock file is created shared-mode (0666), as mtr_unique.pm does
    for build-thread ids, so sequential runs by different users of a
    group-writable directory can reuse it.
  * The restore is skipped only when --start-and-exit hands off after
    the worker reports that the servers are running (and every worker
    exited 0): the detached server keeps running and needs MTR's
    manifest in place, and the backup stays adjacent for the next MTR
    run to adopt and restore.  A --start-and-exit run whose setup or
    server start fails, or whose tests are all skipped, is restored like
    any other run.
  * An existing backup from a crashed prior run is adopted only when the
    file at the manifest path is MTR's own stub; if both hold different
    content, MTR dies before truncating anything rather than guessing
    which is current.
  * When MTR creates the stub itself it also drops a marker
    (<path>.mtr_stub).  At the next start, a file beside a marker is
    MTR-owned: a leftover stub is unlinked, and anything else (e.g. a
    manifest written by an interrupted test) is moved to <path>.mtr_leftover
    with a warning rather than being restored into the installation.
  * die() is called before truncating if the rename fails.
  * Every move is a same-directory rename(), never File::Copy::move: it
    is atomic and has no copy fallback, so a failed restore leaves the
    stub and the backup untouched for the END-block retry or for
    adoption by the next run.
  * Restore state is cleared only after the files are actually gone, so
    the END-block safety net can retry after a failed unlink or rename.
  * On exit the stub is unlinked only if it still holds MTR's own text; a
    stub that changed during the run (e.g. a keyring test that failed
    before its teardown) is quarantined to <path>.mtr_leftover with a
    warning, so the next run never adopts it as a user manifest.  If
    that rename fails the marker is kept and the next run quarantines it.
  * Restore never dies: an unreadable stub is reported and kept for a
    later retry.
  * A manifest that cannot be read is reported as such, never as a
    content conflict.

Abort handling: when MTR is interrupted or dies, its workers may still
be running a test that rewrites the manifest (keyring tests rename their
own backup over it at teardown).  The END hook therefore stops and reaps
the workers (stop_workers(), shared with the normal exit path) before it
restores the manifest.  On Windows mtr_error() leaves via POSIX::_exit,
which skips END blocks, so the parent installs a pre-exit hook in
mtr_report that stops the workers and restores the manifest first.

The lifecycle logic is extracted into My::Manifest so it can be tested
independently of the MTR harness.

Test coverage
-------------
mysql-test/lib/t/manifest.t exercises the module with Test::More,
following the existing lib/t convention; manifest.t runs under
main.mtr_unit_tests, with test descriptions and skip reasons normalized
so the recorded result does not depend on the platform or user.  Cases:

  * crashed-prior-run backup adoption
  * conflicting backup and newly installed manifest → refuse loudly
  * double-restore no-op
  * rename failure at create (die before truncate)
  * whitespace-path open
  * failed restore leaves stub and backup intact; retry restores, and a
    next run adopts the backup without a conflict
  * failed unlink keeps state for retry
  * leftover-stub (marker) detection
  * stub-text manifest without marker is preserved
  * content written after the stub was created is quarantined, not restored
  * interrupted keyring-style test leaves no permanent manifest
  * mode/inode preservation across backup and restore
  * manifest replaced during the run is quarantined at cleanup and not
    adopted by the next run
  * stub-write failure after the backup is restored by the END path
  * unreadable manifest yields an accurate error
  * unreadable stub at restore is kept and retried
  * a concurrent run is refused while the first holds the lock; a lock
    left by a dead run does not block the next one; the lock file is
    mode 0666 regardless of umask and an existing one is reused
  * --start-and-exit: a failed setup is restored; a hand-off leaves the
    stub and backup for the next run, which restores the original
  * root-unreliable chmod injection (SKIPped when running as root)
@surendarchandra
surendarchandra requested a review from a team October 7, 2026 08:49
@oracle-contributor-agreement oracle-contributor-agreement Bot added the OCA Verified All contributors have signed the Oracle Contributor Agreement. label Oct 7, 2026
@github-actions github-actions Bot added Review Requested Review requested from code owners Tests Changes touching test code or test data and removed Review Requested Review requested from code owners labels Oct 7, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found one correctness issue: the saved-manifest regex can select the wrong JSON field or miss an escaped key, silently changing the components loaded during MTR. See the inline comment for examples and a suggested fix.

Reviewed all 10 changed files statically. PR-provided code and tests were not executed, as required by this workflow; CI check data was unavailable.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • ab.chatgpt.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "ab.chatgpt.com"

See Network Configuration for more information.

Generated by Codex PR Review for #826 · codex · gpt60 · 187 AIC · ⌖ 23.8 AIC · ⊞ 13.9K
Comment /codex to run again

Comment thread mysql-test/lib/My/Manifest.pm Outdated
@github-actions github-actions Bot added Build Passed PR build passed MTR Passed MTR suite passed labels Oct 7, 2026
@surendarchandra
surendarchandra force-pushed the manifest-merge-local-public branch from 0fd6bbb to 3f8046c Compare October 7, 2026 16:12
@github-actions github-actions Bot removed Build Passed PR build passed MTR Passed MTR suite passed labels Oct 7, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found two correctness issues: unreadable local manifests are silently omitted during merging, and MTR's generated stub overrides existing read_local_manifest precedence. Both are detailed inline with suggested regression coverage.

Static review of the PR diff and affected callers only; PR code and tests were not executed. Existing review threads were unavailable under the access policy.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • ab.chatgpt.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "ab.chatgpt.com"

See Network Configuration for more information.

Generated by Codex PR Review for #826 · codex · gpt60 · 196.5 AIC · ⌖ 24 AIC · ⊞ 13.9K
Comment /codex to run again

Comment thread sql/sql_component.cc Outdated
Comment thread mysql-test/lib/My/Manifest.pm
inikep pushed a commit to Percona-Lab/percona-server-linear that referenced this pull request Oct 7, 2026
Blueprint
https://blueprints.launchpad.net/percona-server/+spec/audit-log-default-db

Add field `DB' for `MYSQL_AUDIT_GENERAL_STATUS' records.

==========================================

[mysql#786] Bug 1610242: Reading past the end of heap buffer on saving the default DB in audit p

Original title:
[mysql#786] Bug 1610242: Reading past the end of heap buffer on saving the default DB in audit plugin

memcpy in the call

memcpy(local->db, event_general->general_query, sizeof(local->db));

always copies `NAME_LEN' bytes, but the real length of the
`general_query' can be less than `NAME_LEN'

Fix is to copy `general_query_length' bytes.

==========================================

[#930] Bug 1613647: Sporadic audit_log_filter_users failures

Insert silent statements (which aren't are grepped away) before
connects to make sure the previous statement we which want to see in
the audit log actually gets there before the connect.

==========================================

[#941] Bug 1617833: audit_log_default_db failures

1. Insert silent statement after UNINSTALL PLUGIN to make sure that SHOW
   WARNINGS is logged before the statement from the next connection.

2. Insert silent statement before establishing the connection which does
   'INSTALL PLUGIN', make sure 'SELECT * FROM t' gets to the log.

3. Make reconnect in case of error optional for 'change_user' mysqltest
   command

==========================================

[#1682] Bug 1650294: Test main.audit_log_filter_users is unstable

The source of instability is the fact that event of creating new
connection and closing previous one are not synchronized. It makes
"Quit" record to appear after "Connect" one.

Fix is to replace `include/wait_until_disconnected.inc' which waits for
client connection to be closed with
`include/wait_until_count_sessions.inc' which waits for specific
`Threads_connected' value which is updated after
`MYSQL_AUDIT_NOTIFY_CONNECTION_DISCONNECT'.

==========================================

[#1762] Bug 1626559: Test `main.audit_log_default_db' is unstable

Sometimes "SHOW WARNINGS" appears in the audit log around UNINSTALL
PLUGIN / INSTALL PLUGIN. This is the warning which MySQL issue about
plugin being in use.

Normally warning should not make it to audit log because test case
truncates log after UNINSTALL PLUGIN. But sometimes mysql-test picks
this warning up after plugin has been reinstalled and it gets logged
into audit log.

This patch makes sure that test execution continues only when plugin
disappeared from the `mysql.plgins', which happens after `deinit' is
called and all plugin is fully shut down.

==========================================

[mysql#736] Allow to log only queries for specific DBs in audit log plugin

Blueprint:

[https://blueprints.launchpad.net/percona-server/+spec/audit-filer-db]

Add two global variables:

- `audit_log_include_databases' comma separated list of databases to
  include in audit logging
- `audit_log_exclude_databases' comma separated list of databases to
  exclude from audit logging

Allow escaped backticks in the `next_word' function. This change needs
to be backported to the 5.6.

Patch changes behaviour of user and database filters. User filter
becomes case sensitive for user name and case insensitive for host name.
Database filter becomes case insensitive.

[#931] Bug 1617828: audit_log_filter_db failures

The fix increases timeout for event shot wait to 10 minutes and adds
silent query at the end of the event.

============================================================

[mysql#826] Add filtering by `sql_command'

Blueprint:

https://blueprints.launchpad.net/percona-server/+spec/audit-filer-command

- add option `audit_log_include_command' to specify commands to log
- add option `audit_log_exclude_command' to specify commands to exclude
  from logging
- backport changes for `next_word' fixing the capture of default
  database with quoted backticks.
- backport case-sensitivity fix for account filters

==========================================

[#1381] Bug 1650321: Valgrind error on main.audit_log_filter_commands

Valgrind complained about `cmd' being used uninitialized. However, I
don't a path when it could happen, since the first command was to
initialize it unconditionally.

Still this error message pointed me to the fact that we don't need `cmd'
at all, we can simply use `name' and `length' provided as arguments.

==========================================

[#1444] Bug 1663251: ASan errors on main.audit_log_filter_commands

`my_hash_search' takes two arguments - key to search for and it's
length. When length is 0, `my_hash_search' considers that key has the
same length as hash length.

Since this behaviour may be relied on somewhere, the fix is to avoid
calling `my_hash_search' for empty strings.

==========================================

[#846] Bug 1614444: Assertion `local->stack.frames[local->stack.top].query == event_general->general_query.str' failed

It is a bug which can affects filtering by DB for triggers.

There is a trigger

    CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW SET @Aux=1;

and query

    INSERT INTO t1(c5,c6)VALUES (1,0);

Lets see which events are sent to the audit_log:

1. TABLE ACCESS event for "INSERT INTO t1(c5,c6)VALUES (1,0)"
2. STATUS event for "SET @Aux=1"
3. STATUS event for "INSERT INTO t1(c5,c6)VALUES (1,0)"

When (1) comes, plugin pushes "INSERT INTO t1(c5,c6)VALUES (1,0)" to
the top of the stack, so it can match it later with STATUS event.

When (2) comes, plugin is trying to match "SET @Aux=1" against the stack
top. But "SET @Aux=1" isn't on the stack since it doesn't access any
database. In debug mode we see the assertion failure. In the release
mode, "SET @Aux=1" will be attributed as accessing table "t1", which is
wrong.

The fix is to replace assert with if statement. Now the query the within
trigger which doesn't access any database will always be logged just
like any similar query executed outside of the trigger.

============================================================

[#1176] Bug 1641910: Trying to set audit_log_exclude_accounts crashes server

The root cause of this bug is that logic around filtering variables rely
heavily on the fact that CHECK and UPDATE functions are always called.
This is not true when variables passed via defaults file or set as
command line options.

The fix is add special handling for filtering variables on startup.

==========================================

[#1451] Bug 1666496: Server crashes on startup if plugin is unable to create file pointed by --audit_log_file

In order to expose this bug we need to set both
--audit-log-exclude-commands and --audit-log-file at start up.

Second one has to be incorrect, so that plugin would refuse to start
with error:

    mysqld: File './data-dir/mysql-audit.json' not found (Errcode: 2 - No such file or directory)
    2017-02-21T11:58:42.392280Z 0 [ERROR] Plugin audit_log reported: 'Cannot open file ./data-dir/mysql-audit.json.'
    2017-02-21T11:58:42.392350Z 0 [ERROR] Plugin audit_log reported: 'Error: No such file or directory'
    2017-02-21T11:58:42.392355Z 0 [ERROR] Plugin 'audit_log' init function returned error.
    2017-02-21T11:58:42.392360Z 0 [ERROR] Plugin 'audit_log' registration as a AUDIT failed.

The cause for the crash is common with bug 1641910. MEMALLOC'ed
variables are not properly initialized by server (UPDATE and CHECK
functions aren't invoked).

The fix is to make sure that initialization of MEMALLOC'ed variables is
the very first thing we do.

==========================================

[#2032] lp1716844: Escaping control characters in the audit log

Implemented escaping for the JSON output format, and updated the test suite.

The other output formats are left unchanged, as they do not have a well defined method for escaping these characters.
XML does support control characters in version 1.1, but most tools only understand 1.0, and our output is 1.0.

==========================================

[g5]PS-5363 (Merge MySQL 8.0.17): fixed audit_log.audit_log_default_db MTR test case

Similarly to what Oracle did in treir fix for Bug #29248047
"5.7 AUDIT PLUGIN DOES NOT LOG WHO UNINSTALLS THE AUDIT PLUGIN UNLIKE 5.6"
(commit mysql/mysql-server@6a893b8)
added '--source include/disconnect_connections.inc' to
'audit_log.audit_log_default_db' MTR test case after plugin uninstallation.
@github-actions github-actions Bot added the Build Passed PR build passed label Oct 7, 2026
inikep pushed a commit to Percona-Lab/percona-server-linear that referenced this pull request Oct 7, 2026
Blueprint
https://blueprints.launchpad.net/percona-server/+spec/audit-log-default-db

Add field `DB' for `MYSQL_AUDIT_GENERAL_STATUS' records.

==========================================

[mysql#786] Bug 1610242: Reading past the end of heap buffer on saving the default DB in audit p

Original title:
[mysql#786] Bug 1610242: Reading past the end of heap buffer on saving the default DB in audit plugin

memcpy in the call

memcpy(local->db, event_general->general_query, sizeof(local->db));

always copies `NAME_LEN' bytes, but the real length of the
`general_query' can be less than `NAME_LEN'

Fix is to copy `general_query_length' bytes.

==========================================

[#930] Bug 1613647: Sporadic audit_log_filter_users failures

Insert silent statements (which aren't are grepped away) before
connects to make sure the previous statement we which want to see in
the audit log actually gets there before the connect.

==========================================

[#941] Bug 1617833: audit_log_default_db failures

1. Insert silent statement after UNINSTALL PLUGIN to make sure that SHOW
   WARNINGS is logged before the statement from the next connection.

2. Insert silent statement before establishing the connection which does
   'INSTALL PLUGIN', make sure 'SELECT * FROM t' gets to the log.

3. Make reconnect in case of error optional for 'change_user' mysqltest
   command

==========================================

[#1682] Bug 1650294: Test main.audit_log_filter_users is unstable

The source of instability is the fact that event of creating new
connection and closing previous one are not synchronized. It makes
"Quit" record to appear after "Connect" one.

Fix is to replace `include/wait_until_disconnected.inc' which waits for
client connection to be closed with
`include/wait_until_count_sessions.inc' which waits for specific
`Threads_connected' value which is updated after
`MYSQL_AUDIT_NOTIFY_CONNECTION_DISCONNECT'.

==========================================

[#1762] Bug 1626559: Test `main.audit_log_default_db' is unstable

Sometimes "SHOW WARNINGS" appears in the audit log around UNINSTALL
PLUGIN / INSTALL PLUGIN. This is the warning which MySQL issue about
plugin being in use.

Normally warning should not make it to audit log because test case
truncates log after UNINSTALL PLUGIN. But sometimes mysql-test picks
this warning up after plugin has been reinstalled and it gets logged
into audit log.

This patch makes sure that test execution continues only when plugin
disappeared from the `mysql.plgins', which happens after `deinit' is
called and all plugin is fully shut down.

==========================================

[mysql#736] Allow to log only queries for specific DBs in audit log plugin

Blueprint:

[https://blueprints.launchpad.net/percona-server/+spec/audit-filer-db]

Add two global variables:

- `audit_log_include_databases' comma separated list of databases to
  include in audit logging
- `audit_log_exclude_databases' comma separated list of databases to
  exclude from audit logging

Allow escaped backticks in the `next_word' function. This change needs
to be backported to the 5.6.

Patch changes behaviour of user and database filters. User filter
becomes case sensitive for user name and case insensitive for host name.
Database filter becomes case insensitive.

[#931] Bug 1617828: audit_log_filter_db failures

The fix increases timeout for event shot wait to 10 minutes and adds
silent query at the end of the event.

============================================================

[mysql#826] Add filtering by `sql_command'

Blueprint:

https://blueprints.launchpad.net/percona-server/+spec/audit-filer-command

- add option `audit_log_include_command' to specify commands to log
- add option `audit_log_exclude_command' to specify commands to exclude
  from logging
- backport changes for `next_word' fixing the capture of default
  database with quoted backticks.
- backport case-sensitivity fix for account filters

==========================================

[#1381] Bug 1650321: Valgrind error on main.audit_log_filter_commands

Valgrind complained about `cmd' being used uninitialized. However, I
don't a path when it could happen, since the first command was to
initialize it unconditionally.

Still this error message pointed me to the fact that we don't need `cmd'
at all, we can simply use `name' and `length' provided as arguments.

==========================================

[#1444] Bug 1663251: ASan errors on main.audit_log_filter_commands

`my_hash_search' takes two arguments - key to search for and it's
length. When length is 0, `my_hash_search' considers that key has the
same length as hash length.

Since this behaviour may be relied on somewhere, the fix is to avoid
calling `my_hash_search' for empty strings.

==========================================

[#846] Bug 1614444: Assertion `local->stack.frames[local->stack.top].query == event_general->general_query.str' failed

It is a bug which can affects filtering by DB for triggers.

There is a trigger

    CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW SET @Aux=1;

and query

    INSERT INTO t1(c5,c6)VALUES (1,0);

Lets see which events are sent to the audit_log:

1. TABLE ACCESS event for "INSERT INTO t1(c5,c6)VALUES (1,0)"
2. STATUS event for "SET @Aux=1"
3. STATUS event for "INSERT INTO t1(c5,c6)VALUES (1,0)"

When (1) comes, plugin pushes "INSERT INTO t1(c5,c6)VALUES (1,0)" to
the top of the stack, so it can match it later with STATUS event.

When (2) comes, plugin is trying to match "SET @Aux=1" against the stack
top. But "SET @Aux=1" isn't on the stack since it doesn't access any
database. In debug mode we see the assertion failure. In the release
mode, "SET @Aux=1" will be attributed as accessing table "t1", which is
wrong.

The fix is to replace assert with if statement. Now the query the within
trigger which doesn't access any database will always be logged just
like any similar query executed outside of the trigger.

============================================================

[#1176] Bug 1641910: Trying to set audit_log_exclude_accounts crashes server

The root cause of this bug is that logic around filtering variables rely
heavily on the fact that CHECK and UPDATE functions are always called.
This is not true when variables passed via defaults file or set as
command line options.

The fix is add special handling for filtering variables on startup.

==========================================

[#1451] Bug 1666496: Server crashes on startup if plugin is unable to create file pointed by --audit_log_file

In order to expose this bug we need to set both
--audit-log-exclude-commands and --audit-log-file at start up.

Second one has to be incorrect, so that plugin would refuse to start
with error:

    mysqld: File './data-dir/mysql-audit.json' not found (Errcode: 2 - No such file or directory)
    2017-02-21T11:58:42.392280Z 0 [ERROR] Plugin audit_log reported: 'Cannot open file ./data-dir/mysql-audit.json.'
    2017-02-21T11:58:42.392350Z 0 [ERROR] Plugin audit_log reported: 'Error: No such file or directory'
    2017-02-21T11:58:42.392355Z 0 [ERROR] Plugin 'audit_log' init function returned error.
    2017-02-21T11:58:42.392360Z 0 [ERROR] Plugin 'audit_log' registration as a AUDIT failed.

The cause for the crash is common with bug 1641910. MEMALLOC'ed
variables are not properly initialized by server (UPDATE and CHECK
functions aren't invoked).

The fix is to make sure that initialization of MEMALLOC'ed variables is
the very first thing we do.

==========================================

[#2032] lp1716844: Escaping control characters in the audit log

Implemented escaping for the JSON output format, and updated the test suite.

The other output formats are left unchanged, as they do not have a well defined method for escaping these characters.
XML does support control characters in version 1.1, but most tools only understand 1.0, and our output is 1.0.

==========================================

[g5]PS-5363 (Merge MySQL 8.0.17): fixed audit_log.audit_log_default_db MTR test case

Similarly to what Oracle did in treir fix for Bug #29248047
"5.7 AUDIT PLUGIN DOES NOT LOG WHO UNINSTALLS THE AUDIT PLUGIN UNLIKE 5.6"
(commit mysql/mysql-server@6a893b8)
added '--source include/disconnect_connections.inc' to
'audit_log.audit_log_default_db' MTR test case after plugin uninstallation.
@surendarchandra
surendarchandra force-pushed the manifest-merge-local-public branch from 3f8046c to 76d61e5 Compare October 7, 2026 18:33
@github-actions github-actions Bot removed the Build Passed PR build passed label Oct 7, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found two correctness issues: merge-enabled startup skips deduplication when the local manifest is absent or zero bytes, and MTR's JSON conversion can silently change the selected components when keys repeat. Both findings include inline examples and suggested regression coverage.

Reviewed the changes and relevant callers without executing PR code or tests. Existing review threads were unavailable under the GitHub integrity policy, so duplicate-comment checking was limited.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • ab.chatgpt.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "ab.chatgpt.com"

See Network Configuration for more information.

Generated by Codex PR Review for #826 · codex · gpt60 · 239.5 AIC · ⌖ 24.2 AIC · ⊞ 13.9K
Comment /codex to run again

Comment thread sql/sql_component.cc Outdated
Comment thread mysql-test/lib/My/Manifest.pm
@surendarchandra
surendarchandra force-pushed the manifest-merge-local-public branch from 76d61e5 to 2198f6d Compare October 7, 2026 19:51

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the changes at 2198f6d3f7d59cfbe7057766fd2e9989de350cea. Found one correctness issue: merge mode silently drops a local manifest that cannot be opened, allowing startup with an incomplete component set. See the inline finding for the suggested fix and regression coverage.

Static review only; PR code and tests were not executed. Existing review threads were unavailable because the read tool's integrity policy blocked access.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • ab.chatgpt.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "ab.chatgpt.com"

See Network Configuration for more information.

Generated by Codex PR Review for #826 · codex · gpt60 · 170.2 AIC · ⌖ 24 AIC · ⊞ 13.9K
Comment /codex to run again

Comment thread include/manifest.h
read_local_manifest discards the global manifest reader before the
"components" key is parsed, so code that needs both the global and
local component lists has no way to obtain them from a single
reader — they are mutually exclusive.

A new boolean key, merge_local_manifest, makes the global reader
append the local manifest's components after the global ones.
Existing single-key manifests are unaffected: the key defaults to
false and the reader's behaviour is unchanged when it is absent.

The component separator is single-sourced as a constexpr consumed by
both the splitter (get_next_component) and an inline merge helper
(merge_component_lists), so there is exactly one representation of
the delimiter in the codebase.

Merged lists are de-duplicated and a local manifest resolving to
the global file is not merged into itself.  A local manifest that
cannot be opened is treated as absent, as Manifest_reader does
elsewhere; one that opens but has no readable "components" is a
startup error.
The merge step (merge_local_components) always passes the global list
through the de-duplicating merge, so a repeated global URN is loaded
once even when no local manifest exists or it is zero bytes.

The MTR consumer (My::Manifest) preserves the deployment's
components for the duration of the run, ensuring restarts see the
same list that was present at boot.  It decodes the saved manifest
with JSON::PP and takes only the top-level "components" string, as
the server's reader does.  A saved manifest whose read_local_manifest is
true keeps the plain redirect stub, because the server applies that
key before reading "components".  A saved manifest that repeats
"components" or read_local_manifest at the top level is refused:
JSON::PP keeps the last occurrence while the server's RapidJSON lookup
selects the first.

GUnit coverage (manifest-t.cc):
  * composition of global + local component lists
  * empty inputs (global-only, local-only, both empty)
  * no trailing separator in merged output
  * duplicate URN across global and local is kept once (global position)
  * local entirely contained in global yields global unchanged
  * duplicates within one side are also collapsed
  * empty tokens (',,') do not produce empty URNs
  * new-key default-false (merge_local_manifest absent)
  * read_local_manifest behaviour unchanged
  * merge step with an absent, zero-byte, populated or self-referencing
    local manifest de-duplicates the global list; a local manifest
    without "components" fails
  * POSIX fixture (tempfile cleanup) guarded for non-Windows

Tests (manifest.t):
  * crash recovery when the merge stub is on disk
  * nested "components" ignored; escaped key recognised; value
    re-encoded; non-string value and malformed JSON rejected
  * repeated top-level "components" / read_local_manifest rejected;
    nested or unrelated repeated keys accepted
@surendarchandra
surendarchandra force-pushed the manifest-merge-local-public branch from 2198f6d to f194c20 Compare October 7, 2026 21:09

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No high-confidence defects found in the reviewed changes. Reviewed global/local component merging, MTR manifest preservation and cleanup, and the added test coverage.

Validation was static only; PR code and tests were not executed. Existing review threads were unavailable under the GitHub read integrity policy.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • ab.chatgpt.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "ab.chatgpt.com"

See Network Configuration for more information.

Generated by Codex PR Review for #826 · codex · gpt60 · 210 AIC · ⌖ 23.6 AIC · ⊞ 13.9K
Comment /codex to run again

@github-actions github-actions Bot added the MTR Passed MTR suite passed label Oct 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

MTR Passed MTR suite passed OCA Verified All contributors have signed the Oracle Contributor Agreement. Tests Changes touching test code or test data

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Components: support merge_local_manifest in the global manifest

1 participant