@@ -916,12 +916,12 @@ private function execute_create_table() {
916916 }
917917
918918 if ( count ( $ table ->primary_key ) > 1 ) {
919- $ definitions [] = 'PRIMARY KEY (" ' . implode ( '", " ' , $ table ->primary_key ) . '" ) ' ;
919+ $ definitions [] = 'PRIMARY KEY ( ' . implode ( ', ' , array_map ( array ( $ this , ' quote_identifier ' ), $ table ->primary_key ) ) . ') ' ;
920920 }
921921
922922 $ create_query = (
923923 $ table ->create_table .
924- ' " ' . $ table ->name . '" ( ' . "\n" .
924+ $ this -> quote_identifier ( $ table ->name ) . ' ( ' . "\n" .
925925 implode ( ", \n" , $ definitions ) .
926926 ') '
927927 );
@@ -940,7 +940,7 @@ private function execute_create_table() {
940940 }
941941 $ index_name = $ this ->generate_index_name ( $ table ->name , $ constraint ->name );
942942 $ this ->execute_sqlite_query (
943- " CREATE $ unique INDEX $ if_not_exists \" $ index_name\" ON \"{ $ table ->name }\" ( \"" . implode ( '", " ' , $ constraint ->columns ) . '" ) '
943+ ' CREATE ' . $ unique . ' INDEX ' . $ if_not_exists . ' ' . $ this -> quote_identifier ( $ index_name ) . ' ON ' . $ this -> quote_identifier ( $ table ->name ) . ' ( ' . implode ( ', ' , array_map ( array ( $ this , ' quote_identifier ' ), $ constraint ->columns ) ) . ') '
944944 );
945945 $ this ->update_data_type_cache (
946946 $ table ->name ,
@@ -1208,7 +1208,7 @@ private function parse_mysql_create_table_field() {
12081208 * @return string
12091209 */
12101210 private function make_sqlite_field_definition ( $ field ) {
1211- $ definition = ' " ' . $ field ->name . '" ' . $ field ->sqlite_data_type ;
1211+ $ definition = $ this -> quote_identifier ( $ field ->name ) . ' ' . $ field ->sqlite_data_type ;
12121212 if ( $ field ->auto_increment ) {
12131213 $ definition .= ' PRIMARY KEY AUTOINCREMENT ' ;
12141214 } elseif ( $ field ->primary_key ) {
@@ -1382,8 +1382,9 @@ private function execute_delete() {
13821382 // @TODO: Actually rewrite the query instead of using a hardcoded workaround.
13831383 if ( str_contains ( $ updated_query , ' JOIN ' ) ) {
13841384 $ table_prefix = isset ( $ GLOBALS ['table_prefix ' ] ) ? $ GLOBALS ['table_prefix ' ] : 'wp_ ' ;
1385+ $ quoted_table = $ this ->quote_identifier ( $ table_prefix . 'options ' );
13851386 $ this ->execute_sqlite_query (
1386- "DELETE FROM { $ table_prefix } options WHERE option_id IN (SELECT MIN(option_id) FROM { $ table_prefix } options GROUP BY option_name HAVING COUNT(*) > 1) "
1387+ "DELETE FROM $ quoted_table WHERE option_id IN (SELECT MIN(option_id) FROM $ quoted_table GROUP BY option_name HAVING COUNT(*) > 1) "
13871388 );
13881389 $ this ->set_result_from_affected_rows ();
13891390 return ;
@@ -1417,7 +1418,7 @@ private function execute_delete() {
14171418 // SELECT to fetch the IDs of the rows to delete, then delete them
14181419 // using a separate DELETE query.
14191420
1420- $ this ->table_name = $ rewriter ->skip ()->value ;
1421+ $ this ->table_name = $ this -> normalize_column_name ( $ rewriter ->skip ()->value ) ;
14211422 $ rewriter ->add ( new WP_SQLite_Token ( 'SELECT ' , WP_SQLite_Token::TYPE_KEYWORD , WP_SQLite_Token::FLAG_KEYWORD_RESERVED ) );
14221423
14231424 /*
@@ -1433,7 +1434,7 @@ private function execute_delete() {
14331434 for ( $ i = $ index + 1 ; $ i < $ rewriter ->max ; $ i ++ ) {
14341435 // Assume the table name is the first token after FROM.
14351436 if ( ! $ rewriter ->input_tokens [ $ i ]->is_semantically_void () ) {
1436- $ this ->table_name = $ rewriter ->input_tokens [ $ i ]->value ;
1437+ $ this ->table_name = $ this -> normalize_column_name ( $ rewriter ->input_tokens [ $ i ]->value ) ;
14371438 break ;
14381439 }
14391440 }
@@ -1445,7 +1446,7 @@ private function execute_delete() {
14451446 * Now, let's figure out the primary key name.
14461447 * This assumes that all listed table names are the same.
14471448 */
1448- $ q = $ this ->execute_sqlite_query ( 'SELECT l.name FROM pragma_table_info(" ' . $ this ->table_name . '" ) as l WHERE l.pk = 1; ' );
1449+ $ q = $ this ->execute_sqlite_query ( 'SELECT l.name FROM pragma_table_info( ' . $ this ->pdo -> quote ( $ this -> table_name ) . ') as l WHERE l.pk = 1; ' );
14491450 $ pk_name = $ q ->fetch ()['name ' ];
14501451
14511452 /*
@@ -1468,7 +1469,7 @@ private function execute_delete() {
14681469 $ rewriter ->add_many (
14691470 array (
14701471 new WP_SQLite_Token ( '. ' , WP_SQLite_Token::TYPE_OPERATOR , WP_SQLite_Token::FLAG_OPERATOR_SQL ),
1471- new WP_SQLite_Token ( $ pk_name , WP_SQLite_Token::TYPE_KEYWORD , WP_SQLite_Token::FLAG_KEYWORD_KEY ),
1472+ new WP_SQLite_Token ( $ this -> quote_identifier ( $ pk_name ) , WP_SQLite_Token::TYPE_KEYWORD , WP_SQLite_Token::FLAG_KEYWORD_KEY ),
14721473 new WP_SQLite_Token ( ' ' , WP_SQLite_Token::TYPE_WHITESPACE ),
14731474 new WP_SQLite_Token ( 'AS ' , WP_SQLite_Token::TYPE_KEYWORD , WP_SQLite_Token::FLAG_KEYWORD_RESERVED ),
14741475 new WP_SQLite_Token ( ' ' , WP_SQLite_Token::TYPE_WHITESPACE ),
@@ -1491,10 +1492,12 @@ private function execute_delete() {
14911492 $ ids_to_delete [] = $ id ['id_1 ' ];
14921493 }
14931494
1495+ $ quoted_table = $ this ->quote_identifier ( $ this ->table_name );
1496+ $ quoted_pk = $ this ->quote_identifier ( $ pk_name );
14941497 $ query = (
14951498 count ( $ ids_to_delete )
1496- ? "DELETE FROM {$ this -> table_name } WHERE {$ pk_name } IN ( " . implode ( ', ' , $ ids_to_delete ) . ') '
1497- : "DELETE FROM {$ this -> table_name } WHERE 0=1 "
1499+ ? "DELETE FROM {$ quoted_table } WHERE {$ quoted_pk } IN ( " . implode ( ', ' , $ ids_to_delete ) . ') '
1500+ : "DELETE FROM {$ quoted_table } WHERE 0=1 "
14981501 );
14991502 $ this ->execute_sqlite_query ( $ query );
15001503 $ this ->set_result_from_affected_rows (
@@ -1765,9 +1768,9 @@ private function describe( $table_name ) {
17651768 ELSE 'PRI'
17661769 END
17671770 ) as `Key`
1768- FROM pragma_table_info( \" $ table_name\ ") p
1771+ FROM pragma_table_info( " . $ this -> pdo -> quote ( $ table_name ) . ") p
17691772 LEFT JOIN " . self ::DATA_TYPES_CACHE_TABLE . " d
1770- ON d.`table` = \" $ table_name\ "
1773+ ON d.`table` = " . $ this -> pdo -> quote ( $ table_name ) . "
17711774 AND d.`column_or_index` = p.`name`
17721775 ;
17731776 "
@@ -1891,7 +1894,7 @@ private function preface_where_clause_with_a_subquery() {
18911894 new WP_SQLite_Token ( ' ' , WP_SQLite_Token::TYPE_WHITESPACE ),
18921895 new WP_SQLite_Token ( 'FROM ' , WP_SQLite_Token::TYPE_KEYWORD , WP_SQLite_Token::FLAG_KEYWORD_RESERVED ),
18931896 new WP_SQLite_Token ( ' ' , WP_SQLite_Token::TYPE_WHITESPACE ),
1894- new WP_SQLite_Token ( $ this ->table_name , WP_SQLite_Token::TYPE_KEYWORD , WP_SQLite_Token::FLAG_KEYWORD_RESERVED ),
1897+ new WP_SQLite_Token ( $ this ->quote_identifier ( $ this -> table_name ) , WP_SQLite_Token::TYPE_KEYWORD , WP_SQLite_Token::FLAG_KEYWORD_KEY ),
18951898 new WP_SQLite_Token ( ' ' , WP_SQLite_Token::TYPE_WHITESPACE ),
18961899 )
18971900 );
@@ -2955,7 +2958,7 @@ private function translate_on_duplicate_key( $table_name ) {
29552958 $ max = count ( $ conflict_columns );
29562959 $ i = 0 ;
29572960 foreach ( $ conflict_columns as $ conflict_column ) {
2958- $ this ->rewriter ->add ( new WP_SQLite_Token ( ' " ' . $ conflict_column . ' " ' , WP_SQLite_Token::TYPE_KEYWORD , WP_SQLite_Token::FLAG_KEYWORD_KEY ) );
2961+ $ this ->rewriter ->add ( new WP_SQLite_Token ( $ this -> quote_identifier ( $ conflict_column ) , WP_SQLite_Token::TYPE_KEYWORD , WP_SQLite_Token::FLAG_KEYWORD_KEY ) );
29592962 if ( ++$ i < $ max ) {
29602963 $ this ->rewriter ->add ( new WP_SQLite_Token ( ', ' , WP_SQLite_Token::TYPE_OPERATOR ) );
29612964 $ this ->rewriter ->add ( new WP_SQLite_Token ( ' ' , WP_SQLite_Token::TYPE_WHITESPACE ) );
@@ -2993,12 +2996,12 @@ private function get_primary_keys( $table_name ) {
29932996 * @return array
29942997 */
29952998 private function get_keys ( $ table_name , $ only_unique = false ) {
2996- $ query = $ this ->execute_sqlite_query ( 'SELECT * FROM pragma_index_list(" ' . $ table_name . '" ) as l; ' );
2999+ $ query = $ this ->execute_sqlite_query ( 'SELECT * FROM pragma_index_list( ' . $ this -> pdo -> quote ( $ table_name ) . ') as l; ' );
29973000 $ indices = $ query ->fetchAll ();
29983001 $ results = array ();
29993002 foreach ( $ indices as $ index ) {
30003003 if ( ! $ only_unique || '1 ' === $ index ['unique ' ] ) {
3001- $ query = $ this ->execute_sqlite_query ( 'SELECT * FROM pragma_index_info(" ' . $ index ['name ' ] . '" ) as l; ' );
3004+ $ query = $ this ->execute_sqlite_query ( 'SELECT * FROM pragma_index_info( ' . $ this -> pdo -> quote ( $ index ['name ' ] ) . ') as l; ' );
30023005 $ results [] = array (
30033006 'index ' => $ index ,
30043007 'columns ' => $ query ->fetchAll (),
@@ -3049,7 +3052,7 @@ private function execute_alter() {
30493052 new WP_SQLite_Token ( ' ' , WP_SQLite_Token::TYPE_WHITESPACE ),
30503053 new WP_SQLite_Token ( 'TABLE ' , WP_SQLite_Token::TYPE_KEYWORD ),
30513054 new WP_SQLite_Token ( ' ' , WP_SQLite_Token::TYPE_WHITESPACE ),
3052- new WP_SQLite_Token ( $ this ->table_name , WP_SQLite_Token::TYPE_KEYWORD ),
3055+ new WP_SQLite_Token ( $ this ->quote_identifier ( $ this -> table_name ) , WP_SQLite_Token::TYPE_KEYWORD , WP_SQLite_Token:: FLAG_KEYWORD_KEY ),
30533056 )
30543057 );
30553058 $ op_type = strtoupper ( $ this ->rewriter ->consume ()->token ?? '' );
@@ -3153,7 +3156,7 @@ private function execute_alter() {
31533156
31543157 // Drop ON UPDATE trigger by the old column name.
31553158 $ on_update_trigger_name = $ this ->get_column_on_update_current_timestamp_trigger_name ( $ this ->table_name , $ from_name );
3156- $ this ->execute_sqlite_query ( " DROP TRIGGER IF EXISTS \" $ on_update_trigger_name\"" );
3159+ $ this ->execute_sqlite_query ( ' DROP TRIGGER IF EXISTS ' . $ this -> quote_identifier ( $ on_update_trigger_name ) );
31573160
31583161 /*
31593162 * In SQLite, there is no direct equivalent to the CHANGE COLUMN
@@ -3186,7 +3189,7 @@ private function execute_alter() {
31863189 if ( ! $ token ) {
31873190 break ;
31883191 }
3189- if ( WP_SQLite_Token::TYPE_STRING !== $ token ->type
3192+ if ( ( WP_SQLite_Token::TYPE_STRING !== $ token ->type && WP_SQLite_Token:: TYPE_SYMBOL !== $ token -> type )
31903193 || $ from_name !== $ this ->normalize_column_name ( $ token ->value ) ) {
31913194 continue ;
31923195 }
@@ -3222,30 +3225,33 @@ private function execute_alter() {
32223225 // Otherwise, just add the new name in place of the old name we dropped.
32233226 $ create_table ->add (
32243227 new WP_SQLite_Token (
3225- "` $ new_field ->name ` " ,
3226- WP_SQLite_Token::TYPE_KEYWORD
3228+ $ this ->quote_identifier ( $ new_field ->name ),
3229+ WP_SQLite_Token::TYPE_KEYWORD ,
3230+ WP_SQLite_Token::FLAG_KEYWORD_KEY
32273231 )
32283232 );
32293233 }
32303234 }
32313235
32323236 // 3. Copy the data out of the old table
32333237 $ cache_table_name = "_tmp__ {$ this ->table_name }_ " . rand ( 10000000 , 99999999 );
3238+ $ quoted_cache_table = $ this ->quote_identifier ( $ cache_table_name );
3239+ $ quoted_table = $ this ->quote_identifier ( $ this ->table_name );
32343240 $ this ->execute_sqlite_query (
3235- "CREATE TABLE ` $ cache_table_name ` as SELECT * FROM ` $ this -> table_name ` "
3241+ "CREATE TABLE $ quoted_cache_table as SELECT * FROM $ quoted_table "
32363242 );
32373243
32383244 // 4. Drop the old table to free up the indexes names
3239- $ this ->execute_sqlite_query ( "DROP TABLE ` $ this -> table_name ` " );
3245+ $ this ->execute_sqlite_query ( "DROP TABLE $ quoted_table " );
32403246
32413247 // 5. Create a new table from the updated schema
32423248 $ this ->execute_sqlite_query ( $ create_table ->get_updated_query () );
32433249
32443250 // 6. Copy the data from step 3 to the new table
3245- $ this ->execute_sqlite_query ( "INSERT INTO { $ this -> table_name } SELECT * FROM $ cache_table_name " );
3251+ $ this ->execute_sqlite_query ( "INSERT INTO $ quoted_table SELECT * FROM $ quoted_cache_table " );
32463252
32473253 // 7. Drop the old table copy
3248- $ this ->execute_sqlite_query ( "DROP TABLE ` $ cache_table_name ` " );
3254+ $ this ->execute_sqlite_query ( "DROP TABLE $ quoted_cache_table " );
32493255
32503256 // 8. Restore any indexes that were dropped in step 4
32513257 foreach ( $ old_indexes as $ row ) {
@@ -3260,8 +3266,8 @@ private function execute_alter() {
32603266 $ columns = array ();
32613267 foreach ( $ row ['columns ' ] as $ column ) {
32623268 $ columns [] = ( $ column ['name ' ] === $ from_name )
3263- ? ' ` ' . $ new_field ->name . ' ` '
3264- : ' ` ' . $ column ['name ' ] . ' ` ' ;
3269+ ? $ this -> quote_identifier ( $ new_field ->name )
3270+ : $ this -> quote_identifier ( $ column ['name ' ] ) ;
32653271 }
32663272
32673273 $ unique = '1 ' === $ row ['index ' ]['unique ' ] ? 'UNIQUE ' : '' ;
@@ -3271,7 +3277,7 @@ private function execute_alter() {
32713277 * a part of the CREATE TABLE statement
32723278 */
32733279 $ this ->execute_sqlite_query (
3274- "CREATE $ unique INDEX IF NOT EXISTS ` { $ row ['index ' ]['name ' ]} ` ON $ this -> table_name ( " . implode ( ', ' , $ columns ) . ') '
3280+ "CREATE $ unique INDEX IF NOT EXISTS " . $ this -> quote_identifier ( $ row ['index ' ]['name ' ] ) . " ON $ quoted_table ( " . implode ( ', ' , $ columns ) . ') '
32753281 );
32763282 }
32773283
@@ -3300,11 +3306,11 @@ private function execute_alter() {
33003306 new WP_SQLite_Token ( ' ' , WP_SQLite_Token::TYPE_WHITESPACE ),
33013307 new WP_SQLite_Token ( $ sqlite_index_type , WP_SQLite_Token::TYPE_KEYWORD , WP_SQLite_Token::FLAG_KEYWORD_RESERVED ),
33023308 new WP_SQLite_Token ( ' ' , WP_SQLite_Token::TYPE_WHITESPACE ),
3303- new WP_SQLite_Token ( "\" $ sqlite_index_name\"" , WP_SQLite_Token::TYPE_KEYWORD , WP_SQLite_Token::FLAG_KEYWORD_KEY ),
3309+ new WP_SQLite_Token ( $ this -> quote_identifier ( $ sqlite_index_name ) , WP_SQLite_Token::TYPE_KEYWORD , WP_SQLite_Token::FLAG_KEYWORD_KEY ),
33043310 new WP_SQLite_Token ( ' ' , WP_SQLite_Token::TYPE_WHITESPACE ),
33053311 new WP_SQLite_Token ( 'ON ' , WP_SQLite_Token::TYPE_KEYWORD , WP_SQLite_Token::FLAG_KEYWORD_RESERVED ),
33063312 new WP_SQLite_Token ( ' ' , WP_SQLite_Token::TYPE_WHITESPACE ),
3307- new WP_SQLite_Token ( "\" $ this ->table_name \"" , WP_SQLite_Token::TYPE_STRING , WP_SQLite_Token::FLAG_STRING_DOUBLE_QUOTES ),
3313+ new WP_SQLite_Token ( $ this ->quote_identifier ( $ this -> table_name ) , WP_SQLite_Token::TYPE_KEYWORD , WP_SQLite_Token::FLAG_KEYWORD_KEY ),
33083314 new WP_SQLite_Token ( ' ' , WP_SQLite_Token::TYPE_WHITESPACE ),
33093315 new WP_SQLite_Token ( '( ' , WP_SQLite_Token::TYPE_OPERATOR ),
33103316 )
@@ -3332,8 +3338,8 @@ private function execute_alter() {
33323338 }
33333339 // $token is field name.
33343340 if ( ! $ token ->matches ( WP_SQLite_Token::TYPE_OPERATOR ) ) {
3335- $ token ->token = ' ` ' . $ this ->normalize_column_name ( $ token ->token ) . ' ` ' ;
3336- $ token ->value = ' ` ' . $ this -> normalize_column_name ( $ token ->token ) . ' ` ' ;
3341+ $ token ->token = $ this -> quote_identifier ( $ this ->normalize_column_name ( $ token ->token ) ) ;
3342+ $ token ->value = $ token ->token ;
33373343 }
33383344
33393345 /*
@@ -3358,7 +3364,7 @@ private function execute_alter() {
33583364 new WP_SQLite_Token ( ' ' , WP_SQLite_Token::TYPE_WHITESPACE ),
33593365 new WP_SQLite_Token ( 'INDEX ' , WP_SQLite_Token::TYPE_KEYWORD , WP_SQLite_Token::FLAG_KEYWORD_RESERVED ),
33603366 new WP_SQLite_Token ( ' ' , WP_SQLite_Token::TYPE_WHITESPACE ),
3361- new WP_SQLite_Token ( "\"{ $ this ->table_name } __ $ key_name\"" , WP_SQLite_Token::TYPE_KEYWORD , WP_SQLite_Token::FLAG_KEYWORD_KEY ),
3367+ new WP_SQLite_Token ( $ this ->quote_identifier ( $ this -> table_name . ' __ ' . $ key_name ) , WP_SQLite_Token::TYPE_KEYWORD , WP_SQLite_Token::FLAG_KEYWORD_KEY ),
33623368 )
33633369 );
33643370 } else {
@@ -3618,7 +3624,7 @@ private function execute_show() {
36183624 $ tables = $ this ->strip_sqlite_system_tables ( $ stmt ->fetchAll ( $ this ->pdo_fetch_mode ) );
36193625 foreach ( $ tables as $ table ) {
36203626 $ table_name = $ table ->Name ; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
3621- $ stmt = $ this ->execute_sqlite_query ( " SELECT COUNT(1) as `Rows` FROM $ table_name" );
3627+ $ stmt = $ this ->execute_sqlite_query ( ' SELECT COUNT(1) as `Rows` FROM ' . $ this -> quote_identifier ( $ table_name ) );
36223628 $ rows = $ stmt ->fetchall ( $ this ->pdo_fetch_mode );
36233629 $ table ->Rows = $ rows [0 ]->Rows ; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
36243630 }
@@ -3710,7 +3716,7 @@ private function generate_create_statement() {
37103716 * @return stdClass[]
37113717 */
37123718 protected function get_table_columns ( $ table_name ) {
3713- return $ this ->execute_sqlite_query ( " PRAGMA table_info( \" $ table_name\" ); " )
3719+ return $ this ->execute_sqlite_query ( ' PRAGMA table_info( ' . $ this -> pdo -> quote ( $ table_name ) . ' ); ' )
37143720 ->fetchAll ( $ this ->pdo_fetch_mode );
37153721 }
37163722
@@ -3729,7 +3735,7 @@ protected function get_column_definitions( $table_name, $columns ) {
37293735 $ mysql_type = $ this ->get_cached_mysql_data_type ( $ table_name , $ column ->name );
37303736 $ is_auto_incr = $ auto_increment_column && strtolower ( $ auto_increment_column ) === strtolower ( $ column ->name );
37313737 $ definition = array ();
3732- $ definition [] = ' ` ' . $ column ->name . ' ` ' ;
3738+ $ definition [] = $ this -> quote_identifier ( $ column ->name ) ;
37333739 $ definition [] = $ mysql_type ?? $ column ->name ;
37343740
37353741 if ( '1 ' === $ column ->notnull ) {
@@ -3787,7 +3793,7 @@ private function get_key_definitions( $table_name, $columns ) {
37873793 // Remove the prefix from the index name if there is any. We use __ as a separator.
37883794 $ index_name = explode ( '__ ' , $ key ['index ' ]['name ' ], 2 )[1 ] ?? $ key ['index ' ]['name ' ];
37893795
3790- $ key_definition [] = sprintf ( ' `%s` ' , $ index_name );
3796+ $ key_definition [] = $ this -> quote_identifier ( $ index_name );
37913797
37923798 $ cols = array_map (
37933799 function ( $ column ) use ( $ table_name , $ key_length_limit ) {
@@ -3807,9 +3813,9 @@ function ( $column ) use ( $table_name, $key_length_limit ) {
38073813 str_ends_with ( $ data_type , 'blob ' ) ||
38083814 str_starts_with ( $ data_type , 'var ' )
38093815 ) {
3810- return sprintf ( ' `%s`(%s) ' , $ column ['name ' ], $ data_length ) ;
3816+ return $ this -> quote_identifier ( $ column ['name ' ] ) . ' ( ' . $ data_length . ' ) ' ;
38113817 }
3812- return sprintf ( ' `%s` ' , $ column ['name ' ] );
3818+ return $ this -> quote_identifier ( $ column ['name ' ] );
38133819 },
38143820 $ key ['columns ' ]
38153821 );
@@ -3842,7 +3848,7 @@ function ( $a, $b ) {
38423848
38433849 foreach ( $ columns as $ column ) {
38443850 if ( '0 ' !== $ column ->pk ) {
3845- $ primary_keys [] = sprintf ( ' `%s` ' , $ column ->name );
3851+ $ primary_keys [] = $ this -> quote_identifier ( $ column ->name );
38463852 }
38473853 }
38483854
@@ -3860,7 +3866,7 @@ function ( $a, $b ) {
38603866 */
38613867 private function get_autoincrement_column ( $ table_name ) {
38623868 preg_match (
3863- '/" ([^"]+)" \s+integer\s+primary\s+key\s+autoincrement/i ' ,
3869+ '/[`"] ([^` "]+)[`"] \s+integer\s+primary\s+key\s+autoincrement/i ' ,
38643870 $ this ->get_sqlite_create_table ( $ table_name ),
38653871 $ matches
38663872 );
@@ -4050,6 +4056,21 @@ private function normalize_column_name( $column_name ) {
40504056 return trim ( $ column_name , '` \'" ' );
40514057 }
40524058
4059+ /**
4060+ * Quotes an identifier for safe use in SQLite queries.
4061+ *
4062+ * Wraps the identifier in backticks and escapes any internal backticks
4063+ * by doubling them. This ensures identifiers with special characters
4064+ * are properly escaped in the target SQLite query context.
4065+ *
4066+ * @param string $identifier The unquoted identifier.
4067+ *
4068+ * @return string The properly quoted identifier.
4069+ */
4070+ private function quote_identifier ( $ identifier ) {
4071+ return '` ' . str_replace ( '` ' , '`` ' , $ identifier ) . '` ' ;
4072+ }
4073+
40534074 /**
40544075 * Normalizes an index type.
40554076 *
@@ -4487,12 +4508,15 @@ private function add_column_on_update_current_timestamp( $table, $column ) {
44874508 // The trigger wouldn't work for virtual and "WITHOUT ROWID" tables,
44884509 // but currently that can't happen as we're not creating such tables.
44894510 // See: https://www.sqlite.org/rowidtable.html
4511+ $ quoted_trigger = $ this ->quote_identifier ( $ trigger_name );
4512+ $ quoted_table = $ this ->quote_identifier ( $ table );
4513+ $ quoted_column = $ this ->quote_identifier ( $ column );
44904514 $ this ->execute_sqlite_query (
4491- "CREATE TRIGGER \" $ trigger_name \"
4492- AFTER UPDATE ON \" $ table \"
4515+ "CREATE TRIGGER $ quoted_trigger
4516+ AFTER UPDATE ON $ quoted_table
44934517 FOR EACH ROW
44944518 BEGIN
4495- UPDATE \" $ table \" SET \" $ column \" = CURRENT_TIMESTAMP WHERE rowid = NEW.rowid;
4519+ UPDATE $ quoted_table SET $ quoted_column = CURRENT_TIMESTAMP WHERE rowid = NEW.rowid;
44964520 END "
44974521 );
44984522 }
0 commit comments