Skip to content

Commit 50d0bd2

Browse files
committed
Fix column default value handling
1 parent 3cbb647 commit 50d0bd2

File tree

3 files changed

+101
-19
lines changed

3 files changed

+101
-19
lines changed

tests/WP_SQLite_Driver_Tests.php

+31-5
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,7 @@ public function testShowCreateTableWithCorrectDefaultValues() {
476476
'CREATE TABLE `_tmp__table` (
477477
`ID` bigint NOT NULL AUTO_INCREMENT,
478478
`default_empty_string` varchar(255) DEFAULT \'\',
479-
`null_no_default` varchar(255),
479+
`null_no_default` varchar(255) DEFAULT NULL,
480480
PRIMARY KEY (`ID`)
481481
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci',
482482
$results[0]->{'Create Table'}
@@ -1954,7 +1954,7 @@ public function testAlterTableModifyColumnWithHyphens() {
19541954
'Type' => 'text',
19551955
'Null' => 'YES',
19561956
'Key' => '',
1957-
'Default' => 'NULL',
1957+
'Default' => null,
19581958
'Extra' => '',
19591959
),
19601960
),
@@ -3405,7 +3405,7 @@ public function testUniqueConstraints() {
34053405
public function testDefaultNullValue() {
34063406
$this->assertQuery(
34073407
'CREATE TABLE _tmp_table (
3408-
name varchar(20) NOT NULL default NULL,
3408+
name varchar(20) default NULL,
34093409
no_default varchar(20) NOT NULL
34103410
);'
34113411
);
@@ -3418,9 +3418,9 @@ public function testDefaultNullValue() {
34183418
(object) array(
34193419
'Field' => 'name',
34203420
'Type' => 'varchar(20)',
3421-
'Null' => 'NO',
3421+
'Null' => 'YES',
34223422
'Key' => '',
3423-
'Default' => 'NULL',
3423+
'Default' => null,
34243424
'Extra' => '',
34253425
),
34263426
(object) array(
@@ -3639,4 +3639,30 @@ public function testNullCharactersInStrings(): void {
36393639
$this->engine->get_query_results()
36403640
);
36413641
}
3642+
3643+
public function testColumnDefaults(): void {
3644+
$this->assertQuery(
3645+
"
3646+
CREATE TABLE t (
3647+
name varchar(255) DEFAULT 'CURRENT_TIMESTAMP',
3648+
type varchar(255) NOT NULL DEFAULT 'DEFAULT',
3649+
description varchar(250) NOT NULL DEFAULT '',
3650+
created_at timestamp DEFAULT CURRENT_TIMESTAMP,
3651+
updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
3652+
)
3653+
"
3654+
);
3655+
3656+
$result = $this->assertQuery( 'SHOW CREATE TABLE t' );
3657+
$this->assertEquals(
3658+
"CREATE TABLE `t` (\n"
3659+
. " `name` varchar(255) DEFAULT 'CURRENT_TIMESTAMP',\n"
3660+
. " `type` varchar(255) NOT NULL DEFAULT 'DEFAULT',\n"
3661+
. " `description` varchar(250) NOT NULL DEFAULT '',\n"
3662+
. " `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,\n"
3663+
. " `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP\n"
3664+
. ') ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci',
3665+
$result[0]->{'Create Table'}
3666+
);
3667+
}
36423668
}

wp-includes/sqlite-ast/class-wp-sqlite-driver.php

+32-4
Original file line numberDiff line numberDiff line change
@@ -2181,8 +2181,18 @@ private function get_sqlite_create_table_statement( string $table_name, ?string
21812181
$query .= ' PRIMARY KEY AUTOINCREMENT';
21822182
}
21832183
if ( null !== $column['COLUMN_DEFAULT'] ) {
2184-
// @TODO: Correctly quote based on the data type.
2185-
$query .= ' DEFAULT ' . $this->pdo->quote( $column['COLUMN_DEFAULT'] );
2184+
// @TODO: Handle defaults with expression values (DEFAULT_GENERATED).
2185+
2186+
// Handle DEFAULT CURRENT_TIMESTAMP. This works only with timestamp
2187+
// and datetime columns. For other column types, it's just a string.
2188+
if (
2189+
'CURRENT_TIMESTAMP' === $column['COLUMN_DEFAULT']
2190+
&& ( 'timestamp' === $column['DATA_TYPE'] || 'datetime' === $column['DATA_TYPE'] )
2191+
) {
2192+
$query .= ' DEFAULT CURRENT_TIMESTAMP';
2193+
} else {
2194+
$query .= ' DEFAULT ' . $this->pdo->quote( $column['COLUMN_DEFAULT'] );
2195+
}
21862196
}
21872197
$rows[] = $query;
21882198

@@ -2300,14 +2310,32 @@ private function get_mysql_create_table_statement( string $table_name ): ?string
23002310
$sql .= ' ' . $column['COLUMN_TYPE'];
23012311
if ( 'NO' === $column['IS_NULLABLE'] ) {
23022312
$sql .= ' NOT NULL';
2313+
} elseif ( 'timestamp' === $column['COLUMN_TYPE'] ) {
2314+
// Nullable "timestamp" columns dump NULL explicitly.
2315+
$sql .= ' NULL';
23032316
}
23042317
if ( 'auto_increment' === $column['EXTRA'] ) {
23052318
$sql .= ' AUTO_INCREMENT';
23062319
}
2307-
if ( null !== $column['COLUMN_DEFAULT'] ) {
2308-
// @TODO: Correctly quote based on the data type.
2320+
2321+
// Handle DEFAULT CURRENT_TIMESTAMP. This works only with timestamp
2322+
// and datetime columns. For other column types, it's just a string.
2323+
if (
2324+
'CURRENT_TIMESTAMP' === $column['COLUMN_DEFAULT']
2325+
&& ( 'timestamp' === $column['DATA_TYPE'] || 'datetime' === $column['DATA_TYPE'] )
2326+
) {
2327+
$sql .= ' DEFAULT CURRENT_TIMESTAMP';
2328+
} elseif ( null !== $column['COLUMN_DEFAULT'] ) {
23092329
$sql .= ' DEFAULT ' . $this->pdo->quote( $column['COLUMN_DEFAULT'] );
2330+
} elseif ( 'YES' === $column['IS_NULLABLE'] ) {
2331+
$sql .= ' DEFAULT NULL';
23102332
}
2333+
2334+
// Handle ON UPDATE CURRENT_TIMESTAMP.
2335+
if ( str_contains( $column['EXTRA'], 'on update CURRENT_TIMESTAMP' ) ) {
2336+
$sql .= ' ON UPDATE CURRENT_TIMESTAMP';
2337+
}
2338+
23112339
$rows[] = $sql;
23122340
}
23132341

wp-includes/sqlite-ast/class-wp-sqlite-information-schema-builder.php

+38-10
Original file line numberDiff line numberDiff line change
@@ -905,14 +905,31 @@ private function get_table_collation( WP_Parser_Node $node ): string {
905905
}
906906

907907
private function get_column_default( WP_Parser_Node $node ): ?string {
908+
$default_attr = null;
908909
foreach ( $node->get_descendant_nodes( 'columnAttribute' ) as $attr ) {
909910
if ( $attr->has_child_token( WP_MySQL_Lexer::DEFAULT_SYMBOL ) ) {
910-
// @TODO: MySQL seems to normalize default values for numeric
911-
// columns, such as 1.0 to 1, 1e3 to 1000, etc.
912-
return substr( $this->get_value( $attr ), strlen( 'DEFAULT' ) );
911+
$default_attr = $attr;
913912
}
914913
}
915-
return null;
914+
915+
if ( null === $default_attr ) {
916+
return null;
917+
}
918+
919+
if ( $default_attr->has_child_token( WP_MySQL_Lexer::NOW_SYMBOL ) ) {
920+
return 'CURRENT_TIMESTAMP';
921+
}
922+
923+
if (
924+
$default_attr->has_child_node( 'signedLiteral' )
925+
&& null !== $default_attr->get_descendant_node( 'nullLiteral' )
926+
) {
927+
return null;
928+
}
929+
930+
// @TODO: MySQL seems to normalize default values for numeric
931+
// columns, such as 1.0 to 1, 1e3 to 1000, etc.
932+
return $this->get_value( $default_attr->get_child_node() );
916933
}
917934

918935
private function get_column_nullable( WP_Parser_Node $node ): string {
@@ -967,32 +984,43 @@ private function get_column_key( WP_Parser_Node $column_node ): string {
967984
}
968985

969986
private function get_column_extra( WP_Parser_Node $node ): string {
970-
$extra = '';
987+
$extras = array();
988+
$attributes = $node->get_descendant_nodes( 'columnAttribute' );
971989

972990
// SERIAL
973991
$data_type = $node->get_descendant_node( 'dataType' );
974992
if ( null !== $data_type->get_descendant_token( WP_MySQL_Lexer::SERIAL_SYMBOL ) ) {
975993
return 'auto_increment';
976994
}
977995

978-
foreach ( $node->get_descendant_nodes( 'columnAttribute' ) as $attr ) {
996+
// Check whether DEFAULT value is an expression.
997+
foreach ( $attributes as $attr ) {
998+
if (
999+
$attr->has_child_token( WP_MySQL_Lexer::DEFAULT_SYMBOL )
1000+
&& $attr->has_child_node( 'exprWithParentheses' )
1001+
) {
1002+
$extras[] = 'DEFAULT_GENERATED';
1003+
}
1004+
}
1005+
1006+
foreach ( $attributes as $attr ) {
9791007
if ( $attr->has_child_token( WP_MySQL_Lexer::AUTO_INCREMENT_SYMBOL ) ) {
9801008
return 'auto_increment';
9811009
}
9821010
if (
9831011
$attr->has_child_token( WP_MySQL_Lexer::ON_SYMBOL )
9841012
&& $attr->has_child_token( WP_MySQL_Lexer::UPDATE_SYMBOL )
9851013
) {
986-
return 'on update CURRENT_TIMESTAMP';
1014+
$extras[] = 'on update CURRENT_TIMESTAMP';
9871015
}
9881016
}
9891017

9901018
if ( $node->get_descendant_token( WP_MySQL_Lexer::VIRTUAL_SYMBOL ) ) {
991-
$extra = 'VIRTUAL GENERATED';
1019+
$extras[] = 'VIRTUAL GENERATED';
9921020
} elseif ( $node->get_descendant_token( WP_MySQL_Lexer::STORED_SYMBOL ) ) {
993-
$extra = 'STORED GENERATED';
1021+
$extras[] = 'STORED GENERATED';
9941022
}
995-
return $extra;
1023+
return implode( ' ', $extras );
9961024
}
9971025

9981026
private function get_column_comment( WP_Parser_Node $node ): string {

0 commit comments

Comments
 (0)