Skip to content

Commit 914f675

Browse files
committed
Implement altering column with SET DEFAULT and DROP DEFAULT
1 parent dd6bd6b commit 914f675

File tree

2 files changed

+114
-10
lines changed

2 files changed

+114
-10
lines changed

tests/WP_SQLite_Translator_Tests.php

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3048,6 +3048,63 @@ public function testCurrentTimestamp() {
30483048
$this->assertQuery( 'DELETE FROM _dates WHERE option_value = CURRENT_TIMESTAMP()' );
30493049
}
30503050

3051+
3052+
public function testAlterColumnSetAndDropDefault() {
3053+
$this->assertQuery(
3054+
'CREATE TABLE _tmp_table (
3055+
name varchar(20) NOT NULL
3056+
);'
3057+
);
3058+
$result = $this->assertQuery( 'DESCRIBE _tmp_table' );
3059+
$this->assertEquals(
3060+
array(
3061+
(object) array(
3062+
'Field' => 'name',
3063+
'Type' => 'varchar(20)',
3064+
'Null' => 'NO',
3065+
'Key' => '',
3066+
'Default' => '',
3067+
'Extra' => '',
3068+
),
3069+
),
3070+
$result
3071+
);
3072+
3073+
// SET DEFAULT
3074+
$this->assertQuery( "ALTER TABLE _tmp_table CHANGE name SET DEFAULT 'abc'" );
3075+
$result = $this->assertQuery( 'DESCRIBE _tmp_table' );
3076+
$this->assertEquals(
3077+
array(
3078+
(object) array(
3079+
'Field' => 'name',
3080+
'Type' => 'varchar(20)',
3081+
'Null' => 'NO',
3082+
'Key' => '',
3083+
'Default' => 'abc',
3084+
'Extra' => '',
3085+
),
3086+
),
3087+
$result
3088+
);
3089+
3090+
// DROP DEFAULT
3091+
$this->assertQuery( 'ALTER TABLE _tmp_table CHANGE name DROP DEFAULT' );
3092+
$result = $this->assertQuery( 'DESCRIBE _tmp_table' );
3093+
$this->assertEquals(
3094+
array(
3095+
(object) array(
3096+
'Field' => 'name',
3097+
'Type' => 'varchar(20)',
3098+
'Null' => 'NO',
3099+
'Key' => '',
3100+
'Default' => '',
3101+
'Extra' => '',
3102+
),
3103+
),
3104+
$result
3105+
);
3106+
}
3107+
30513108
/**
30523109
* @dataProvider mysqlVariablesToTest
30533110
*/

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

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3053,16 +3053,31 @@ private function execute_alter() {
30533053
$this->rewriter->consume_all();
30543054
} elseif ( 'CHANGE' === $op_type ) {
30553055
// Parse the new column definition.
3056-
$raw_from_name = 'COLUMN' === $op_subject ? $this->rewriter->skip()->token : $op_raw_subject;
3057-
$from_name = $this->normalize_column_name( $raw_from_name );
3058-
$new_field = $this->parse_mysql_create_table_field();
3059-
$alter_terminator = end( $this->rewriter->output_tokens );
3060-
$this->update_data_type_cache(
3061-
$this->table_name,
3062-
$new_field->name,
3063-
$new_field->mysql_data_type
3056+
$raw_from_name = 'COLUMN' === $op_subject ? $this->rewriter->skip()->token : $op_raw_subject;
3057+
$from_name = $this->normalize_column_name( $raw_from_name );
3058+
3059+
$set_or_drop_default = $this->rewriter->peek()->matches(
3060+
WP_SQLite_Token::TYPE_KEYWORD,
3061+
WP_SQLite_Token::FLAG_KEYWORD_RESERVED,
3062+
array( 'SET', 'DROP' )
30643063
);
30653064

3065+
// Not all CHANGE statements have a new field definition (e.g, SET/DROP DEFAULT).
3066+
if ( $set_or_drop_default ) {
3067+
$new_field = null;
3068+
} else {
3069+
$new_field = $this->parse_mysql_create_table_field();
3070+
}
3071+
3072+
$alter_terminator = end( $this->rewriter->output_tokens );
3073+
if ( $new_field ) {
3074+
$this->update_data_type_cache(
3075+
$this->table_name,
3076+
$new_field->name,
3077+
$new_field->mysql_data_type
3078+
);
3079+
}
3080+
30663081
/*
30673082
* In SQLite, there is no direct equivalent to the CHANGE COLUMN
30683083
* statement from MySQL. We need to do a bit of work to emulate it.
@@ -3107,7 +3122,7 @@ private function execute_alter() {
31073122
WP_SQLite_Token::TYPE_KEYWORD,
31083123
WP_SQLite_Token::FLAG_KEYWORD_DATA_TYPE
31093124
);
3110-
if ( $is_column_definition ) {
3125+
if ( $new_field && $is_column_definition ) {
31113126
// Skip the old field definition.
31123127
$field_depth = $create_table->depth;
31133128
do {
@@ -3130,10 +3145,42 @@ private function execute_alter() {
31303145
// Otherwise, just add the new name in place of the old name we dropped.
31313146
$create_table->add(
31323147
new WP_SQLite_Token(
3133-
"`$new_field->name`",
3148+
'`' . ( $new_field ? $new_field->name : $from_name ) . '`',
31343149
WP_SQLite_Token::TYPE_KEYWORD
31353150
)
31363151
);
3152+
3153+
// Handle "CHANGE <column> DROP DEFAULT" and "CHANGE <column> SET DEFAULT <value>".
3154+
if ( $set_or_drop_default ) {
3155+
// 1. Drop "DEFAULT <value>" from old column definition.
3156+
$field_depth = $create_table->depth;
3157+
do {
3158+
$is_default = $create_table->peek()->matches(
3159+
WP_SQLite_Token::TYPE_KEYWORD,
3160+
WP_SQLite_Token::FLAG_KEYWORD_RESERVED,
3161+
array( 'DEFAULT' )
3162+
);
3163+
if ( $is_default ) {
3164+
$create_table->skip(); // DEFAULT
3165+
$create_table->skip(); // value
3166+
} else {
3167+
$create_table->consume();
3168+
}
3169+
} while (
3170+
! $this->is_create_table_field_terminator( $create_table->peek(), $field_depth, $create_table->depth )
3171+
);
3172+
3173+
// 2. For SET, add new "DEFAULT <value>" to column definition.
3174+
$keyword = $this->rewriter->consume();
3175+
if ( 'SET' === $keyword->value ) {
3176+
$terminator = $create_table->drop_last();
3177+
$create_table->add( new WP_SQLite_Token( ' ', WP_SQLite_Token::TYPE_WHITESPACE ) );
3178+
$create_table->add( $this->rewriter->consume() ); // DEFAULT
3179+
$create_table->add( new WP_SQLite_Token( ' ', WP_SQLite_Token::TYPE_WHITESPACE ) );
3180+
$create_table->add( $this->rewriter->consume() ); // value
3181+
$create_table->add( $terminator );
3182+
}
3183+
}
31373184
}
31383185
}
31393186

0 commit comments

Comments
 (0)