diff --git a/.gitattributes b/.gitattributes index 5a8431e..bdd976d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,9 +5,10 @@ composer.json export-ignore phpcs.xml.dist export-ignore phpunit.xml.dist export-ignore +/.github export-ignore /grammar-tools export-ignore /tests export-ignore /wp-includes/mysql export-ignore /wp-includes/parser export-ignore /wp-includes/sqlite-ast export-ignore -wp-includes/sqlite/class-wp-sqlite-crosscheck-db.php export-ignore +/wp-includes/sqlite/class-wp-sqlite-crosscheck-db.php export-ignore diff --git a/load.php b/load.php index 73f89a6..2a3764f 100644 --- a/load.php +++ b/load.php @@ -3,7 +3,7 @@ * Plugin Name: SQLite Database Integration * Description: SQLite database driver drop-in. * Author: The WordPress Team - * Version: 2.1.15 + * Version: 2.1.16 * Requires PHP: 7.0 * Textdomain: sqlite-database-integration * diff --git a/readme.txt b/readme.txt index 70286c4..ee6f5a1 100644 --- a/readme.txt +++ b/readme.txt @@ -1,10 +1,10 @@ === SQLite Database Integration === -Contributors: wordpressdotorg, aristath +Contributors: wordpressdotorg, aristath, janjakes, zieladam, berislav.grgicak, bpayton, zaerl Requires at least: 6.4 Tested up to: 6.6.1 Requires PHP: 7.0 -Stable tag: 2.1.15 +Stable tag: 2.1.16 License: GPLv2 or later License URI: https://www.gnu.org/licenses/gpl-2.0.html Tags: performance, database diff --git a/tests/WP_SQLite_Translator_Tests.php b/tests/WP_SQLite_Translator_Tests.php index 20bc152..33fa9ad 100644 --- a/tests/WP_SQLite_Translator_Tests.php +++ b/tests/WP_SQLite_Translator_Tests.php @@ -267,8 +267,8 @@ public function testShowCreateTable1() { 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) + UNIQUE KEY option_name (option_name(100)), + KEY composite (option_name(100), option_value(100)) );" ); @@ -283,8 +283,49 @@ public function testShowCreateTable1() { `option_name` varchar(255) DEFAULT '', `option_value` text NOT NULL DEFAULT '', PRIMARY KEY (`ID`), - KEY `composite` (`option_name`, `option_value`), - UNIQUE KEY `option_name` (`option_name`) + KEY `composite` (`option_name`(100), `option_value`(100)), + UNIQUE KEY `option_name` (`option_name`(100)) +);", + $results[0]->{'Create Table'} + ); + } + + public function testShowCreateTableWithEmptyDatetimeDefault() { + $this->assertQuery( + "CREATE TABLE _tmp_table ( + ID BIGINT PRIMARY KEY AUTO_INCREMENT, + timestamp1 datetime NOT NULL, + timestamp2 date NOT NULL, + timestamp3 time NOT NULL, + timestamp4 timestamp NOT NULL, + timestamp5 year NOT NULL, + notempty1 datetime DEFAULT '1999-12-12 12:12:12', + notempty2 date DEFAULT '1999-12-12', + notempty3 time DEFAULT '12:12:12', + notempty4 year DEFAULT '2024', + notempty5 timestamp DEFAULT '1734539165', + );" + ); + + $this->assertQuery( + 'SHOW CREATE TABLE _tmp_table;' + ); + $results = $this->engine->get_query_results(); + + $this->assertEquals( + "CREATE TABLE `_tmp_table` ( + `ID` bigint AUTO_INCREMENT, + `timestamp1` datetime NOT NULL, + `timestamp2` date NOT NULL, + `timestamp3` time NOT NULL, + `timestamp4` timestamp NOT NULL, + `timestamp5` year NOT NULL, + `notempty1` datetime DEFAULT '1999-12-12 12:12:12', + `notempty2` date DEFAULT '1999-12-12', + `notempty3` time DEFAULT '12:12:12', + `notempty4` year DEFAULT '2024', + `notempty5` timestamp DEFAULT '1734539165', + PRIMARY KEY (`ID`) );", $results[0]->{'Create Table'} ); @@ -296,8 +337,8 @@ public function testShowCreateTableQuoted() { 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) + UNIQUE KEY option_name (option_name(100)), + KEY composite (option_name, option_value(100)) );" ); @@ -312,8 +353,8 @@ public function testShowCreateTableQuoted() { `option_name` varchar(255) DEFAULT '', `option_value` text NOT NULL DEFAULT '', PRIMARY KEY (`ID`), - KEY `composite` (`option_name`, `option_value`), - UNIQUE KEY `option_name` (`option_name`) + KEY `composite` (`option_name`(100), `option_value`(100)), + UNIQUE KEY `option_name` (`option_name`(100)) );", $results[0]->{'Create Table'} ); @@ -377,8 +418,8 @@ public function testCreateTablseWithIdenticalIndexNames() { ID BIGINT PRIMARY KEY AUTO_INCREMENT NOT NULL, option_name VARCHAR(255) default '', option_value TEXT NOT NULL, - KEY `option_name` (`option_name`), - KEY `double__underscores` (`option_name`, `ID`) + KEY `option_name` (`option_name`(100)), + KEY `double__underscores` (`option_name`(100), `ID`) );" ); @@ -387,8 +428,8 @@ public function testCreateTablseWithIdenticalIndexNames() { ID BIGINT PRIMARY KEY AUTO_INCREMENT NOT NULL, option_name VARCHAR(255) default '', option_value TEXT NOT NULL, - KEY `option_name` (`option_name`), - KEY `double__underscores` (`option_name`, `ID`) + KEY `option_name` (`option_name`(100)), + KEY `double__underscores` (`option_name`(100), `ID`) );" ); } @@ -399,8 +440,8 @@ public function testShowCreateTablePreservesDoubleUnderscoreKeyNames() { ID BIGINT PRIMARY KEY AUTO_INCREMENT NOT NULL, option_name VARCHAR(255) default '', option_value TEXT NOT NULL, - KEY `option_name` (`option_name`), - KEY `double__underscores` (`option_name`, `ID`) + KEY `option_name` (`option_name`(100)), + KEY `double__underscores` (`option_name`(100), `ID`) );" ); @@ -414,8 +455,43 @@ public function testShowCreateTablePreservesDoubleUnderscoreKeyNames() { `option_name` varchar(255) DEFAULT \'\', `option_value` text NOT NULL DEFAULT \'\', PRIMARY KEY (`ID`), - KEY `double__underscores` (`option_name`, `ID`), - KEY `option_name` (`option_name`) + KEY `double__underscores` (`option_name`(100), `ID`), + KEY `option_name` (`option_name`(100)) +);', + $results[0]->{'Create Table'} + ); + } + + public function testShowCreateTableLimitsKeyLengths() { + $this->assertQuery( + 'CREATE TABLE _tmp__table ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `order_id` bigint(20) unsigned DEFAULT NULL, + `meta_key` varchar(20) DEFAULT NULL, + `meta_value` text DEFAULT NULL, + `meta_data` mediumblob DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `meta_key_value` (`meta_key`(20),`meta_value`(82)), + KEY `order_id_meta_key_meta_value` (`order_id`,`meta_key`(100),`meta_value`(82)), + KEY `order_id_meta_key_meta_data` (`order_id`,`meta_key`(100),`meta_data`(100)) + );' + ); + + $this->assertQuery( + 'SHOW CREATE TABLE _tmp__table;' + ); + $results = $this->engine->get_query_results(); + $this->assertEquals( + 'CREATE TABLE `_tmp__table` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `order_id` bigint(20) unsigned DEFAULT NULL, + `meta_key` varchar(20) DEFAULT NULL, + `meta_value` text DEFAULT NULL, + `meta_data` mediumblob DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `order_id_meta_key_meta_data` (`order_id`, `meta_key`(20), `meta_data`(100)), + KEY `order_id_meta_key_meta_value` (`order_id`, `meta_key`(20), `meta_value`(100)), + KEY `meta_key_value` (`meta_key`(20), `meta_value`(100)) );', $results[0]->{'Create Table'} ); diff --git a/wp-includes/sqlite/class-wp-sqlite-translator.php b/wp-includes/sqlite/class-wp-sqlite-translator.php index 705b397..44996cd 100644 --- a/wp-includes/sqlite/class-wp-sqlite-translator.php +++ b/wp-includes/sqlite/class-wp-sqlite-translator.php @@ -3693,16 +3693,17 @@ protected function get_column_definitions( $table_name, $columns ) { $auto_increment_column = $this->get_autoincrement_column( $table_name ); $column_definitions = array(); foreach ( $columns as $column ) { + $mysql_type = $this->get_cached_mysql_data_type( $table_name, $column->name ); $is_auto_incr = $auto_increment_column && strtolower( $auto_increment_column ) === strtolower( $column->name ); $definition = array(); $definition[] = '`' . $column->name . '`'; - $definition[] = $this->get_cached_mysql_data_type( $table_name, $column->name ) ?? $column->name; + $definition[] = $mysql_type ?? $column->name; if ( '1' === $column->notnull ) { $definition[] = 'NOT NULL'; } - if ( null !== $column->dflt_value && '' !== $column->dflt_value && ! $is_auto_incr ) { + if ( $this->column_has_default( $column, $mysql_type ) && ! $is_auto_incr ) { $definition[] = 'DEFAULT ' . $column->dflt_value; } @@ -3724,7 +3725,8 @@ protected function get_column_definitions( $table_name, $columns ) { * @return array An array of key definitions */ private function get_key_definitions( $table_name, $columns ) { - $key_definitions = array(); + $key_length_limit = 100; + $key_definitions = array(); $pks = array(); foreach ( $columns as $column ) { @@ -3755,7 +3757,25 @@ private function get_key_definitions( $table_name, $columns ) { $key_definition[] = sprintf( '`%s`', $index_name ); $cols = array_map( - function ( $column ) { + function ( $column ) use ( $table_name, $key_length_limit ) { + $data_type = strtolower( $this->get_cached_mysql_data_type( $table_name, $column['name'] ) ); + $data_length = $key_length_limit; + + // Extract the length from the data type. Make it lower if needed. Skip 'unsigned' parts and whitespace. + if ( 1 === preg_match( '/^(\w+)\s*\(\s*(\d+)\s*\)/', $data_type, $matches ) ) { + $data_type = $matches[1]; // "varchar" + $data_length = min( $matches[2], $key_length_limit ); // "255" + } + + // Set the data length to the varchar and text key lengths + // char, varchar, varbinary, tinyblob, tinytext, blob, text, mediumblob, mediumtext, longblob, longtext + if ( str_ends_with( $data_type, 'char' ) || + str_ends_with( $data_type, 'text' ) || + str_ends_with( $data_type, 'blob' ) || + str_starts_with( $data_type, 'var' ) + ) { + return sprintf( '`%s`(%s)', $column['name'], $data_length ); + } return sprintf( '`%s`', $column['name'] ); }, $key['columns'] @@ -3858,6 +3878,33 @@ function ( $row ) use ( $name_map ) { ); } + /** + * Checks if column should define the default. + * + * @param stdClass $column The table column + * @param string $mysql_type The MySQL data type + * + * @return boolean If column should have a default definition. + */ + private function column_has_default( $column, $mysql_type ) { + if ( null === $column->dflt_value ) { + return false; + } + + if ( '' === $column->dflt_value ) { + return false; + } + + if ( + in_array( strtolower( $mysql_type ), array( 'datetime', 'date', 'time', 'timestamp', 'year' ), true ) && + "''" === $column->dflt_value + ) { + return false; + } + + return true; + } + /** * Consumes data types from the query. *