From ff09e42b40fb65e46aa6f6eb2729d2f5be378b16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Zieli=C5=84ski?= Date: Thu, 6 Jun 2024 01:25:17 +0200 Subject: [PATCH] Bugfixes in SHOW CREATE TABLE and SHOW TABLES (#117) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes a series of crashes encountered when * SHOW TABLES now returns a flat list, not an array of objects – I'm not sure here. It makes `$tables = $wpdb->get_results("SHOW TABLES LIKE '{$prefix}%'", ARRAY_N);` work as expected [here](https://github.com/WordPress/playground-tools/blob/128123e84e25cf0421770f6885c6f26aaf0b05dc/packages/playground/src/playground-db.php#L90-L91), but is the right thing to return, or is this more about correct handling of the fetch mode, like ARRAY_N? * `SHOW tables` isn't all uppercase * There's no table tho SHOW CREATE: `SHOW CREATE TABLE _no_such_table;` * The table identifier passed to SHOW CREATE is quoted: ``` 'SHOW CREATETABLE `_tmp_table`;' ``` This PR makes the [Sandbox site plugin](https://wordpress.org/plugins/playground/) work in Playground cc @bgrgicak @brandonpayton @wojtekn --- tests/WP_SQLite_Translator_Tests.php | 40 +++++++++++++++++-- .../sqlite/class-wp-sqlite-translator.php | 25 +++++++++--- 2 files changed, 57 insertions(+), 8 deletions(-) diff --git a/tests/WP_SQLite_Translator_Tests.php b/tests/WP_SQLite_Translator_Tests.php index f0b7251..b5a65ff 100644 --- a/tests/WP_SQLite_Translator_Tests.php +++ b/tests/WP_SQLite_Translator_Tests.php @@ -253,6 +253,14 @@ public function testSelectFromDual() { $this->assertEquals( 1, $result[0]->output ); } + public function testShowCreateTableNotFound() { + $this->assertQuery( + 'SHOW CREATE TABLE _no_such_table;' + ); + $results = $this->engine->get_query_results(); + $this->assertCount( 0, $results ); + } + public function testShowCreateTable1() { $this->assertQuery( "CREATE TABLE _tmp_table ( @@ -281,6 +289,34 @@ public function testShowCreateTable1() { ); } + public function testShowCreateTableQuoted() { + $this->assertQuery( + "CREATE TABLE _tmp_table ( + ID BIGINT PRIMARY KEY AUTO_INCREMENT NOT NULL, + option_name VARCHAR(255) default '', + option_value TEXT NOT NULL, + UNIQUE KEY option_name (option_name), + KEY composite (option_name, option_value) + );" + ); + + $this->assertQuery( + 'SHOW CREATE TABLE `_tmp_table`;' + ); + $results = $this->engine->get_query_results(); + # TODO: Should we fix mismatch with original `option_value` text NOT NULL,` without default? + $this->assertEquals( + "CREATE TABLE _tmp_table ( + `ID` bigint PRIMARY KEY AUTO_INCREMENT NOT NULL, + `option_name` varchar(255) DEFAULT '', + `option_value` text NOT NULL DEFAULT '', + KEY _tmp_table__composite (option_name, option_value), + UNIQUE KEY _tmp_table__option_name (option_name) +);", + $results[0]->{'Create Table'} + ); + } + public function testShowCreateTableSimpleTable() { $this->assertQuery( 'CREATE TABLE _tmp_table ( @@ -417,9 +453,7 @@ public function testShowTablesLike() { ); $this->assertEquals( array( - (object) array( - 'Tables_in_db' => '_tmp_table', - ), + '_tmp_table', ), $this->engine->get_query_results() ); diff --git a/wp-includes/sqlite/class-wp-sqlite-translator.php b/wp-includes/sqlite/class-wp-sqlite-translator.php index 0558842..7f4b85f 100644 --- a/wp-includes/sqlite/class-wp-sqlite-translator.php +++ b/wp-includes/sqlite/class-wp-sqlite-translator.php @@ -3238,8 +3238,8 @@ private function execute_drop() { */ private function execute_show() { $this->rewriter->skip(); - $what1 = $this->rewriter->consume()->token; - $what2 = $this->rewriter->consume()->token; + $what1 = strtoupper( $this->rewriter->consume()->token ); + $what2 = strtoupper( $this->rewriter->consume()->token ); $what = $what1 . ' ' . $what2; switch ( $what ) { case 'CREATE PROCEDURE': @@ -3338,10 +3338,18 @@ private function execute_show() { return; case 'CREATE TABLE': - $table_name = $this->rewriter->consume()->token; + // Value is unquoted table name + $table_name = $this->rewriter->consume()->value; $columns = $this->get_columns_from( $table_name ); $keys = $this->get_keys( $table_name ); + if ( empty( $columns ) ) { + $this->set_results_from_fetched_data( + array() + ); + return; + } + foreach ( $columns as $column ) { $column = (array) $column; $definition = ''; @@ -3452,8 +3460,12 @@ private function execute_show() { ':param' => $table_expression->value, ) ); + $this->set_results_from_fetched_data( - $stmt->fetchAll( $this->pdo_fetch_mode ) + array_column( + $stmt->fetchAll( $this->pdo_fetch_mode ), + 'Tables_in_db' + ) ); return; @@ -3464,7 +3476,10 @@ private function execute_show() { "SELECT name FROM sqlite_master WHERE type='table'" ); $this->set_results_from_fetched_data( - $stmt->fetchAll( $this->pdo_fetch_mode ) + array_column( + $stmt->fetchAll( $this->pdo_fetch_mode ), + 'Tables_in_db' + ) ); return;