Skip to content

Commit 2478ce4

Browse files
committed
Remove system tables from information schema results
1 parent 7ab0100 commit 2478ce4

2 files changed

Lines changed: 48 additions & 62 deletions

File tree

tests/WP_SQLite_Metadata_Tests.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,38 @@ public function testInformationSchemaTables() {
101101
),
102102
(array) $result[0]
103103
);
104+
105+
$result = $this->assertQuery( "SELECT
106+
table_name as 'name',
107+
engine AS 'engine',
108+
round( ( data_length / 1024 / 1024 ), 2 ) 'data'
109+
FROM INFORMATION_SCHEMA.TABLES
110+
WHERE TABLE_NAME = 'wp_posts'
111+
ORDER BY name ASC;"
112+
);
113+
114+
$this->assertEquals(
115+
array(
116+
'name' => 'wp_posts',
117+
'engine' => 'InnoDB',
118+
'data' => '0',
119+
),
120+
(array) $result[0]
121+
);
122+
}
123+
124+
public function testInformationSchemaQueryHidesSqliteSystemTables() {
125+
/**
126+
* By default, system tables are not returned.
127+
*/
128+
$result = $this->assertQuery( "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'sqlite_sequence'" );
129+
$this->assertEquals( 0, count( $result ) );
130+
131+
/**
132+
* If we use a custom name for the table_name column, system tables are returned.
133+
*/
134+
$result = $this->assertQuery( "SELECT TABLE_NAME as custom_name FROM INFORMATION_SCHEMA.TABLES WHERE custom_name = 'sqlite_sequence'" );
135+
$this->assertEquals( 1, count( $result ) );
104136
}
105137

106138
private function assertQuery( $sql, $error_substring = null ) {

wp-includes/sqlite/class-wp-sqlite-translator.php

Lines changed: 16 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1508,11 +1508,9 @@ private function execute_select() {
15081508
$updated_query = $this->rewriter->get_updated_query();
15091509

15101510
if ( $table_name && str_starts_with( strtolower( $table_name ), 'information_schema' ) ) {
1511-
// $this->is_information_schema_query = true;
1512-
// $updated_query = $this->get_information_schema_query( $updated_query );
1513-
// $params = array();
1514-
$updated_query = str_replace(
1515-
$table_name.'.tables',
1511+
$this->is_information_schema_query = true;
1512+
$updated_query = preg_replace(
1513+
'/'.$table_name.'\.tables/i',
15161514
"(SELECT
15171515
name as TABLE_NAME,
15181516
'database' as TABLE_SCHEMA,
@@ -2789,51 +2787,6 @@ private function translate_like_escape( $token ) {
27892787
return false;
27902788
}
27912789

2792-
/**
2793-
* Rewrite a query from the MySQL information_schema.
2794-
*
2795-
* @param string $updated_query The query to rewrite.
2796-
*
2797-
* @return string The query for use by SQLite
2798-
*/
2799-
private function get_information_schema_query( $updated_query ) {
2800-
// @TODO: Actually rewrite the columns.
2801-
$normalized_query = preg_replace( '/\s+/', ' ', strtolower( $updated_query ) );
2802-
if ( str_contains( $normalized_query, 'bytes' ) ) {
2803-
// Count rows per table.
2804-
$tables =
2805-
$this->execute_sqlite_query( "SELECT name as `table_name` FROM sqlite_master WHERE type='table' ORDER BY name" )->fetchAll();
2806-
$tables = $this->strip_sqlite_system_tables( $tables );
2807-
2808-
$rows = '(CASE ';
2809-
foreach ( $tables as $table ) {
2810-
$table_name = $table['table_name'];
2811-
$count = $this->execute_sqlite_query( "SELECT COUNT(1) as `count` FROM $table_name" )->fetch();
2812-
$rows .= " WHEN name = '$table_name' THEN {$count['count']} ";
2813-
}
2814-
$rows .= 'ELSE 0 END) ';
2815-
$updated_query =
2816-
"SELECT name as `table_name`, $rows as `rows`, 0 as `bytes` FROM sqlite_master WHERE type='table' ORDER BY name";
2817-
} elseif ( str_contains( $normalized_query, 'count(*)' ) && ! str_contains( $normalized_query, 'table_name =' ) ) {
2818-
// @TODO This is a guess that the caller wants a count of tables.
2819-
$list = array();
2820-
foreach ( $this->sqlite_system_tables as $system_table => $name ) {
2821-
$list [] = "'" . $system_table . "'";
2822-
}
2823-
$list = implode( ', ', $list );
2824-
$sql = "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name NOT IN ($list)";
2825-
$table_count = $this->execute_sqlite_query( $sql )->fetch();
2826-
$updated_query = 'SELECT ' . $table_count[0] . ' AS num';
2827-
2828-
$this->is_information_schema_query = false;
2829-
} else {
2830-
$updated_query =
2831-
"SELECT name as `table_name`, 'myisam' as `engine`, 0 as `data_length`, 0 as `index_length`, 0 as `data_free` FROM sqlite_master WHERE type='table' ORDER BY name";
2832-
}
2833-
2834-
return $updated_query;
2835-
}
2836-
28372790
/**
28382791
* Remove system table rows from resultsets of information_schema tables.
28392792
*
@@ -2846,19 +2799,20 @@ private function strip_sqlite_system_tables( $tables ) {
28462799
array_filter(
28472800
$tables,
28482801
function ( $table ) {
2849-
$table_name = false;
2850-
if ( is_array( $table ) ) {
2851-
if ( isset( $table['Name'] ) ) {
2852-
$table_name = $table['Name'];
2853-
} elseif ( isset( $table['table_name'] ) ) {
2854-
$table_name = $table['table_name'];
2855-
}
2856-
} elseif ( is_object( $table ) ) {
2857-
$table_name = property_exists( $table, 'Name' )
2858-
? $table->Name // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
2859-
: $table->table_name;
2802+
/**
2803+
* By default, we assume the table name is in the result set.
2804+
* Otherwise, if a information_schema table uses a custom name
2805+
* for the name/table_name column, the table would be removed.
2806+
*/
2807+
$table_name = true;
2808+
$table = (array) $table;
2809+
if ( isset( $table['Name'] ) ) {
2810+
$table_name = $table['Name'];
2811+
} elseif ( isset( $table['table_name'] ) ) {
2812+
$table_name = $table['table_name'];
2813+
} elseif ( isset( $table['TABLE_NAME'] ) ) {
2814+
$table_name = $table['TABLE_NAME'];
28602815
}
2861-
28622816
return $table_name && ! array_key_exists( $table_name, $this->sqlite_system_tables );
28632817
},
28642818
ARRAY_FILTER_USE_BOTH

0 commit comments

Comments
 (0)