@@ -125,11 +125,13 @@ private function get_existing_table_names(): array {
125
125
SELECT name
126
126
FROM sqlite_schema
127
127
WHERE type = 'table'
128
+ AND name != ?
128
129
AND name NOT LIKE ? ESCAPE '\'
129
130
AND name NOT LIKE ? ESCAPE '\'
130
131
ORDER BY name
131
132
" ,
132
133
array (
134
+ '_mysql_data_types_cache ' ,
133
135
'sqlite\_% ' ,
134
136
str_replace ( '_ ' , '\_ ' , WP_SQLite_Driver::RESERVED_PREFIX ) . '% ' ,
135
137
)
@@ -160,15 +162,15 @@ private function generate_create_table_statement( string $table_name ): string {
160
162
sprintf ( 'PRAGMA table_xinfo("%s") ' , $ table_name )
161
163
)->fetchAll ( PDO ::FETCH_ASSOC );
162
164
163
- $ definitions = array ();
164
- $ data_types = array ();
165
+ $ definitions = array ();
166
+ $ column_types = array ();
165
167
foreach ( $ columns as $ column ) {
166
168
$ mysql_type = $ this ->get_cached_mysql_data_type ( $ table_name , $ column ['name ' ] );
167
169
if ( null === $ mysql_type ) {
168
170
$ mysql_type = $ this ->get_mysql_data_type ( $ column ['type ' ] );
169
171
}
170
- $ definitions [] = $ this ->get_column_definition ( $ table_name , $ column );
171
- $ data_types [ $ column ['name ' ] ] = $ mysql_type ;
172
+ $ definitions [] = $ this ->get_column_definition ( $ table_name , $ column );
173
+ $ column_types [ $ column ['name ' ] ] = $ mysql_type ;
172
174
}
173
175
174
176
// Primary key.
@@ -199,18 +201,12 @@ private function generate_create_table_statement( string $table_name ): string {
199
201
)->fetchAll ( PDO ::FETCH_ASSOC );
200
202
201
203
foreach ( $ keys as $ key ) {
202
- $ key_columns = $ this ->driver ->execute_sqlite_query (
203
- 'SELECT * FROM pragma_index_info(" ' . $ key ['name ' ] . '") '
204
- )->fetchAll ( PDO ::FETCH_ASSOC );
205
-
206
- // If the PK columns are the same as the UK columns, skip the key.
207
- // This is because a primary key is already unique in MySQL.
208
- $ key_equals_pk = ! array_diff ( $ pk_columns , array_column ( $ key_columns , 'name ' ) );
209
- $ is_auto_index = strpos ( $ key ['name ' ], 'sqlite_autoindex_ ' ) === 0 ;
210
- if ( $ is_auto_index && $ key ['unique ' ] && $ key_equals_pk ) {
204
+ // Skip the internal index that SQLite may create for a primary key.
205
+ // In MySQL, no explicit index needs to be defined for a primary key.
206
+ if ( 'pk ' === $ key ['origin ' ] ) {
211
207
continue ;
212
208
}
213
- $ definitions [] = $ this ->get_key_definition ( $ key , $ key_columns , $ data_types );
209
+ $ definitions [] = $ this ->get_key_definition ( $ table_name , $ key , $ column_types );
214
210
}
215
211
216
212
return sprintf (
@@ -271,25 +267,52 @@ private function get_column_definition( string $table_name, array $column_info )
271
267
*
272
268
* This method generates a MySQL key definition from SQLite key data.
273
269
*
270
+ * @param string $table_name The name of the table.
274
271
* @param array $key The SQLite key information.
275
- * @param array $key_columns The SQLite key column information.
276
- * @param array $data_types The MySQL data types of the columns.
272
+ * @param array $column_type The MySQL data types of the columns.
277
273
* @return string The MySQL key definition.
278
274
*/
279
- private function get_key_definition ( array $ key , array $ key_columns , array $ data_types ): string {
280
- // Key definition.
275
+ private function get_key_definition ( string $ table_name , array $ key , array $ column_type ): string {
281
276
$ definition = array ();
282
- if ( $ key ['unique ' ] ) {
283
- $ definition [] = 'UNIQUE ' ;
277
+
278
+ // Key type.
279
+ $ cached_type = $ this ->get_cached_mysql_data_type ( $ table_name , $ key ['name ' ] );
280
+ if ( 'FULLTEXT ' === $ cached_type ) {
281
+ $ definition [] = 'FULLTEXT KEY ' ;
282
+ } elseif ( 'SPATIAL ' === $ cached_type ) {
283
+ $ definition [] = 'SPATIAL KEY ' ;
284
+ } elseif ( 'UNIQUE ' === $ cached_type || '1 ' === $ key ['unique ' ] ) {
285
+ $ definition [] = 'UNIQUE KEY ' ;
286
+ } else {
287
+ $ definition [] = 'KEY ' ;
288
+ }
289
+
290
+ // Key name.
291
+ $ name = $ key ['name ' ];
292
+
293
+ /*
294
+ * The SQLite driver prefixes index names with "{$table_name}__" to avoid
295
+ * naming conflicts among tables in SQLite. We need to remove the prefix.
296
+ */
297
+ if ( str_starts_with ( $ name , "{$ table_name }__ " ) ) {
298
+ $ name = substr ( $ name , strlen ( "{$ table_name }__ " ) );
284
299
}
285
- $ definition [] = 'KEY ' ;
286
300
287
- // Remove the prefix from the index name if there is any. We use __ as a separator.
288
- $ index_name = explode ( '__ ' , $ key ['name ' ], 2 )[1 ] ?? $ key ['name ' ];
289
- $ definition [] = $ this ->quote_sqlite_identifier ( $ index_name );
301
+ /**
302
+ * SQLite creates automatic internal indexes for primary and unique keys,
303
+ * naming them in format "sqlite_autoindex_{$table_name}_{$index_id}".
304
+ * For these internal indexes, we need to skip their name, so that in
305
+ * the generated MySQL definition, they follow implicit MySQL naming.
306
+ */
307
+ if ( ! str_starts_with ( $ name , 'sqlite_autoindex_ ' ) ) {
308
+ $ definition [] = $ this ->quote_sqlite_identifier ( $ name );
309
+ }
290
310
291
311
// Key columns.
292
- $ cols = array ();
312
+ $ key_columns = $ this ->driver ->execute_sqlite_query (
313
+ 'SELECT * FROM pragma_index_info(" ' . $ key ['name ' ] . '") '
314
+ )->fetchAll ( PDO ::FETCH_ASSOC );
315
+ $ cols = array ();
293
316
foreach ( $ key_columns as $ column ) {
294
317
/*
295
318
* Extract type and length from column data type definition.
@@ -299,7 +322,7 @@ private function get_key_definition( array $key, array $key_columns, array $data
299
322
* the format "type(length)", such as "varchar(255)".
300
323
*/
301
324
$ max_prefix_length = 100 ;
302
- $ type = strtolower ( $ data_types [ $ column ['name ' ] ] );
325
+ $ type = strtolower ( $ column_type [ $ column ['name ' ] ] );
303
326
$ parts = explode ( '( ' , $ type );
304
327
$ column_type = $ parts [0 ];
305
328
$ column_length = isset ( $ parts [1 ] ) ? (int ) $ parts [1 ] : null ;
@@ -362,6 +385,12 @@ private function column_has_default( string $mysql_type, ?string $default_value
362
385
* that was used by an old version of the SQLite driver and that is otherwise
363
386
* no longer needed. This is more precise than direct inference from SQLite.
364
387
*
388
+ * For columns, it returns full column type, including prefix length, e.g.:
389
+ * int(11), bigint(20) unsigned, varchar(255), longtext
390
+ *
391
+ * For indexes, it returns one of:
392
+ * KEY, PRIMARY, UNIQUE, FULLTEXT, SPATIAL
393
+ *
365
394
* @param string $table_name The table name.
366
395
* @param string $column_or_index_name The column or index name.
367
396
* @return string|null The MySQL definition, or null when not found.
@@ -378,6 +407,10 @@ private function get_cached_mysql_data_type( string $table_name, string $column_
378
407
}
379
408
throw $ e ;
380
409
}
410
+
411
+ // Normalize index type for backward compatibility. Some older versions
412
+ // of the SQLite driver stored index types with a " KEY" suffix, e.g.,
413
+ // "PRIMARY KEY" or "UNIQUE KEY". More recent versions omit the suffix.
381
414
if ( str_ends_with ( $ mysql_type , ' KEY ' ) ) {
382
415
$ mysql_type = substr ( $ mysql_type , 0 , strlen ( $ mysql_type ) - strlen ( ' KEY ' ) );
383
416
}
0 commit comments