@@ -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