Skip to content

Commit

Permalink
Implement altering column with SET DEFAULT and DROP DEFAULT
Browse files Browse the repository at this point in the history
  • Loading branch information
JanJakes committed Aug 12, 2024
1 parent dd6bd6b commit 914f675
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 10 deletions.
57 changes: 57 additions & 0 deletions tests/WP_SQLite_Translator_Tests.php
Original file line number Diff line number Diff line change
Expand Up @@ -3048,6 +3048,63 @@ public function testCurrentTimestamp() {
$this->assertQuery( 'DELETE FROM _dates WHERE option_value = CURRENT_TIMESTAMP()' );
}


public function testAlterColumnSetAndDropDefault() {
$this->assertQuery(
'CREATE TABLE _tmp_table (
name varchar(20) NOT NULL
);'
);
$result = $this->assertQuery( 'DESCRIBE _tmp_table' );
$this->assertEquals(
array(
(object) array(
'Field' => 'name',
'Type' => 'varchar(20)',
'Null' => 'NO',
'Key' => '',
'Default' => '',
'Extra' => '',
),
),
$result
);

// SET DEFAULT
$this->assertQuery( "ALTER TABLE _tmp_table CHANGE name SET DEFAULT 'abc'" );
$result = $this->assertQuery( 'DESCRIBE _tmp_table' );
$this->assertEquals(
array(
(object) array(
'Field' => 'name',
'Type' => 'varchar(20)',
'Null' => 'NO',
'Key' => '',
'Default' => 'abc',
'Extra' => '',
),
),
$result
);

// DROP DEFAULT
$this->assertQuery( 'ALTER TABLE _tmp_table CHANGE name DROP DEFAULT' );
$result = $this->assertQuery( 'DESCRIBE _tmp_table' );
$this->assertEquals(
array(
(object) array(
'Field' => 'name',
'Type' => 'varchar(20)',
'Null' => 'NO',
'Key' => '',
'Default' => '',
'Extra' => '',
),
),
$result
);
}

/**
* @dataProvider mysqlVariablesToTest
*/
Expand Down
67 changes: 57 additions & 10 deletions wp-includes/sqlite/class-wp-sqlite-translator.php
Original file line number Diff line number Diff line change
Expand Up @@ -3053,16 +3053,31 @@ private function execute_alter() {
$this->rewriter->consume_all();
} elseif ( 'CHANGE' === $op_type ) {
// Parse the new column definition.
$raw_from_name = 'COLUMN' === $op_subject ? $this->rewriter->skip()->token : $op_raw_subject;
$from_name = $this->normalize_column_name( $raw_from_name );
$new_field = $this->parse_mysql_create_table_field();
$alter_terminator = end( $this->rewriter->output_tokens );
$this->update_data_type_cache(
$this->table_name,
$new_field->name,
$new_field->mysql_data_type
$raw_from_name = 'COLUMN' === $op_subject ? $this->rewriter->skip()->token : $op_raw_subject;
$from_name = $this->normalize_column_name( $raw_from_name );

$set_or_drop_default = $this->rewriter->peek()->matches(
WP_SQLite_Token::TYPE_KEYWORD,
WP_SQLite_Token::FLAG_KEYWORD_RESERVED,
array( 'SET', 'DROP' )
);

// Not all CHANGE statements have a new field definition (e.g, SET/DROP DEFAULT).
if ( $set_or_drop_default ) {
$new_field = null;
} else {
$new_field = $this->parse_mysql_create_table_field();
}

$alter_terminator = end( $this->rewriter->output_tokens );
if ( $new_field ) {
$this->update_data_type_cache(
$this->table_name,
$new_field->name,
$new_field->mysql_data_type
);
}

/*
* In SQLite, there is no direct equivalent to the CHANGE COLUMN
* statement from MySQL. We need to do a bit of work to emulate it.
Expand Down Expand Up @@ -3107,7 +3122,7 @@ private function execute_alter() {
WP_SQLite_Token::TYPE_KEYWORD,
WP_SQLite_Token::FLAG_KEYWORD_DATA_TYPE
);
if ( $is_column_definition ) {
if ( $new_field && $is_column_definition ) {
// Skip the old field definition.
$field_depth = $create_table->depth;
do {
Expand All @@ -3130,10 +3145,42 @@ private function execute_alter() {
// Otherwise, just add the new name in place of the old name we dropped.
$create_table->add(
new WP_SQLite_Token(
"`$new_field->name`",
'`' . ( $new_field ? $new_field->name : $from_name ) . '`',
WP_SQLite_Token::TYPE_KEYWORD
)
);

// Handle "CHANGE <column> DROP DEFAULT" and "CHANGE <column> SET DEFAULT <value>".
if ( $set_or_drop_default ) {
// 1. Drop "DEFAULT <value>" from old column definition.
$field_depth = $create_table->depth;
do {
$is_default = $create_table->peek()->matches(
WP_SQLite_Token::TYPE_KEYWORD,
WP_SQLite_Token::FLAG_KEYWORD_RESERVED,
array( 'DEFAULT' )
);
if ( $is_default ) {
$create_table->skip(); // DEFAULT
$create_table->skip(); // value
} else {
$create_table->consume();
}
} while (
! $this->is_create_table_field_terminator( $create_table->peek(), $field_depth, $create_table->depth )
);

// 2. For SET, add new "DEFAULT <value>" to column definition.
$keyword = $this->rewriter->consume();
if ( 'SET' === $keyword->value ) {
$terminator = $create_table->drop_last();
$create_table->add( new WP_SQLite_Token( ' ', WP_SQLite_Token::TYPE_WHITESPACE ) );
$create_table->add( $this->rewriter->consume() ); // DEFAULT
$create_table->add( new WP_SQLite_Token( ' ', WP_SQLite_Token::TYPE_WHITESPACE ) );
$create_table->add( $this->rewriter->consume() ); // value
$create_table->add( $terminator );
}
}
}
}

Expand Down

0 comments on commit 914f675

Please sign in to comment.