@@ -125,11 +125,13 @@ private function get_existing_table_names(): array {
125125 SELECT name
126126 FROM sqlite_schema
127127 WHERE type = 'table'
128+ AND name != ?
128129 AND name NOT LIKE ? ESCAPE '\'
129130 AND name NOT LIKE ? ESCAPE '\'
130131 ORDER BY name
131132 " ,
132133 array (
134+ '_mysql_data_types_cache ' ,
133135 'sqlite\_% ' ,
134136 str_replace ( '_ ' , '\_ ' , WP_SQLite_Driver::RESERVED_PREFIX ) . '% ' ,
135137 )
@@ -160,15 +162,15 @@ private function generate_create_table_statement( string $table_name ): string {
160162 sprintf ( 'PRAGMA table_xinfo("%s") ' , $ table_name )
161163 )->fetchAll ( PDO ::FETCH_ASSOC );
162164
163- $ definitions = array ();
164- $ data_types = array ();
165+ $ definitions = array ();
166+ $ column_types = array ();
165167 foreach ( $ columns as $ column ) {
166168 $ mysql_type = $ this ->get_cached_mysql_data_type ( $ table_name , $ column ['name ' ] );
167169 if ( null === $ mysql_type ) {
168170 $ mysql_type = $ this ->get_mysql_data_type ( $ column ['type ' ] );
169171 }
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 ;
172174 }
173175
174176 // Primary key.
@@ -199,18 +201,12 @@ private function generate_create_table_statement( string $table_name ): string {
199201 )->fetchAll ( PDO ::FETCH_ASSOC );
200202
201203 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 ' ] ) {
211207 continue ;
212208 }
213- $ definitions [] = $ this ->get_key_definition ( $ key , $ key_columns , $ data_types );
209+ $ definitions [] = $ this ->get_key_definition ( $ table_name , $ key , $ column_types );
214210 }
215211
216212 return sprintf (
@@ -271,25 +267,52 @@ private function get_column_definition( string $table_name, array $column_info )
271267 *
272268 * This method generates a MySQL key definition from SQLite key data.
273269 *
274- * @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.
277- * @return string The MySQL key definition.
270+ * @param string $table_name The name of the table .
271+ * @param array $key The SQLite key information.
272+ * @param array $column_types The MySQL data types of the columns.
273+ * @return string The MySQL key definition.
278274 */
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_types ): string {
281276 $ 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 ' ;
284288 }
285- $ definition [] = 'KEY ' ;
286289
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 );
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 }__ " ) );
299+ }
300+
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+ }
290310
291311 // 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 ();
293316 foreach ( $ key_columns as $ column ) {
294317 /*
295318 * 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
299322 * the format "type(length)", such as "varchar(255)".
300323 */
301324 $ max_prefix_length = 100 ;
302- $ type = strtolower ( $ data_types [ $ column ['name ' ] ] );
325+ $ type = strtolower ( $ column_types [ $ column ['name ' ] ] );
303326 $ parts = explode ( '( ' , $ type );
304327 $ column_type = $ parts [0 ];
305328 $ column_length = isset ( $ parts [1 ] ) ? (int ) $ parts [1 ] : null ;
@@ -362,6 +385,12 @@ private function column_has_default( string $mysql_type, ?string $default_value
362385 * that was used by an old version of the SQLite driver and that is otherwise
363386 * no longer needed. This is more precise than direct inference from SQLite.
364387 *
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+ *
365394 * @param string $table_name The table name.
366395 * @param string $column_or_index_name The column or index name.
367396 * @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_
378407 }
379408 throw $ e ;
380409 }
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.
381414 if ( str_ends_with ( $ mysql_type , ' KEY ' ) ) {
382415 $ mysql_type = substr ( $ mysql_type , 0 , strlen ( $ mysql_type ) - strlen ( ' KEY ' ) );
383416 }
0 commit comments