Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
bd07307
docs: design MySQL Router plugin for ProxySQL 4.0
renecannao Aug 19, 2026
b7b9dd8
docs: plan MySQL Router plugin implementation
renecannao Aug 19, 2026
f2833c5
refactor(v4): remove legacy bootstrap from core
renecannao Aug 19, 2026
cf4d97e
fix(v4): preserve bootstrap init interface
renecannao Aug 19, 2026
baf33ee
feat(plugin): register named plugin CLI options
renecannao Aug 19, 2026
a96dd6e
test(plugin): cover executable plugin help
renecannao Aug 19, 2026
e6963de
test(plugin): isolate executable help fixture
renecannao Aug 19, 2026
4299e92
feat(plugin): add early action lifecycle phase
renecannao Aug 19, 2026
ed922f2
feat(plugin): add encrypted secret storage
renecannao Aug 19, 2026
34a8248
fix(plugin): harden secret storage errors
renecannao Aug 20, 2026
2b9430e
fix(plugin): hide secret test hooks
renecannao Aug 20, 2026
2d6e2ef
feat(plugin): gate listeners on runtime readiness
renecannao Aug 20, 2026
8a947a4
feat(plugin): publish scoped MySQL config generations
renecannao Aug 20, 2026
319a72f
fix(plugin): harden MySQL config publication
renecannao Aug 20, 2026
0ace3d9
fix: harden atomic MySQL config publication
renecannao Aug 20, 2026
68f3f35
fix: make Auth checksum locking exception-safe
renecannao Aug 20, 2026
7313864
test(plugin): lock Router chassis contract
renecannao Aug 20, 2026
d22ff66
test(plugin): strengthen Router chassis contract
renecannao Aug 20, 2026
5d6275c
fix(plugin): preserve exact managed user state
renecannao Aug 20, 2026
8c6c1ae
fix(plugin): discriminate exact user ownership
renecannao Aug 20, 2026
9147554
fix(admin): preserve plugin ownership schema
renecannao Aug 20, 2026
bab9572
fix(admin): reject stale ownership migrations
renecannao Aug 20, 2026
cc313ee
Merge remote-tracking branch 'origin/v3.0' into agent/mysql-router-pl…
renecannao Aug 30, 2026
be3744d
Merge remote-tracking branch 'origin/v3.0' into agent/mysql-router-pl…
renecannao Aug 30, 2026
dab8d32
test(ci): register Router chassis unit tests
renecannao Aug 30, 2026
bbc4a09
feat(query-rules): expose fast-forward action
renecannao Aug 31, 2026
7fd416b
feat(mysql): switch COM_QUERY sessions to fast-forward
renecannao Aug 31, 2026
282b587
fix(mysql): reject unsafe query-rule transitions
renecannao Aug 31, 2026
981826d
feat(mysql-router): scaffold the real Router plugin
renecannao Aug 31, 2026
e58ec58
feat(mysql-router): parse secure bootstrap options
renecannao Aug 31, 2026
b471eb6
feat(mysql-router): model metadata and GR health
renecannao Aug 31, 2026
3ae0a68
feat(mysql-router): bootstrap and register InnoDB Cluster
renecannao Aug 31, 2026
4b25833
feat(mysql-router): compile native Classic routing
renecannao Aug 31, 2026
d40fc59
feat(router): synchronize managed MySQL users
renecannao Aug 31, 2026
9fce431
feat(router): reconcile topology continuously
renecannao Aug 31, 2026
a8b3c74
Merge remote v3.0 into mysql-router-plugin
renecannao Sep 1, 2026
7b4db85
feat(mysql-router): validate real InnoDB Cluster routing
renecannao Aug 31, 2026
8598581
docs(mysql-router): design fast-forward rule publication
renecannao Sep 1, 2026
6208b33
docs(mysql-router): plan fast-forward rule publication
renecannao Sep 1, 2026
2aca69e
docs(router): align direct builds with v3 feature tiers
renecannao Sep 1, 2026
abb3fa7
feat(plugin): add versioned MySQL rule attributes service
renecannao Sep 1, 2026
ae25d06
feat(plugin): publish managed query-rule attributes atomically
renecannao Sep 1, 2026
fb57362
feat(mysql-router): enable fast-forward on direct Classic routes
renecannao Sep 1, 2026
89a9c27
docs(mysql-router): document ABI-9 Router operation
renecannao Sep 1, 2026
73f2638
fix(plugin): restore default-tier compilation
renecannao Sep 2, 2026
5c78404
fix(plugin): reject unsafe ownership collisions
renecannao Sep 2, 2026
759236f
fix(plugin): harden chassis discovery and services
renecannao Sep 2, 2026
e9ddff4
fix(plugin): harden manager publication boundaries
renecannao Sep 2, 2026
f1126f1
fix(mysql-router): validate metadata and health transitions
renecannao Sep 2, 2026
8772774
fix(mysql-router): make runtime publication consistent
renecannao Sep 2, 2026
2bfef7e
fix(mysql-router): harden bootstrap state transitions
renecannao Sep 2, 2026
de93600
fix(mysql-router): close runtime error boundaries
renecannao Sep 2, 2026
ca61e54
test(mysql-router): run the real plugin in InnoDB Cluster CI
renecannao Sep 2, 2026
bc1e25a
Merge remote v3.0 into MySQL Router plugin branch
renecannao Sep 2, 2026
55106ea
test(admin): scope bootstrap importer coverage
renecannao Sep 2, 2026
ff3e774
test(plugin): resolve Sonar reliability findings
renecannao Sep 2, 2026
c9ad778
test(admin): keep bootstrap test in unit manifest
renecannao Sep 2, 2026
675af4d
build(mysql-router): keep runtime staging writable
renecannao Sep 2, 2026
a76ffe3
build(mysql-router): secure runtime plugin staging
renecannao Sep 2, 2026
ce8f596
fix(mysql-router): keep listener gates open across user reconcile
renecannao Sep 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions .github/workflows/CI-mysql-router-ic-g1.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: CI-mysql-router-ic-g1
run-name: '${{ github.event.workflow_run && github.event.workflow_run.head_branch || github.ref_name }} ${{ github.workflow }} ${{ github.event.workflow_run && github.event.workflow_run.head_sha || github.sha }}'

on:
workflow_dispatch:
workflow_run:
workflows: [ CI-trigger ]
types: [ completed ]

concurrency:
group: ${{ github.workflow }}-${{ github.event.workflow_run && github.event.workflow_run.head_branch || github.ref_name }}
cancel-in-progress: true

jobs:
run:
if: ${{ github.event.workflow_run && github.event.workflow_run.conclusion == 'success' || ! github.event.workflow_run }}
# The shared ubuntu24 PROXYSQL40+GCOV handoff builds every chassis plugin.
# mysql_router stages its real .so in test/tap/tap/_runtime_libs so this
# group does not depend on the GenAI-only restore destination.
permissions: write-all # NOSONAR: required by and consistent with the shared CI caller contract.
uses: sysown/proxysql/.github/workflows/ci-ai-gcov.yml@GH-Actions # NOSONAR: repository-owned integration branch.
secrets: inherit # NOSONAR: the shared CI workflow selects the credentials needed by its infrastructure.
with:
trigger: ${{ toJson(github) }}
tap_group: mysql-router-ic-g1
infra_id: ci-mysql-router-ic-g1
14 changes: 14 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ build_src_legacy: build_lib_legacy
cd src && OPTZ="${O2} -ggdb" CC=${CC} CXX=${CXX} ${MAKE}
$(if $(filter 1,$(PROXYSQL40)),cd plugins/mysqlx && OPTZ="${O2} -ggdb" PROXYSQL40=$(PROXYSQL40) PROXYSQL31=$(PROXYSQL31) PROXYSQLFFTO=$(PROXYSQLFFTO) PROXYSQLTSDB=$(PROXYSQLTSDB) CC=${CC} CXX=${CXX} ${MAKE},@echo "[skip] mysqlx plugin (PROXYSQL40 not set)")
$(if $(filter 1,$(PROXYSQL40)),cd plugins/genai && OPTZ="${O2} -ggdb" PROXYSQL40=$(PROXYSQL40) PROXYSQL31=$(PROXYSQL31) PROXYSQLFFTO=$(PROXYSQLFFTO) PROXYSQLTSDB=$(PROXYSQLTSDB) CC=${CC} CXX=${CXX} ${MAKE},@echo "[skip] genai plugin (PROXYSQL40 not set)")
$(if $(filter 1,$(PROXYSQL40)),cd plugins/mysql_router && OPTZ="${O2} -ggdb" PROXYSQL40=$(PROXYSQL40) PROXYSQL31=$(PROXYSQL31) PROXYSQLFFTO=$(PROXYSQLFFTO) PROXYSQLTSDB=$(PROXYSQLTSDB) CC=${CC} CXX=${CXX} ${MAKE},@echo "[skip] mysql_router plugin (PROXYSQL40 not set)")

.PHONY: build_deps_debug_legacy
build_deps_debug_legacy:
Expand All @@ -293,6 +294,7 @@ build_src_debug_legacy: build_lib_debug_legacy
cd src && OPTZ="${O0} -ggdb -DDEBUG" CC=${CC} CXX=${CXX} ${MAKE}
$(if $(filter 1,$(PROXYSQL40)),cd plugins/mysqlx && OPTZ="${O0} -ggdb -DDEBUG" PROXYSQL40=$(PROXYSQL40) PROXYSQL31=$(PROXYSQL31) PROXYSQLFFTO=$(PROXYSQLFFTO) PROXYSQLTSDB=$(PROXYSQLTSDB) CC=${CC} CXX=${CXX} ${MAKE},@echo "[skip] mysqlx plugin (PROXYSQL40 not set)")
$(if $(filter 1,$(PROXYSQL40)),cd plugins/genai && OPTZ="${O0} -ggdb -DDEBUG" PROXYSQL40=$(PROXYSQL40) PROXYSQL31=$(PROXYSQL31) PROXYSQLFFTO=$(PROXYSQLFFTO) PROXYSQLTSDB=$(PROXYSQLTSDB) CC=${CC} CXX=${CXX} ${MAKE},@echo "[skip] genai plugin (PROXYSQL40 not set)")
$(if $(filter 1,$(PROXYSQL40)),cd plugins/mysql_router && OPTZ="${O0} -ggdb -DDEBUG" PROXYSQL40=$(PROXYSQL40) PROXYSQL31=$(PROXYSQL31) PROXYSQLFFTO=$(PROXYSQLFFTO) PROXYSQLTSDB=$(PROXYSQLTSDB) CC=${CC} CXX=${CXX} ${MAKE},@echo "[skip] mysql_router plugin (PROXYSQL40 not set)")
#--

.PHONY: build_src_testaurora
Expand Down Expand Up @@ -426,12 +428,14 @@ build_src_default: build_lib_default
cd src && OPTZ="${O2} -ggdb" PROXYSQLCLICKHOUSE=1 PROXYSQLFFTO=$(PROXYSQLFFTO) PROXYSQLTSDB=$(PROXYSQLTSDB) PROXYSQLED25519=$(PROXYSQLED25519) CC=${CC} CXX=${CXX} ${MAKE}
$(if $(filter 1,$(PROXYSQL40)),cd plugins/mysqlx && OPTZ="${O2} -ggdb" PROXYSQL40=$(PROXYSQL40) PROXYSQL31=$(PROXYSQL31) PROXYSQLFFTO=$(PROXYSQLFFTO) PROXYSQLTSDB=$(PROXYSQLTSDB) CC=${CC} CXX=${CXX} ${MAKE},@echo "[skip] mysqlx plugin (PROXYSQL40 not set)")
$(if $(filter 1,$(PROXYSQL40)),cd plugins/genai && OPTZ="${O2} -ggdb" PROXYSQL40=$(PROXYSQL40) PROXYSQL31=$(PROXYSQL31) PROXYSQLFFTO=$(PROXYSQLFFTO) PROXYSQLTSDB=$(PROXYSQLTSDB) CC=${CC} CXX=${CXX} ${MAKE},@echo "[skip] genai plugin (PROXYSQL40 not set)")
$(if $(filter 1,$(PROXYSQL40)),cd plugins/mysql_router && OPTZ="${O2} -ggdb" PROXYSQL40=$(PROXYSQL40) PROXYSQL31=$(PROXYSQL31) PROXYSQLFFTO=$(PROXYSQLFFTO) PROXYSQLTSDB=$(PROXYSQLTSDB) CC=${CC} CXX=${CXX} ${MAKE},@echo "[skip] mysql_router plugin (PROXYSQL40 not set)")

.PHONY: build_src_debug_default
build_src_debug_default: build_lib_debug_default
cd src && OPTZ="${O0} -ggdb -DDEBUG" PROXYSQLCLICKHOUSE=1 PROXYSQLFFTO=$(PROXYSQLFFTO) PROXYSQLTSDB=$(PROXYSQLTSDB) PROXYSQLED25519=$(PROXYSQLED25519) CC=${CC} CXX=${CXX} ${MAKE}
$(if $(filter 1,$(PROXYSQL40)),cd plugins/mysqlx && OPTZ="${O0} -ggdb -DDEBUG" PROXYSQL40=$(PROXYSQL40) PROXYSQL31=$(PROXYSQL31) PROXYSQLFFTO=$(PROXYSQLFFTO) PROXYSQLTSDB=$(PROXYSQLTSDB) CC=${CC} CXX=${CXX} ${MAKE},@echo "[skip] mysqlx plugin (PROXYSQL40 not set)")
$(if $(filter 1,$(PROXYSQL40)),cd plugins/genai && OPTZ="${O0} -ggdb -DDEBUG" PROXYSQL40=$(PROXYSQL40) PROXYSQL31=$(PROXYSQL31) PROXYSQLFFTO=$(PROXYSQLFFTO) PROXYSQLTSDB=$(PROXYSQLTSDB) CC=${CC} CXX=${CXX} ${MAKE},@echo "[skip] genai plugin (PROXYSQL40 not set)")
$(if $(filter 1,$(PROXYSQL40)),cd plugins/mysql_router && OPTZ="${O0} -ggdb -DDEBUG" PROXYSQL40=$(PROXYSQL40) PROXYSQL31=$(PROXYSQL31) PROXYSQLFFTO=$(PROXYSQLFFTO) PROXYSQLTSDB=$(PROXYSQLTSDB) CC=${CC} CXX=${CXX} ${MAKE},@echo "[skip] mysql_router plugin (PROXYSQL40 not set)")


### packaging targets
Expand Down Expand Up @@ -538,6 +542,7 @@ clean:
cd src && ${MAKE} clean
cd plugins/mysqlx && ${MAKE} clean
cd plugins/genai && ${MAKE} clean
cd plugins/mysql_router && ${MAKE} clean
cd test/tap && ${MAKE} clean
rm -f pkgroot || true

Expand All @@ -548,13 +553,15 @@ cleandeps:
cd src && ${MAKE} clean
cd plugins/mysqlx && ${MAKE} clean
cd plugins/genai && ${MAKE} clean
cd plugins/mysql_router && ${MAKE} clean

.PHONY: cleandev
cleandev:
cd lib && ${MAKE} clean
cd src && ${MAKE} clean
cd plugins/mysqlx && ${MAKE} clean
cd plugins/genai && ${MAKE} clean
cd plugins/mysql_router && ${MAKE} clean

.PHONY: cleantest
cleantest:
Expand All @@ -568,6 +575,7 @@ cleanall:
cd src && ${MAKE} clean
cd plugins/mysqlx && ${MAKE} clean
cd plugins/genai && ${MAKE} clean
cd plugins/mysql_router && ${MAKE} clean
cd test/tap && ${MAKE} clean
cd test/deps && ${MAKE} cleanall
rm -f binaries/* || true
Expand All @@ -580,6 +588,7 @@ cleanbuild:
cd src && ${MAKE} clean
cd plugins/mysqlx && ${MAKE} clean
cd plugins/genai && ${MAKE} clean
cd plugins/mysql_router && ${MAKE} clean
rm -rf pkgroot || true


Expand All @@ -598,6 +607,10 @@ install: src/proxysql
install -d /usr/lib/proxysql/plugins ; \
install -m 0755 plugins/genai/ProxySQL_GenAI_Plugin.so /usr/lib/proxysql/plugins/ ; \
fi
if [ -f plugins/mysql_router/proxysql_mysql_router.so ]; then \
install -d /usr/lib/proxysql/plugins ; \
install -m 0755 plugins/mysql_router/proxysql_mysql_router.so /usr/lib/proxysql/plugins/ ; \
fi
ifeq ($(findstring proxysql,$(USERCHECK)),)
@echo "Creating proxysql user and group"
useradd -r -U -s /bin/false proxysql
Expand Down Expand Up @@ -638,6 +651,7 @@ uninstall:
if [ -f /usr/bin/proxysql ]; then rm /usr/bin/proxysql ; fi
if [ -f /usr/lib/proxysql/plugins/ProxySQL_MySQLX_Plugin.so ]; then rm /usr/lib/proxysql/plugins/ProxySQL_MySQLX_Plugin.so ; fi
if [ -f /usr/lib/proxysql/plugins/ProxySQL_GenAI_Plugin.so ]; then rm /usr/lib/proxysql/plugins/ProxySQL_GenAI_Plugin.so ; fi
if [ -f /usr/lib/proxysql/plugins/proxysql_mysql_router.so ]; then rm /usr/lib/proxysql/plugins/proxysql_mysql_router.so ; fi
if [ -d /usr/lib/proxysql/plugins ]; then rmdir /usr/lib/proxysql/plugins 2>/dev/null || true ; fi
if [ -d /usr/lib/proxysql ]; then rmdir /usr/lib/proxysql 2>/dev/null || true ; fi
if [ -d /var/lib/proxysql ]; then rmdir /var/lib/proxysql 2>/dev/null || true ; fi
Expand Down
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,12 @@ sha256sum -c proxysql-<version>-linux-amd64.tar.gz.sha256
tar xzf proxysql-<version>-linux-amd64.tar.gz
```
The archive contains `bin/proxysql`, a sample `etc/proxysql.cnf`, the `systemd/`
units, and helper tools. The v4.0 build additionally ships the runtime plugins
under `lib/proxysql/` (`ProxySQL_MySQLX_Plugin.so`, `ProxySQL_GenAI_Plugin.so`).
units, and helper tools. The v4.0 build additionally includes runtime plugins
for MySQL X, GenAI, and the real
[MySQL Router compatibility foundation](doc/mysql-router-plugin.md). The
Router plugin is distinct from the MySQL X protocol plugin and is not yet
included in release packages; source builds install
`proxysql_mysql_router.so` under `/usr/lib/proxysql/plugins/`.

Building ProxySQL from source requires Git LFS so the pinned OpenSSL source is
hydrated before dependency builds start:
Expand Down
89 changes: 61 additions & 28 deletions doc/PLUGIN_API.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,13 @@ startup phase before the database takes precedence).

### Startup Sequence

ProxySQL uses a **four-phase** plugin lifecycle. Every phase but Phase B
is mandatory; Phase B is optional via the `register_schemas` descriptor
field and only enabled when the plugin declares ABI version 2 or higher.

1. **Phase A — load.** ProxySQL parses `proxysql.cnf` and populates the
`plugins` list. For each plugin path, ProxySQL calls `dlopen()`,
resolves the `proxysql_plugin_descriptor_v1` symbol, and validates
the descriptor (`abi_version`, `name`, callback pointers).
ProxySQL uses an ordered six-phase plugin lifecycle. Schema registration is
optional via the `register_schemas` descriptor field and is enabled only when
the plugin declares ABI version 2 or higher.

1. **Phase A — discover and register CLI.** ProxySQL parses `proxysql.cnf`,
loads and validates each plugin, then invokes `register_cli_options` (ABI
6+) before the one definitive command-line parse.
2. **Phase B — register_schemas (optional, ABI 2+).** If the
descriptor wires `register_schemas`, the loader invokes it with a
`ProxySQL_PluginServices` whose `register_table` /
Expand All @@ -58,22 +57,21 @@ field and only enabled when the plugin declares ABI version 2 or higher.
are non-null stubs that return `nullptr`. The plugin declares the
tables it owns, its admin commands, and any admin-side runtime
views it wants the chassis to project from module state; it MUST
NOT touch DB handles here. Plugins that leave `register_schemas`
null (or that declare ABI 1) skip this phase entirely and do all
their setup in Phase D.
NOT touch DB handles here.
3. **Phase C — admin materialization.** The admin module initializes
and materializes the SQLite schemas collected during Phase B
(`merge_plugin_tables` + `CREATE TABLE`). On DDL failure ProxySQL
aborts startup.
4. **Phase D — init.** The plugin's `init()` callback is called,
receiving a fully live `ProxySQL_PluginServices` (DB handles now
valid). Plugins that opted out of Phase B register their tables
AND commands here; plugins that used Phase B only finish their
context setup.
5. **Phase E — start.** The plugin's `start()` callback is called.
The plugin should start its threads, open listener sockets, and
load runtime configuration. After this returns, ProxySQL is ready
and the plugin is live.
4. **Phase D — early action (ABI 6+).** After Admin is live, ProxySQL invokes
`early_action` once. It may continue normal startup or request a successful
or failed process exit (for example after bootstrap).
5. **Phase E — init.** The plugin's `init()` callback receives fully live
services. Plugins that omitted Phase B may register their schema and
commands here; plugins that used Phase B finish their context setup.
6. **Phase F — start.** The plugin's `start()` callback starts plugin-owned
workers and other active resources. After core runtime dependencies exist,
ABI-8 plugins also receive `runtime_ready()` immediately before listener
validation/start.

### Shutdown Sequence

Expand Down Expand Up @@ -103,32 +101,41 @@ All types are defined in `include/ProxySQL_Plugin.h`:
```cpp
struct ProxySQL_PluginDescriptor {
const char *name; // Human-readable plugin name
uint32_t abi_version; // PROXYSQL_PLUGIN_ABI_VERSION (currently 5)
uint32_t abi_version; // PROXYSQL_PLUGIN_ABI_VERSION (currently 9)
proxysql_plugin_init_cb init; // bool (*)(ProxySQL_PluginServices *)
proxysql_plugin_start_cb start; // bool (*)()
proxysql_plugin_stop_cb stop; // bool (*)()
proxysql_plugin_status_json_cb status_json; // const char *(*)()
proxysql_plugin_register_schemas_cb register_schemas; // ABI 2+, optional
proxysql_plugin_register_cli_options_cb register_cli_options; // ABI 6+, optional
proxysql_plugin_early_action_cb early_action; // ABI 6+, optional
proxysql_plugin_runtime_ready_cb runtime_ready; // ABI 8+, optional
};
```

| Field | Type | Description |
|--------------------|---------------|-----------------------------------------------------------|
| `name` | `const char*` | Plugin identifier, used in logging. |
| `abi_version` | `uint32_t` | Set from `PROXYSQL_PLUGIN_ABI_VERSION`. Value `1` is the pre-chassis descriptor; `2` adds `register_schemas`; `3` adds `register_runtime_view`; `4` appends `db_kind` to runtime views; `5` appends optional Admin-mutex handoff callbacks to `ProxySQL_PluginCommandContext`. The current PROXYSQL40 core accepts `[1, 5]`. |
| `init` | callback | Phase D — called with live services; register tables and commands here (or finish context setup if `register_schemas` already did it). |
| `start` | callback | Phase E — start threads, open sockets, load config. |
| `abi_version` | `uint32_t` | Set from `PROXYSQL_PLUGIN_ABI_VERSION`. The current PROXYSQL40 core accepts `[1, 9]`; all evolution is tail-additive. See the ABI reference for the per-version matrix. |
| `init` | callback | Phase E — called with live services; register tables and commands here (or finish context setup if `register_schemas` already did it). |
| `start` | callback | Phase F — start threads, open sockets, load config. |
| `stop` | callback | Called on shutdown. Pairs with `init`, not `start`: if `init` returned true and `start` later failed, `stop` is still called so the plugin can release resources it allocated in `init`. |
| `status_json` | callback | Return a static JSON string describing plugin status. |
| `register_schemas` | callback | Phase B (ABI 2+). Optional; leave null to skip Phase B entirely. Services passed here have `register_table` / `register_command` / `register_command_alias` / `register_runtime_view` LIVE but DB-handle getters returning `nullptr`. |
| `register_cli_options` | callback | ABI 6+. Registers options before the one definitive core parse. |
| `early_action` | callback | ABI 6+. Runs once after Admin is live and may continue startup or request process exit. |
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
| `runtime_ready` | callback | ABI 8+. Runs after core runtime dependencies exist and before listener validation. |

All callbacks return `bool` (except `status_json` which returns `const char*`).
Return `true` on success, `false` on failure. A `false` return from
`register_schemas`, `init`, or `start` causes ProxySQL to exit.
Lifecycle and registration callbacks return `bool` (except `status_json`,
which returns `const char*`). `early_action` instead returns
`ProxySQL_PluginEarlyActionResult`: `continue_startup`, `exit_success`, or
`exit_failure`. Return `true` on success and `false` on failure from boolean
callbacks. A `false` return from `register_schemas`, `init`, or `start` causes
ProxySQL to exit.

#### ABI version

`include/ProxySQL_Plugin.h` exposes `PROXYSQL_PLUGIN_ABI_VERSION` (currently 5
`include/ProxySQL_Plugin.h` exposes `PROXYSQL_PLUGIN_ABI_VERSION` (currently 9
under PROXYSQL40, undefined in pre-chassis builds — the descriptor is then a
legacy six-field struct with `abi_version = 1`). Plugins MUST assign
`abi_version` from this macro rather than hard-coding a literal; the
Expand Down Expand Up @@ -168,9 +175,35 @@ struct ProxySQL_PluginServices {
proxysql_plugin_register_command_alias_cb register_command_alias;
// ABI 3 tail extension:
proxysql_plugin_register_runtime_view_cb register_runtime_view;
// ABI 7 tail extension:
ProxySQL_PluginSecretResult (*put_secret)(...);
ProxySQL_PluginSecretResult (*get_secret)(...);
ProxySQL_PluginSecretResult (*erase_secret)(...);
// ABI 8 tail extensions:
bool (*set_listener_gate)(const ProxySQL_PluginListenerGate&);
ProxySQL_PluginMysqlConfigResult (*apply_mysql_config)(
const ProxySQL_PluginMysqlConfigPlan&);
// ABI 9 final tail:
ProxySQL_PluginMysqlConfigResult (*apply_mysql_config_v2)(
const ProxySQL_PluginMysqlConfigPlanV2&);
};
```

#### `apply_mysql_config_v2` (ABI 9)

ABI 9 preserves the complete ABI-8 `ProxySQL_PluginMysqlConfigPlan` and rule
row. `ProxySQL_PluginMysqlConfigPlanV2` embeds that base plan and adds a
separate array of `{rule_id, attributes}` rows. Attributes must be JSON objects
and every ID must refer to one base-plan rule.

The callback is synchronous: the plugin owns the plan arrays and strings only
until the call returns. Core copies and validates them before taking locks, then
publishes storage and live MySQL state as one generation. Validation failure,
runtime failure, or transaction failure leaves the previous generation active.
Phase B provides a rejecting stub. ABI-8 plugins continue using the unchanged
V1 callback; ABI-9 plugins that require attributes should fail closed rather
than falling back and losing behavior.

### Service Callbacks

#### `register_table`
Expand Down
Loading
Loading