Skip to content

feat: add support for excluding table data during export - #298

Open
astappiev wants to merge 12 commits into
wp-cli:mainfrom
astappiev:patch-1
Open

feat: add support for excluding table data during export#298
astappiev wants to merge 12 commits into
wp-cli:mainfrom
astappiev:patch-1

Conversation

@astappiev

@astappiev astappiev commented Oct 10, 2025

Copy link
Copy Markdown

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.

Warning: only supported by MariaDB 10.1 and later. As far as I know, not supported by MySQL.

Resolves #289

Summary by CodeRabbit

  • New Features
    • Added the --exclude_tables_data=<tables> option to wp db export.
    • Export table structures without including data for selected tables.
    • Added support for MariaDB, including examples and validation for unsupported MySQL and SQLite usage.
  • Documentation
    • Updated database export documentation with option details and usage examples.
  • Tests
    • Added coverage for successful MariaDB exports and expected failures on MySQL and SQLite.

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.
@astappiev
astappiev requested a review from a team as a code owner October 10, 2025 09:09
@swissspidy
swissspidy requested a review from Copilot November 2, 2025 14:59

This comment was marked as resolved.

@swissspidy

This comment was marked as resolved.

@github-actions github-actions Bot added command:db-export Related to 'db export' command scope:distribution Related to distribution labels Dec 22, 2025
@swissspidy swissspidy added this to the 2.1.5 milestone Jan 22, 2026
@codecov

codecov Bot commented Jan 22, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 38.46154% with 8 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/DB_Command.php 38.46% 8 Missing ⚠️

📢 Thoughts on this report? Let us know!

@swissspidy

This comment was marked as resolved.

gemini-code-assist[bot]

This comment was marked as resolved.

@swissspidy swissspidy modified the milestones: 2.1.5, 2.1.6 Mar 17, 2026
Comment thread src/DB_Command.php Outdated
@swissspidy swissspidy modified the milestones: 2.1.6, 2.1.7 May 23, 2026
@swissspidy swissspidy removed this from the 3.0.0 milestone Aug 4, 2026
@swissspidy

Copy link
Copy Markdown
Member

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

wp db export now supports --exclude_tables_data=<tables> for MariaDB. The command preserves table structure, omits selected table data, rejects MySQL and SQLite usage, and includes documentation and feature scenarios.

Changes

Table-data exclusion

Layer / File(s) Summary
Export option handling
src/DB_Command.php, README.md
wp db export documents and processes --exclude_tables_data=<tables>. The option is MariaDB-only, ignores empty entries, and forwards each selected table as a --ignore-table-data argument.
Export behavior validation
features/db-export.feature
Scenarios verify errors on MySQL and SQLite and verify that MariaDB exports retain wp_users structure without its INSERT statements.

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
Loading

Possibly related PRs

Suggested labels: scope:testing

Suggested reviewers: schlessera, swissspidy

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the primary change: support for excluding table data during database export.
Linked Issues check ✅ Passed The implementation supports multiple table-data exclusions by converting requested tables into separate MariaDB dump arguments, addressing issue #289.
Out of Scope Changes check ✅ Passed The documentation, implementation, and feature tests directly support the exclusion option and linked issue objectives.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🧹 Nitpick comments (1)
features/db-export.feature (1)

84-99: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Test multiple exclusions and structure retention.

Issue #289 concerns multiple table-data exclusions, but this scenario passes only wp_users. Use at least two comma-separated tables and assert that no data statement exists for each. Also assert CREATE TABLE for an excluded table. A generic wp_users match 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

📥 Commits

Reviewing files that changed from the base of the PR and between 8ecef74 and 9d07ac1.

📒 Files selected for processing (3)
  • README.md
  • features/db-export.feature
  • src/DB_Command.php

Comment thread src/DB_Command.php
Comment on lines +687 to +690
* [--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.
*

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 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 || true

Repository: 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 || true

Repository: 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:


🌐 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:


🌐 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:


🌐 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:


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

Comment thread src/DB_Command.php
Comment on lines +846 to +858
$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;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 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 -200

Repository: 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:


🏁 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 -n

Repository: 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:


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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

command:db-export Related to 'db export' command scope:distribution Related to distribution

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Giving multiple same arguments to mysqldump (via wp db export) only forwards the latest

3 participants