feat: add support for excluding table data during export - #298
feat: add support for excluding table data during export#298astappiev wants to merge 12 commits into
Conversation
Introduces the `--exclude_tables_data` option to the `wp db export` command, allowing users to export only the structure of specified tables while excluding their data. This enhances flexibility in database management and export processes.
This comment was marked as resolved.
This comment was marked as resolved.
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
This comment was marked as resolved.
This comment was marked as resolved.
|
@coderabbitai review |
✅ Action performedReview finished.
|
📝 WalkthroughWalkthrough
ChangesTable-data exclusion
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant CLI as wp db export
participant Command as DB_Command::export
participant MariaDB as MariaDB dump
CLI->>Command: Provide exclude_tables_data
Command->>Command: Validate MariaDB and parse tables
Command->>MariaDB: Forward ignore-table-data arguments
MariaDB-->>CLI: Write SQL export without selected data
Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
features/db-export.feature (1)
84-99: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winTest multiple exclusions and structure retention.
Issue
#289concerns multiple table-data exclusions, but this scenario passes onlywp_users. Use at least two comma-separated tables and assert that no data statement exists for each. Also assertCREATE TABLEfor an excluded table. A genericwp_usersmatch does not prove that the table structure was retained.As per coding guidelines, new features and bug fixes must include Behat acceptance tests.
Suggested test expansion
- When I run `wp db export wp_cli_test.sql --exclude_tables_data=wp_users --porcelain` + When I run `wp db export wp_cli_test.sql --exclude_tables_data=wp_users,wp_options --porcelain` Then the wp_cli_test.sql file should exist - And the wp_cli_test.sql file should contain: - """ - wp_users - """ + And the contents of the wp_cli_test.sql file should match /CREATE TABLE ["`]?wp_users["`]?/ And the wp_cli_test.sql file should not contain: """ INSERT INTO `wp_users` """ + And the contents of the wp_cli_test.sql file should not match /INSERT INTO ["`]?wp_options["`]?/🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@features/db-export.feature` around lines 84 - 99, Expand the “Exclude data of certain tables” scenario to pass at least two comma-separated tables via --exclude_tables_data, assert the exported SQL contains no INSERT statements for each excluded table, and verify a CREATE TABLE statement remains for at least one excluded table instead of relying on a generic table-name match.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/DB_Command.php`:
- Around line 846-858: Update the exclude_tables_data handling in the command
method to read and unset assoc_args['exclude_tables_data'] unconditionally
before validation or trimming. Reject non-string values, including empty or
numeric inputs, before processing CSV content; only trim and split valid
strings, while preserving the MariaDB support check and preventing the option
from reaching self::run().
- Around line 687-690: Update the --exclude_tables_data documentation in
src/DB_Command.php lines 687-690 and README.md lines 470-472 to state that the
option is supported by MariaDB 10.1 and later, using consistent wording in both
references.
---
Nitpick comments:
In `@features/db-export.feature`:
- Around line 84-99: Expand the “Exclude data of certain tables” scenario to
pass at least two comma-separated tables via --exclude_tables_data, assert the
exported SQL contains no INSERT statements for each excluded table, and verify a
CREATE TABLE statement remains for at least one excluded table instead of
relying on a generic table-name match.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: a56b328e-3b43-4f3f-83bc-3ce5017d3d3e
📒 Files selected for processing (3)
README.mdfeatures/db-export.featuresrc/DB_Command.php
| * [--exclude_tables_data=<tables>] | ||
| * : The comma separated list of specific tables for which only the structure will be exported. Excluding this parameter will export data for all tables in the export. | ||
| * Note: currently only supported by MariaDB. | ||
| * |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== candidate files =="
git ls-files | rg '(^|/)DB_Command\.php$|(^|/)README\.md$' || true
echo
echo "== relevant mentions of exclude_tables_data and MariaDB minimum/version =="
rg -n --hidden --glob '!vendor/**' --glob '!node_modules/**' \
'exclude_tables_data|MariaDB|10\.1|10|11|version' \
src/DB_Command.php README.md 2>/dev/null || true
echo
echo "== DB_Command.php context =="
sed -n '660,715p' src/DB_Command.php 2>/dev/null || true
echo
echo "== README.md context =="
sed -n '455,485p' README.md 2>/dev/null || trueRepository: wp-cli/db-command
Length of output: 8057
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== all repository references to MariaDB 10.1/10.1 minimum and export include/exclude =="
rg -n --hidden --glob '!vendor/**' --glob '!node_modules/**' \
'MariaDB\s*(10\.1|10|11)|10\.1\s*MariaDB|mariadb|MariaDB \d+\.\d+|export|--include_tables|--exclude_tables' .
echo
echo "== DB_Command.php outline around DB export methods =="
ast-grep outline src/DB_Command.php --match 'export' --view expanded 2>/dev/null || trueRepository: wp-cli/db-command
Length of output: 16553
🌐 Web query:
MariaDB 10.1 SET export documentation --set-gtid-purged
💡 Result:
The MariaDB mysqldump utility does not support the --set-gtid-purged flag [1][2][3]. This flag is specific to the MySQL mysqldump implementation [1]. If you attempt to use --set-gtid-purged=OFF (or any other value) with MariaDB's mysqldump, the command will fail with an error stating that it is an "unknown variable" [4][2][3]. This incompatibility arises because MariaDB and MySQL use different, non-compatible implementations for Global Transaction IDs (GTIDs) [1][5][6]. Consequently, the options related to GTIDs in the MySQL version of mysqldump do not exist in the MariaDB version [1]. If you encounter this error in automation scripts or build tools (such as Laravel or custom shell scripts), the correct solution is to remove the --set-gtid-purged flag from your mysqldump command [1][7][2][3].
Citations:
- 1: https://stackoverflow.com/questions/48876519/mysqldump-stopped-working-with-conversion-to-mariadb-set-gtid-purged-off-issue
- 2: [8.x] Schema Dump (MariaDB) laravel/framework#32552
- 3: Unsupported mysqldump args cause scripts to fail with MariaDB nystudio107/craft-scripts#59
- 4: unknown variable 'set-gtid-purged=OFF' webarchitect609/mysql-twin-dump#1
- 5: https://mariadb.com/docs/release-notes/community-server/about/compatibility-and-differences/system-variable-differences-between-mariadb-and-mysql/system-variable-differences-between-mariadb-and-mysql-unmaintained-series/system-variable-differences-between-mariadb-10-1-and-mysql-5-7.md
- 6: https://mariadb.com/docs/release-notes/community-server/about/compatibility-and-differences/system-variable-differences-between-mariadb-and-mysql/system-variable-differences-between-mariadb-and-mysql-unmaintained-series/system-variable-differences-between-mariadb-10-1-and-mysql-5-6.md
- 7: heyinc/exwiw@1874a34
🌐 Web query:
MariaDB server options documentation --set-gtid-purged --skip-set-gtid-purged MariaDB 10.1
💡 Result:
The command-line options --set-gtid-purged and --skip-set-gtid-purged do not exist in the MariaDB version of mysqldump, including in MariaDB 10.1 [1][2][3]. These options are specific to the MySQL implementation of mysqldump [4][1]. Because MariaDB's GTID implementation differs from MySQL's, MariaDB does not support these flags [1]. Attempting to use them with a MariaDB-provided mysqldump client will result in an "unknown variable" error and the command will fail [2][5][3][6]. If you encounter this error (common when using tools designed for MySQL against a MariaDB client environment), the correct solution is to remove these flags from your command-line arguments [1][7][3]. MariaDB uses its own methods and options for managing GTIDs during backups and replication, such as the --gtid option [8][9].
Citations:
- 1: https://stackoverflow.com/questions/48876519/mysqldump-stopped-working-with-conversion-to-mariadb-set-gtid-purged-off-issue
- 2: unknown variable 'set-gtid-purged=OFF' webarchitect609/mysql-twin-dump#1
- 3: artisan schema:dump breaks - if MySQL server and MariaDB client is used (mysqldump: unknown variable 'set-gtid-purged=OFF') laravel/framework#35223
- 4: https://dev.mysql.com/doc/en/mysqldump.html
- 5: schema:dump error laravel/framework#34280
- 6: artisan schema:dump error laravel/framework#34592
- 7: heyinc/exwiw@1874a34
- 8: https://mariadb.com/docs/server/clients-and-utilities/backup-restore-and-import-clients/mariadb-dump
- 9: https://manpages.debian.org/stretch/mariadb-client-10.1/mysqldump.1.en.html
🌐 Web query:
site:Mariadb.com mysqldump SET_SESSION_GTID_PRUNE MariaDB mysqldump options MariaDB 10.1 exclude tables data structure only
💡 Result:
The command formerly known as mysqldump is now called mariadb-dump in MariaDB, though mysqldump remains accessible as a symbolic link in many versions [1][2]. Regarding your specific queries: SET_SESSION_GTID_PRUNE There is no standard mysqldump or mariadb-dump option named SET_SESSION_GTID_PRUNE. MariaDB manages GTID-based replication using options like --gtid, which, when combined with --master-data or --dump-slave, automatically includes necessary SQL statements (such as setting gtid_slave_pos and executing CHANGE MASTER) to configure a replica [3][4][5]. If you encounter SET_SESSION_GTID_PRUNE, it is likely a non-standard or custom session variable; standard session variables are managed via the SET statement in SQL [6]. Exclude tables To exclude specific tables when using mariadb-dump (or mysqldump), use the --ignore-table option. You must specify the table in the format db_name.table_name. You can use this option multiple times to exclude multiple tables: mariadb-dump --ignore-table=database_name.table_name1 --ignore-table=database_name.table_name2 database_name > backup.sql Data structure only To export only the database structure (schema) without table data, use the --no-data option [7][8]: mariadb-dump --no-data database_name > schema_backup.sql Combining these, to dump the structure of a database while excluding specific tables: mariadb-dump --no-data --ignore-table=db.table1 --ignore-table=db.table2 db_name > schema_only_exclude_tables.sql
Citations:
- 1: https://mariadb.com/docs/server/clients-and-utilities/legacy-clients-and-utilities/mysqldump
- 2: https://mariadb.com/docs/server/mariadb-quickstart-guides/mariadb-backup-guide.md
- 3: https://mariadb.com/docs/server/clients-and-utilities/backup-restore-and-import-clients/mariadb-dump
- 4: https://mariadb.com/docs/server/ha-and-performance/standard-replication/gtid
- 5: https://mariadb.com/docs/server/ha-and-performance/standard-replication/gtid.md
- 6: https://mariadb.com/docs/server/reference/sql-statements/administrative-sql-statements/set-commands/set.md
- 7: https://mariadb.com/docs/server/server-management/install-and-upgrade-mariadb/migrating-to-mariadb/ddl-export
- 8: https://mariadb.com/docs/mariadb-cloud/cloud-data-handling/data-offloading
🌐 Web query:
"exclude_tables_data" "MariaDB" "10.1" "10" "11"
💡 Result:
In MariaDB, the --ignore-table-data option is the specific command-line argument used to exclude the data (contents) of a table from a backup while still exporting its structure [1][2][3]. Usage Requirements The option requires the full format of database_name.table_name [1][2]. If you need to exclude data for multiple tables, you must repeat the --ignore-table-data option for each table [1][3]. Example To back up a database named my_database while excluding data from tables named table1 and table2: mariadb-dump my_database --ignore-table-data=my_database.table1 --ignore-table-data=my_database.table2 > backup.sql Version Compatibility This option is a feature specific to MariaDB's dump utility and is not available in standard MySQL mysqldump [4]. It was introduced in the following MariaDB releases: - MariaDB 10.1.46 and later [2][3] - MariaDB 10.2.33 and later [2][3] - MariaDB 10.3.24 and later [2][3] - MariaDB 10.4.14 and later [2][3] - MariaDB 10.5.3 and later [2][3] For versions of MariaDB newer than 10.5.3, including 10.11, this option remains available and is the standard way to perform this task [1][5]. If you encounter an error when using this command, ensure you are using the MariaDB-provided version of the dump utility (mariadb-dump or mysqldump) rather than a client bundled with a different MySQL distribution [4].
Citations:
- 1: https://mariadb.com/docs/server/clients-and-utilities/backup-restore-and-import-clients/mariadb-dump
- 2: https://stackoverflow.com/questions/13593148/mysqldump-exclude-some-table-data
- 3: https://docs.w3cub.com/mariadb/mariadb-dump/index
- 4: https://stackoverflow.com/questions/75548318/when-i-use-mysqldump-with-the-ignore-table-data-option-i-get-an-unknown-vari
- 5: https://manpages.debian.org/unstable/mariadb-client-compat/mysqldump.1
Include the MariaDB 10.1 minimum for --exclude_tables_data.
Both src/DB_Command.php and README.md say the option is available only for MariaDB but omit the minimum version. Add the same MariaDB 10.1 and later wording to both references.
📍 Affects 2 files
src/DB_Command.php#L687-L690(this comment)README.md#L470-L472
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/DB_Command.php` around lines 687 - 690, Update the --exclude_tables_data
documentation in src/DB_Command.php lines 687-690 and README.md lines 470-472 to
state that the option is supported by MariaDB 10.1 and later, using consistent
wording in both references.
Source: Coding guidelines
| $exclude_tables_data = Utils\get_flag_value( $assoc_args, 'exclude_tables_data', '' ); | ||
| if ( ! empty( $exclude_tables_data ) ) { | ||
| unset( $assoc_args['exclude_tables_data'] ); | ||
|
|
||
| if ( 'mariadb' !== Utils\get_db_type() ) { | ||
| WP_CLI::error( 'The --exclude_tables_data option is only supported by MariaDB.' ); | ||
| } | ||
|
|
||
| $tables = explode( ',', trim( $exclude_tables_data, ',' ) ); | ||
| foreach ( $tables as $table ) { | ||
| $table = trim( $table ); | ||
| if ( '' === $table ) { | ||
| continue; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
rg -n -C 8 'function\s+get_flag_value\b|\bget_flag_value\s*\(' \
--glob '*.php' .Repository: wp-cli/db-command
Length of output: 19796
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
# Locate Utils and get_flag_value definition.
fd -a 'Utils.*\.php|class Utils|function get_flag_value' . | sed 's#^\./##'
rg -n -C 12 'public static function get_flag_value|function get_flag_value|get_flag_value' vendor wp-includes wp-cli . 2>/dev/null | head -200Repository: wp-cli/db-command
Length of output: 12383
🌐 Web query:
WP_CLI Utils get_flag_value implementation return type
💡 Result:
The WP-CLI function WP_CLI\Utils\get_flag_value returns a mixed type, specifically defined in its PHPDoc as string|bool|int|null [1][2][3]. The function is implemented as a simple conditional return that checks if a flag exists within the provided associative arguments array ($assoc_args); if the flag is present, it returns that value, and if not, it returns the provided $default value [1][4][3]: function get_flag_value( $assoc_args, $flag, $default = null) { return isset( $assoc_args[ $flag ])? $assoc_args[ $flag ]: $default; } Because the $default parameter defaults to null [1][3], the function effectively returns the type of the value stored in the arguments array (typically string, bool, or int) or the type of the $default value provided by the caller [1][2]. It is intended as a safer alternative to manual isset checks on arguments arrays, particularly because it helps handle negated flags (e.g., --no-quiet) [1][4].
Citations:
- 1: https://github.com/wp-cli/wp-cli/blob/main/php/utils.php
- 2: https://make.wordpress.org/cli/handbook/references/internal-api/wp-cli-utils-get-flag-value/
- 3: https://wp-kama.com/filecode/wp-cli/php/utils.php
- 4: https://wp-kama.com/handbook/wp-cli/function/get_flag_value
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
# Inspect the current export path around MariaDB handling and the SQL dump command.
sed -n '730,890p' src/DB_Command.php -n
# Behavioral probe for the current `empty()`/`trim()` decision table using PHP available in the sandbox.
php -r '
$values = [
"missing" => null,
"empty string" => "",
"true flag" => true,
"false flag" => false,
"numeric" => 123,
"empty array" => [],
];
echo "PHP version: ", PHP_VERSION, "\n";
foreach ( $values as $name => $value ) {
$unset_called = false;
if ( ! empty( $value ) ) {
$unset_called = true;
echo "SKIP ", $name, " (", gettype( $value ), ") has unset: ", var_export( $unset_called, true ), "\n";
} else {
echo "SKIP ", $name, " (", gettype( $value ), ") has unset: ", var_export( $unset_called, true ), "\n";
}
if ( ! empty( $value ) ) {
try {
echo " trim result: ", var_export( trim( $value, "," ), true ), "\n";
} catch ( \TypeError $e ) {
echo " trim type error: " . $e->getMessage() . "\n";
}
}
}
'Repository: wp-cli/db-command
Length of output: 6086
🏁 Script executed:
#!/usr/bin/env bash
set- euo pipefail
# Inspect run() method and get_defaults_flag_string for remaining assoc_args forwarding.
rg -n -C 12 'self::run\s*\(|protected static function run|private static function run|\$assoc_args|get_defaults_flag_string' src/DB_Command.php
# Read relevant ranges if present.
sed -n '100,220p' src/DB_Command.php | cat -n
sed -n '2330,2395p' src/DB_Command.php | cat -nRepository: wp-cli/db-command
Length of output: 50373
🌐 Web query:
WP_CLI run_mysql_command assoc_args implementation
💡 Result:
In WP-CLI, run_mysql_command is an internal utility function located in the php/utils.php file, designed to execute a MySQL command and handle the communication of arguments to the underlying process [1][2][3]. The function signature is: run_mysql_command( $cmd, $assoc_args, $_ = null, $send_to_shell = true, $interactive = false ) Implementation Details: 1. Associative Arguments Processing: The $assoc_args parameter is an associative array of key-value pairs representing the flags to be passed to the MySQL command (e.g., --host, --user, --password) [1][2]. 2. Handling Specific Arguments: - Host: If host is present in $assoc_args, the function merges it with specific CLI arguments using mysql_host_to_cli_args() [1][2]. - Password: If pass is present, the function securely sets the MYSQL_PWD environment variable for the process execution to avoid passing passwords directly in the command string, and restores the previous environment value afterward [1][2]. 3. Command Construction: The function uses assoc_args_to_str( $assoc_args ) to convert the associative array into a formatted string of CLI arguments, which is then appended to the base command $cmd [4][1][2]. 4. Process Execution: The constructed command is executed using proc_open_compat(). Depending on the parameters, it either redirects output to the shell ($send_to_shell) or captures it via pipes ($stdout, $stderr) [1][2]. In the context of WP-CLI command development, assoc_args typically refers to the associative array passed to your command callback, which contains flags parsed from the terminal (e.g., --key=value or --flag). This $assoc_args array is then passed to run_mysql_command to ensure the correct options are utilized when the database command is invoked [5][6].
Citations:
- 1: https://github.com/wp-cli/wp-cli/blob/main/php/utils.php
- 2: https://github.com/wp-cli/wp-cli/blob/f3e4b0785aa3d3132ee73be30aedca8838a8fa06/php/utils.php
- 3: https://wp-kama.com/filecode/wp-cli/php/utils.php
- 4: https://wp-kama.com/handbook/wp-cli/function/run_mysql_command
- 5: https://make.wordpress.org/cli/handbook/guides/commands-cookbook/
- 6: https://techearl.com/wordpress-custom-wp-cli-command
Remove and normalize exclude_tables_data before trimming.
Utils\get_flag_value() can return non-string values; non-empty flags or integers currently reach trim() and become numeric ignore-table values. An empty --exclude_tables_data or the SQLite return path also leaves the key in assoc_args until self::run(), where it can be forwarded to the dump command. Read and unset the key unconditionally, then reject non-string values before calling trim() on CSV content.
🧰 Tools
🪛 PHPStan (2.2.7)
[error] 854-854: Parameter #1 $string of function trim expects string, mixed given.
(argument.type)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/DB_Command.php` around lines 846 - 858, Update the exclude_tables_data
handling in the command method to read and unset
assoc_args['exclude_tables_data'] unconditionally before validation or trimming.
Reject non-string values, including empty or numeric inputs, before processing
CSV content; only trim and split valid strings, while preserving the MariaDB
support check and preventing the option from reaching self::run().
Source: Linters/SAST tools
Introduces the
--exclude_tables_dataoption to thewp db exportcommand, allowing users to export only the structure of specified tables while excluding their data.Warning: only supported by MariaDB 10.1 and later. As far as I know, not supported by MySQL.
Resolves #289
Summary by CodeRabbit
--exclude_tables_data=<tables>option towp db export.