prefix . 'abientot_' . $name; } public static function definitions(): array { return array( 'import_batches' => array( 'batch_uuid' => 'char(36)', 'actor_id' => 'bigint unsigned', 'command_hash' => 'char(64)', 'file_digest' => 'char(64)', 'mapping_json' => 'longtext', 'revision_hash' => 'char(64)', 'kind' => 'varchar(20)', 'state' => 'varchar(20)', 'created_at' => 'datetime', 'updated_at' => 'datetime' ), 'import_rows' => array( 'batch_uuid' => 'char(36)', 'ordinal' => 'int unsigned', 'source_hash' => 'char(64)', 'normalized_hash' => 'char(64)', 'state' => 'varchar(20)', 'ownership_json' => 'longtext' ) ); } public static function verified(): bool { global $wpdb; $suppression = $wpdb->suppress_errors( true );try { foreach ( self::definitions() as $name => $expected ) { $actual = array(); foreach ( Db::rows( $wpdb->suppress_errors( true ), $wpdb->get_results( $wpdb->prepare( 'SHOW COLUMNS FROM %i', self::table( $name ) ), ARRAY_A ), 'import_storage' ) as $column ) { if ( $column['Null'] !== 'NO' || $column['Extra'] !== '' ) { return false; } $actual[ $column['Field'] ] = preg_replace( '/\b(bigint|int)\(\d+\)/', '$1', strtolower( $column['Type'] ) ); } if ( $actual !== $expected ) { return false; } $keys = array(); foreach ( Db::rows( $wpdb->suppress_errors( true ), $wpdb->get_results( $wpdb->prepare( 'SHOW INDEX FROM %i', self::table( $name ) ), ARRAY_A ), 'import_storage' ) as $key ) { if ( ! in_array( $key['Key_name'], $name === 'import_rows' ? array( 'PRIMARY', 'source_hash' ) : array( 'PRIMARY' ), true ) || (int) $key['Non_unique'] !== 0 || ! empty( $key['Sub_part'] ) ) { return false; } if ( $key['Key_name'] === 'PRIMARY' ) { $keys[ (int) $key['Seq_in_index'] ] = $key['Column_name']; } elseif ( $key['Column_name'] !== 'source_hash' || (int) $key['Seq_in_index'] !== 1 ) { return false; } } if ( $name === 'import_rows' && count( Db::rows( $wpdb->suppress_errors( true ), $wpdb->get_results( $wpdb->prepare( 'SHOW INDEX FROM %i', self::table( $name ) ), ARRAY_A ), 'import_storage' ) ) !== 3 ) { return false; } ksort( $keys ); if ( array_values( $keys ) !== ( $name === 'import_rows' ? array( 'batch_uuid', 'ordinal' ) : array( 'batch_uuid' ) ) ) { return false; } } foreach ( array( 'import_batches', 'import_rows', 'customers', 'services', 'appointments', 'staff_services' ) as $name ) { $rows = Db::rows( $wpdb->suppress_errors( true ), $wpdb->get_results( $wpdb->prepare( 'SELECT ENGINE FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=%s', self::table( $name ) ), ARRAY_A ), 'import_storage' ); if ( strtoupper( $rows[0]['ENGINE'] ?? '' ) !== 'INNODB' ) { return false; } } return true; } catch ( \Throwable $error ) { return false; } finally { $wpdb->suppress_errors( $suppression ); } } public static function ensure(): bool { global $wpdb; $owned = ! BookingLock::is_held(); if ( $owned && ! BookingLock::acquire() ) { return false; } $suppression = $wpdb->suppress_errors( true );try { $marker = get_option( self::OPTION, '' ); if ( ! in_array( $marker, array( '', self::VERSION ), true ) ) { return false; } TransactionGuard::prepare_write(); foreach ( self::definitions() as $name => $columns ) { $exists = Db::rows( $wpdb->suppress_errors( true ), $wpdb->get_results( $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->esc_like( self::table( $name ) ) ), ARRAY_A ), 'import_storage' ); if ( ! $exists ) { if ( $marker !== '' ) { return false; } if ( $name === 'import_rows' ) { $created = $wpdb->query( "CREATE TABLE {$wpdb->prefix}abientot_import_rows (batch_uuid char(36) NOT NULL,ordinal int unsigned NOT NULL,source_hash char(64) NOT NULL,normalized_hash char(64) NOT NULL,state varchar(20) NOT NULL,ownership_json longtext NOT NULL,PRIMARY KEY(batch_uuid,ordinal),UNIQUE KEY source_hash(source_hash)) ENGINE=InnoDB " . $wpdb->get_charset_collate() ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.SchemaChange -- Fixed DDL from the WordPress prefix and collation. } else { $created = $wpdb->query( "CREATE TABLE {$wpdb->prefix}abientot_import_batches (batch_uuid char(36) NOT NULL,actor_id bigint unsigned NOT NULL,command_hash char(64) NOT NULL,file_digest char(64) NOT NULL,mapping_json longtext NOT NULL,revision_hash char(64) NOT NULL,kind varchar(20) NOT NULL,state varchar(20) NOT NULL,created_at datetime NOT NULL,updated_at datetime NOT NULL,PRIMARY KEY(batch_uuid)) ENGINE=InnoDB " . $wpdb->get_charset_collate() ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.SchemaChange -- Fixed DDL from the WordPress prefix and collation. } if ( false === $created ) { return false; } } } if ( ! self::verified() ) { return false; } if ( $marker !== self::VERSION ) { update_option( self::OPTION, self::VERSION, false ); } return get_option( self::OPTION ) === self::VERSION; } catch ( \Throwable $error ) { return false; } finally { $wpdb->suppress_errors( $suppression ); if ( $owned ) { BookingLock::release(); } } } }