get_results($wpdb->prepare( "SHOW INDEX FROM %i WHERE Key_name = %s", $tableName, $indexName )); return !empty($results); } /** * Add an index if it does not exist. * * @param string $indexName Index name * @param string|array $columns Column name(s) * @param bool $unique Whether the index is unique * @return void */ protected static function addIndexIfNotExists($indexName, $columns, $unique = false) { if (static::hasIndex($indexName)) { return; } $type = $unique ? 'UNIQUE INDEX' : 'INDEX'; if (is_array($columns)) { $colsSql = '`' . implode('`, `', $columns) . '`'; } else { $colsSql = "`{$columns}`"; } Schema::alterTable( static::$tableName, "ADD {$type} `{$indexName}` ({$colsSql})" ); } /** * Drop an index if it exists. * * @param string $indexName Index name * @return void */ protected static function dropIndexIfExists($indexName) { if (!static::hasIndex($indexName)) { return; } // Drop the index with a single direct ALTER rather than routing through // Schema::dropIndex(), which calls WP core drop_index(). That core helper // fires 25 speculative "DROP INDEX {name}_0".."_24" queries to clean up // stray dbDelta-created duplicates; none of those variants exist for our // explicitly-named indexes, so each one errors as "Can't DROP ..., check // that column/key exists" and floods migration/test output with noise. // hasIndex() above already confirmed the real index is present, so one // ALTER is sufficient. The %i placeholder mirrors hasIndex() and keeps // this safe on both MySQL and the WP SQLite integration. $wpdb = Schema::db(); $tableName = static::getTableName(); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared $wpdb->query($wpdb->prepare( "ALTER TABLE %i DROP INDEX %i", $tableName, $indexName )); } public static function getTableName(bool $withPrefix = true): string { return ($withPrefix ? static::getDbPrefix() : '') . static::$tableName; } public static function getDbPrefix(): string { global $wpdb; return $wpdb->prefix; } public static function getCharsetCollate(): string { global $wpdb; return $wpdb->get_charset_collate(); } public static function dropTable() { Schema::dropTableIfExists(static::getTableName(false)); } abstract public static function getSqlSchema(): string; }