Skip to content
Open
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@
"db search",
"db tables",
"db size",
"db columns"
"db columns",
"db status"
]
},
"autoload": {
Expand Down
89 changes: 89 additions & 0 deletions features/db-status.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
Feature: Display database status overview

Scenario: Display database status for a WordPress install
Given a WP install

When I run `wp db status`
Then STDOUT should contain:
"""
Database Name: wp_cli_test
"""
And STDOUT should match /^Tables:\s+\d+$/m
And STDOUT should match /^Total Size:\s+[\d.]+ \wB$/m
And STDOUT should contain:
"""
Prefix: wp_
"""
And STDOUT should match /^Engine:\s+\w+$/m
And STDOUT should match /^Charset:\s+\w+$/m
And STDOUT should match /^Collation:\s+\w+$/m
And STDOUT should contain:
"""
Check Status: OK
"""

Scenario: Run db status with MySQL defaults to check the database
Given a WP install

When I run `wp db status --defaults`
Then STDOUT should contain:
"""
Database Name:
"""
And STDOUT should contain:
"""
Check Status: OK
"""

Scenario: Run db status with --no-defaults to check the database
Given a WP install

When I run `wp db status --no-defaults`
Then STDOUT should contain:
"""
Database Name:
"""
And STDOUT should contain:
"""
Check Status: OK
"""

Scenario: Run db status with passed-in options
Given a WP install

When I run `wp db status --dbuser=wp_cli_test`
Then STDOUT should contain:
"""
Database Name:
"""
And STDOUT should contain:
"""
Check Status: OK
"""

When I run `wp db status --dbpass=password1`
Then STDOUT should contain:
"""
Database Name:
"""
And STDOUT should contain:
"""
Check Status: OK
"""

When I run `wp db status --dbuser=wp_cli_test --dbpass=password1`
Then STDOUT should contain:
"""
Database Name:
"""
And STDOUT should contain:
"""
Check Status: OK
"""

When I try `wp db status --dbuser=no_such_user`
Then the return code should not be 0

When I try `wp db status --dbpass=no_such_pass`
Then the return code should not be 0

144 changes: 144 additions & 0 deletions src/DB_Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -1271,6 +1271,150 @@
WP_CLI::log( $wpdb->prefix );
}

/**
* Displays a quick database status overview.
*
* Shows key database information including name, table count, size,
* prefix, engine, charset, collation, and health check status. This
* command is useful for getting a quick snapshot of database health
* without needing to run multiple separate commands.
*
* ## OPTIONS
*
* [--dbuser=<value>]
* : Username to pass to mysql. Defaults to DB_USER.
*
* [--dbpass=<value>]
* : Password to pass to mysql. Defaults to DB_PASSWORD.
*
* [--defaults]
* : Loads the environment's MySQL option files. Default behavior is to skip loading them to avoid failures due to misconfiguration.
*
* ## EXAMPLES
*
* $ wp db status
* Database Name: wp_cli_test
* Tables: 54
* Total Size: 312 KB
* Prefix: wp_
* Engine: InnoDB
* Charset: utf8mb4
* Collation: utf8mb4_unicode_ci
* Check Status: OK
*
* @when after_wp_load
*/
public function status( $_, $assoc_args ) {
global $wpdb;

$table_count = count( Utils\wp_get_table_names( [], [ 'scope' => 'all' ] ) );

$db_size_bytes = $wpdb->get_var(
$wpdb->prepare(
'SELECT SUM(data_length + index_length) FROM information_schema.TABLES where table_schema = %s GROUP BY table_schema;',
DB_NAME
)
);

if ( ! empty( $db_size_bytes ) && $db_size_bytes > 0 ) {
$size_key = floor( log( (float) $db_size_bytes ) / log( 1000 ) );
$sizes = [ 'B', 'KB', 'MB', 'GB', 'TB' ];
$size_format = $sizes[ $size_key ] ?? $sizes[0];

Check failure on line 1322 in src/DB_Command.php

View workflow job for this annotation

GitHub Actions / code-quality / PHPStan

Invalid array key type float.
$divisor = pow( 1000, $size_key );
$db_size = round( (int) $db_size_bytes / $divisor, 2 ) . ' ' . $size_format;
} else {
$db_size = '0 B';
}

$prefix = $wpdb->prefix;

$table_info = $wpdb->get_row(
$wpdb->prepare(
'SELECT '
. 'COUNT(DISTINCT ENGINE) AS engine_count, '
. 'MIN(ENGINE) AS engine, '
. 'COUNT(DISTINCT CCSA.character_set_name) AS charset_count, '
. 'MIN(CCSA.character_set_name) AS charset, '
. 'COUNT(DISTINCT TABLE_COLLATION) AS collation_count, '
. 'MIN(TABLE_COLLATION) AS collation '
. 'FROM information_schema.TABLES T '
. 'LEFT JOIN information_schema.COLLATION_CHARACTER_SET_APPLICABILITY CCSA '
. 'ON CCSA.collation_name = T.table_collation '
. 'WHERE T.table_schema = %s '
. 'AND T.table_name LIKE %s',
DB_NAME,
$wpdb->esc_like( $prefix ) . '%'
)
);

if ( $table_info ) {
$engine_count = isset( $table_info->engine_count ) ? (int) $table_info->engine_count : 0;
$charset_count = isset( $table_info->charset_count ) ? (int) $table_info->charset_count : 0;
$collation_count = isset( $table_info->collation_count ) ? (int) $table_info->collation_count : 0;

if ( $engine_count > 1 ) {
$engine = 'Mixed';
} elseif ( isset( $table_info->engine ) && '' !== $table_info->engine ) {
$engine = $table_info->engine;
} else {
$engine = 'N/A';
}

if ( $charset_count > 1 ) {
$charset = 'Mixed';
} elseif ( isset( $table_info->charset ) && '' !== $table_info->charset ) {
$charset = $table_info->charset;
} else {
$charset = 'N/A';
}

if ( $collation_count > 1 ) {
$collation = 'Mixed';
} elseif ( isset( $table_info->collation ) && '' !== $table_info->collation ) {
$collation = $table_info->collation;
} else {
$collation = 'N/A';
}
} else {
$engine = 'N/A';
$charset = 'N/A';
$collation = 'N/A';
}
// Run database check silently to get status.
if ( $table_count > 0 ) {
$command = sprintf(
'/usr/bin/env %s%s %s',
Utils\get_sql_check_command(),
$this->get_defaults_flag_string( $assoc_args ),
'%s'
);
list( $stdout, $stderr, $exit_code ) = self::run(
Utils\esc_cmd( $command, DB_NAME ),
array_merge( [ 'check' => true ], $assoc_args ),
false
);
$check_status = ( 0 === $exit_code ) ? 'OK' : 'Error';
} else {
// No tables to check; mark status as not applicable.
$check_status = 'N/A';
}

$status_items = [
'Database Name' => DB_NAME,
'Tables' => $table_count,
'Total Size' => $db_size,
'Prefix' => $prefix,
'Engine' => $engine,
'Charset' => $charset,
'Collation' => $collation,
'Check Status' => $check_status,
];

foreach ( $status_items as $label => $value ) {
WP_CLI::log( sprintf( '%-18s %s', $label . ':', $value ) );
}
}

/**
* Finds a string in the database.
*
Expand Down
Loading