From d24fff8e58b8dc232c72d8cac78a4c8ac283dd86 Mon Sep 17 00:00:00 2001 From: Jeroen P Date: Thu, 18 Jul 2024 17:34:53 +0700 Subject: [PATCH] Support multi-value column type modifiers for `_mysql_data_types_cache` (#126) Fixes: #122 This fix will skip over tokens until it finds the closing bracket of the type modifier `)` instead of consuming exactly 3. This should account for data types that support more than one value as a modifier, such as: enum, float, decimal, double. Additionally, I've added support for enums. There are plugins that use enum fields and it makes sense to convert those to text in SQLite. ## Testing instructions Confirm the tests pass --- tests/WP_SQLite_Translator_Tests.php | 54 +++++++++++++++++++ .../sqlite/class-wp-sqlite-translator.php | 15 ++++-- 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/tests/WP_SQLite_Translator_Tests.php b/tests/WP_SQLite_Translator_Tests.php index 7a334eeb..1dba2a86 100644 --- a/tests/WP_SQLite_Translator_Tests.php +++ b/tests/WP_SQLite_Translator_Tests.php @@ -704,6 +704,60 @@ public function testCreateTableSpatialIndex() { $this->assertEquals( 1, $result ); } + public function testCreateTableWithMultiValueColumnTypeModifiers() { + $result = $this->assertQuery( + "CREATE TABLE wptests_users ( + ID bigint(20) unsigned NOT NULL auto_increment, + decimal_column DECIMAL(10,2) NOT NULL DEFAULT 0, + float_column FLOAT(10,2) NOT NULL DEFAULT 0, + enum_column ENUM('a', 'b', 'c') NOT NULL DEFAULT 'a', + PRIMARY KEY (ID), + )" + ); + $this->assertEquals( '', $this->engine->get_error_message() ); + $this->assertEquals( 1, $result ); + + $this->assertQuery( 'DESCRIBE wptests_users;' ); + $results = $this->engine->get_query_results(); + $this->assertEquals( + array( + (object) array( + 'Field' => 'ID', + 'Type' => 'bigint(20) unsigned', + 'Null' => 'NO', + 'Key' => 'PRI', + 'Default' => '0', + 'Extra' => '', + ), + (object) array( + 'Field' => 'decimal_column', + 'Type' => 'decimal(10,2)', + 'Null' => 'NO', + 'Key' => '', + 'Default' => 0, + 'Extra' => '', + ), + (object) array( + 'Field' => 'float_column', + 'Type' => 'float(10,2)', + 'Null' => 'NO', + 'Key' => '', + 'Default' => 0, + 'Extra' => '', + ), + (object) array( + 'Field' => 'enum_column', + 'Type' => "enum('a','b','c')", + 'Null' => 'NO', + 'Key' => '', + 'Default' => 'a', + 'Extra' => '', + ), + ), + $results + ); + } + public function testAlterTableAddColumn() { $result = $this->assertQuery( "CREATE TABLE _tmp_table ( diff --git a/wp-includes/sqlite/class-wp-sqlite-translator.php b/wp-includes/sqlite/class-wp-sqlite-translator.php index ac6a170c..7b227b28 100644 --- a/wp-includes/sqlite/class-wp-sqlite-translator.php +++ b/wp-includes/sqlite/class-wp-sqlite-translator.php @@ -65,6 +65,7 @@ class WP_SQLite_Translator { 'double' => 'real', 'decimal' => 'real', 'dec' => 'real', + 'enum' => 'text', 'numeric' => 'real', 'fixed' => 'real', 'date' => 'text', @@ -3556,12 +3557,18 @@ private function skip_mysql_data_type() { $sqlite_data_type = $this->field_types_translation[ $mysql_data_type ]; - // Skip the length, e.g. (10) in VARCHAR(10). + // Skip the type modifier, e.g. (20) for varchar(20) or (10,2) for decimal(10,2). $paren_maybe = $this->rewriter->peek(); if ( $paren_maybe && '(' === $paren_maybe->token ) { - $mysql_data_type .= $this->rewriter->skip()->token; - $mysql_data_type .= $this->rewriter->skip()->token; - $mysql_data_type .= $this->rewriter->skip()->token; + $mysql_data_type .= $this->rewriter->skip()->token; // Skip '(' and add it to the data type + + // Loop to capture everything until the closing parenthesis ')' + while ( $token = $this->rewriter->skip() ) { + $mysql_data_type .= $token->token; + if ( ')' === $token->token ) { + break; + } + } } // Skip the int keyword.