Skip to content

WIP migration script #1

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Draft
wants to merge 4 commits into
base: develop
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 2 additions & 24 deletions activate.php
Original file line number Diff line number Diff line change
@@ -84,29 +84,7 @@ function sqlite_plugin_copy_db_file() {

// Place database drop-in if not present yet, except in case there is
// another database drop-in present already.
if ( ! defined( 'SQLITE_DB_DROPIN_VERSION' ) && ! file_exists( $destination ) ) {
// Init the filesystem to allow copying the file.
global $wp_filesystem;

require_once ABSPATH . '/wp-admin/includes/file.php';

// Init the filesystem if needed, then copy the file, replacing contents as needed.
if ( ( $wp_filesystem || WP_Filesystem() ) && $wp_filesystem->touch( $destination ) ) {

// Get the db.copy.php file contents, replace placeholders and write it to the destination.
$file_contents = str_replace(
array(
'{SQLITE_IMPLEMENTATION_FOLDER_PATH}',
'{SQLITE_PLUGIN}',
),
array(
__DIR__,
str_replace( WP_PLUGIN_DIR . '/', '', SQLITE_MAIN_FILE ),
),
file_get_contents( __DIR__ . '/db.copy' )
);

$wp_filesystem->put_contents( $destination, $file_contents );
}
if ( ! defined( 'SQLITE_DROPIN' ) && ! file_exists( $destination ) ) {
@symlink( __DIR__ . '/wp-content/db.php', $destination ); // phpcs:ignore
}
}
8 changes: 4 additions & 4 deletions admin-notices.php
Original file line number Diff line number Diff line change
@@ -29,18 +29,18 @@ function sqlite_plugin_admin_notice() {
}

/*
* If the SQLITE_DB_DROPIN_VERSION constant is not defined
* If the SQLITE_DROPIN constant is not defined
* but there's a db.php file in the wp-content directory, then the module can't be activated.
* The module should not have been activated in the first place
* (there's a check in the can-load.php file), but this is a fallback check.
*/
if ( file_exists( WP_CONTENT_DIR . '/db.php' ) && ! defined( 'SQLITE_DB_DROPIN_VERSION' ) ) {
if ( file_exists( WP_CONTENT_DIR . '/db.php' ) && ! defined( 'SQLITE_DROPIN' ) ) {
printf(
'<div class="notice notice-error"><p>%s</p></div>',
sprintf(
/* translators: 1: SQLITE_DB_DROPIN_VERSION constant, 2: db.php drop-in path */
/* translators: 1: SQLITE_DROPIN constant, 2: db.php drop-in path */
__( 'The SQLite Integration module is active, but the %1$s constant is missing. It appears you already have another %2$s file present on your site. ', 'sqlite-database-integration' ),
'<code>SQLITE_DB_DROPIN_VERSION</code>',
'<code>SQLITE_DROPIN</code>',
'<code>' . esc_html( basename( WP_CONTENT_DIR ) ) . '/db.php</code>'
)
);
43 changes: 12 additions & 31 deletions admin-page.php
Original file line number Diff line number Diff line change
@@ -32,7 +32,7 @@ function sqlite_integration_admin_screen() {
</div>
<!-- Set the wrapper width to 50em, to improve readability. -->
<div style="max-width:50em;">
<?php if ( defined( 'SQLITE_DB_DROPIN_VERSION' ) ) : ?>
<?php if ( defined( 'SQLITE_DROPIN' ) ) : ?>
<div class="notice notice-success">
<p><?php esc_html_e( 'SQLite is enabled.', 'sqlite-database-integration' ); ?></p>
</div>
@@ -55,41 +55,18 @@ function sqlite_integration_admin_screen() {
<div class="notice notice-error">
<p><?php esc_html_e( 'We detected that the PDO SQLite driver is missing from your server (the pdo_sqlite extension is not loaded). Please make sure that SQLite is enabled in your PHP installation before proceeding.', 'sqlite-database-integration' ); ?></p>
</div>
<?php elseif ( file_exists( WP_CONTENT_DIR . '/db.php' ) && ! defined( 'SQLITE_DB_DROPIN_VERSION' ) ) : ?>
<?php if ( defined( 'PERFLAB_SQLITE_DB_DROPIN_VERSION' ) ) : ?>
<div class="notice notice-warning">
<p>
<?php
printf(
/* translators: %s: db.php drop-in path */
esc_html__( 'An older %s file was detected. Please click the button below to update the file.', 'sqlite-database-integration' ),
'<code>' . esc_html( basename( WP_CONTENT_DIR ) ) . '/db.php</code>'
);
?>
</p>
</div>
<a class="button button-primary" href="<?php echo esc_url( wp_nonce_url( admin_url( 'admin.php?page=sqlite-integration&confirm-install&upgrade-from-pl' ), 'sqlite-install' ) ); ?>">
<?php elseif ( file_exists( WP_CONTENT_DIR . '/db.php' ) && ! defined( 'SQLITE_DROPIN' ) ) : ?>
<div class="notice notice-error">
<p>
<?php
printf(
/* translators: %s: db.php drop-in path */
esc_html__( 'Update %s file', 'sqlite-database-integration' ),
esc_html__( 'The SQLite plugin cannot be activated because a different %s drop-in already exists.', 'sqlite-database-integration' ),
'<code>' . esc_html( basename( WP_CONTENT_DIR ) ) . '/db.php</code>'
);
?>
</a>
<?php else : ?>
<div class="notice notice-error">
<p>
<?php
printf(
/* translators: %s: db.php drop-in path */
esc_html__( 'The SQLite plugin cannot be activated because a different %s drop-in already exists.', 'sqlite-database-integration' ),
'<code>' . esc_html( basename( WP_CONTENT_DIR ) ) . '/db.php</code>'
);
?>
</p>
</div>
<?php endif; ?>
</p>
</div>
<?php elseif ( ! is_writable( WP_CONTENT_DIR ) ) : ?>
<div class="notice notice-error">
<p>
@@ -111,9 +88,13 @@ function sqlite_integration_admin_screen() {
<p><?php esc_html_e( 'By clicking the button below, you will be redirected to the WordPress installation screen to setup your new database', 'sqlite-database-integration' ); ?></p>

<a class="button button-primary" href="<?php echo esc_url( wp_nonce_url( admin_url( 'admin.php?page=sqlite-integration&confirm-install' ), 'sqlite-install' ) ); ?>"><?php esc_html_e( 'Install SQLite database', 'sqlite-database-integration' ); ?></a>
<a class="button button-primary" href="<?php echo esc_url( wp_nonce_url( admin_url( 'admin.php?page=sqlite-integration&confirm-mysql-migration=1' ), 'sqlite-confirm-mysql-migration' ) ); ?>"><?php esc_html_e( 'Migrate database from MySQL to SQLite', 'sqlite-database-integration' ); ?></a>
<?php endif; ?>
<?php endif; ?>
</div>
<?php if ( isset( $_GET['confirm-mysql-migration'] ) ) : ?>
<span id="sqlite-migration-status"></span>
<?php endif; ?>
<?php
}

@@ -129,7 +110,7 @@ function sqlite_integration_admin_screen() {
function sqlite_plugin_adminbar_item( $admin_bar ) {
global $wpdb;

if ( defined( 'SQLITE_DB_DROPIN_VERSION' ) && defined( 'DB_ENGINE' ) && 'sqlite' === DB_ENGINE ) {
if ( defined( 'SQLITE_DROPIN' ) && SQLITE_DROPIN && defined( 'DB_ENGINE' ) && 'sqlite' === DB_ENGINE ) {
$title = '<span style="color:#46B450;">' . __( 'Database: SQLite', 'sqlite-database-integration' ) . '</span>';
} elseif ( stripos( $wpdb->db_server_info(), 'maria' ) !== false ) {
$title = '<span style="color:#DC3232;">' . __( 'Database: MariaDB', 'sqlite-database-integration' ) . '</span>';
9 changes: 1 addition & 8 deletions constants.php
Original file line number Diff line number Diff line change
@@ -8,14 +8,7 @@

// Temporary - This will be in wp-config.php once SQLite is merged in Core.
if ( ! defined( 'DB_ENGINE' ) ) {
if ( defined( 'SQLITE_DB_DROPIN_VERSION' ) ) {
define( 'DB_ENGINE', 'sqlite' );
} elseif ( defined( 'DATABASE_ENGINE' ) ) {
// backwards compatibility with previous versions of the plugin.
define( 'DB_ENGINE', DATABASE_ENGINE );
} else {
define( 'DB_ENGINE', 'mysql' );
}
define( 'DB_ENGINE', 'mysql' );
}

/**
2 changes: 1 addition & 1 deletion deactivate.php
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@
* When the plugin gets merged in wp-core, this is not to be ported.
*/
function sqlite_plugin_remove_db_file() {
if ( ! defined( 'SQLITE_DB_DROPIN_VERSION' ) || ! file_exists( WP_CONTENT_DIR . '/db.php' ) ) {
if ( ! defined( 'SQLITE_DROPIN' ) || ! SQLITE_DROPIN || ! file_exists( WP_CONTENT_DIR . '/db.php' ) ) {
return;
}

1 change: 1 addition & 0 deletions load.php
Original file line number Diff line number Diff line change
@@ -20,3 +20,4 @@
require_once __DIR__ . '/deactivate.php';
require_once __DIR__ . '/admin-notices.php';
require_once __DIR__ . '/health-check.php';
require_once __DIR__ . '/mysql-to-sqlite-migration.php';
142 changes: 142 additions & 0 deletions mysql-to-sqlite-migration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
<?php

require_once __DIR__ . '/constants.php';
require_once __DIR__ . '/wp-includes/sqlite/class-wp-sqlite-lexer.php';
require_once __DIR__ . '/wp-includes/sqlite/class-wp-sqlite-query-rewriter.php';
require_once __DIR__ . '/wp-includes/sqlite/class-wp-sqlite-translator.php';
require_once __DIR__ . '/wp-includes/sqlite/class-wp-sqlite-token.php';
require_once __DIR__ . '/wp-includes/sqlite/class-wp-sqlite-pdo-user-defined-functions.php';
require_once __DIR__ . '/wp-includes/sqlite/class-wp-sqlite-db.php';
require_once __DIR__ . '/wp-includes/sqlite/install-functions.php';

global $sqlite_db;
$sqlite_db = new WP_SQLite_DB();

/**
* Get an array of the tables names from the MySQL database.
*
* @return array
*/
function sqlite_integration_get_mysql_tables_names() {
global $wpdb;
return array_map( function ( $table ) {
return array_values( (array) $table )[0];
}, $wpdb->get_results( 'SHOW TABLES' ) );
}

/**
* Create a table in the SQLite database.
*
* @param string $table_name The name of the table to create.
* @param string $create_table_query The CREATE TABLE query to execute.
*/
function sqlite_integration_create_table( $table_name ) {
global $wpdb, $sqlite_db;
// Get the table structure.
$table_structure = $wpdb->get_results( "SHOW CREATE TABLE $table_name" );
// Execute the CREATE TABLE query.
$sqlite_db->query( $table_structure[0]->{'Create Table'} );
}

/**
* Migrate data for a single table.
*
* @param string $table_name The name of the table to migrate data for.
*/
function sqlite_integration_migrate_table( $table_name ) {
global $wpdb, $sqlite_db;
// Get the data from the MySQL table, and insert it into the SQLite table.
$data = $wpdb->get_results( "SELECT * FROM $table_name" );
foreach ( $data as $row ) {
$sqlite_db->insert( $table_name, (array) $row );
}
}

/**
* Run AJAX action to migrate a table.
*/
function sqlite_integration_migrate_table_ajax() {
if ( ! isset( $_POST['table_name'] ) ) {
wp_send_json_error( 'Table name is required' );
}
$table_name = sanitize_text_field( $_POST['table_name'] );
sqlite_integration_create_table( $table_name );
sqlite_integration_migrate_table( $table_name );
wp_send_json_success( 'Table migrated' );
}
add_action( 'wp_ajax_sqlite_integration_migrate_table', 'sqlite_integration_migrate_table_ajax' );

/**
* Run AJAX action to add the db.php file.
*/
function sqlite_integration_add_db_php_file_ajax() {
// Check if the sqlite_plugin_copy_db_file function exists.
if ( ! function_exists( 'sqlite_plugin_copy_db_file' ) ) {
require_once __DIR__ . '/activate.php';
}
sqlite_plugin_copy_db_file();
wp_send_json_success( 'db.php file added' );
}
add_action( 'wp_ajax_sqlite_integration_add_db_php_file', 'sqlite_integration_add_db_php_file_ajax' );

/**
* Add a script to the admin page to handle the migration process.
*/
function sqlite_integration_add_admin_script() {
?>
<script>
const databaseTables = <?php echo json_encode( sqlite_integration_get_mysql_tables_names() ); ?>;
const sqliteMigrateTable = ( tableName ) => {
jQuery( '#sqlite-migration-status' ).text( 'Migrating ' + tableName + ' table...' );
jQuery.ajax( {
url: ajaxurl,
type: 'POST',
data: {
action: 'sqlite_integration_migrate_table',
_wpnonce: '<?php echo wp_create_nonce( 'sqlite-confirm-mysql-migration' ); ?>',
table_name: tableName
},
success: function( response ) {
// Check if there is a next table to migrate.
if ( databaseTables.indexOf( tableName ) + 1 >= databaseTables.length ) {
jQuery( '#sqlite-migration-status' ).text( 'Database migrated. Adding the db.php file in your wp-content folder...' );
jQuery.ajax( {
url: ajaxurl,
type: 'POST',
data: {
action: 'sqlite_integration_add_db_php_file',
_wpnonce: '<?php echo wp_create_nonce( 'sqlite-confirm-mysql-migration' ); ?>',
},
success: function( response ) {
jQuery( '#sqlite-migration-status' ).text( 'Database migrated. Refreshing the page...' );
setTimeout( () => {
// Remove the confirm-mysql-migration query arg from the URL.
window.location.href = window.location.href.replace( '&confirm-mysql-migration=1', '' );
}, 1000 );
}
} );
return;
}
// Get the next table name.
const nextTableName = databaseTables[ databaseTables.indexOf( tableName ) + 1 ];

// Wait half a second, then migrate the next table.
setTimeout( () => {
sqliteMigrateTable( nextTableName );
}, 500 );
},
error: function( response ) {

}
} );
};
jQuery( document ).ready( function() {
let tableName = databaseTables[0];
sqliteMigrateTable( tableName );
} );
</script>
<?php
}
if ( isset( $_GET['confirm-mysql-migration'] ) ) {
add_action( 'admin_footer', 'sqlite_integration_add_admin_script' );
}
20 changes: 8 additions & 12 deletions db.copy → wp-content/db.php
Original file line number Diff line number Diff line change
@@ -11,17 +11,12 @@
* @package wp-sqlite-integration
*/

define( 'SQLITE_DB_DROPIN_VERSION', '1.8.0' );

// Tweak to allow copy-pasting the file without having to run string-replacements.
$sqlite_plugin_implementation_folder_path = '{SQLITE_IMPLEMENTATION_FOLDER_PATH}';
if ( ! file_exists( $sqlite_plugin_implementation_folder_path ) ) { // Check that the folder exists.
$sqlite_plugin_implementation_folder_path = realpath( __DIR__ . '/plugins/sqlite-database-integration' );
if ( ! defined( 'ABSPATH' ) ) {
exit;
}

// Bail early if the SQLite implementation was not located in the plugin.
if ( ! $sqlite_plugin_implementation_folder_path || ! file_exists( $sqlite_plugin_implementation_folder_path . '/wp-includes/sqlite/db.php' ) ) {
return;
if ( ! defined( 'SQLITE_DROPIN' ) ) {
define( 'SQLITE_DROPIN', true );
}

// Constant for backward compatibility.
@@ -34,7 +29,7 @@
}

// Require the implementation from the plugin.
require_once $sqlite_plugin_implementation_folder_path . '/wp-includes/sqlite/db.php';
require_once dirname( __DIR__ ) . '/wp-includes/sqlite/db.php';

// Activate the performance-lab plugin if it is not already activated.
add_action(
@@ -46,11 +41,12 @@ function() {
if ( ! function_exists( 'activate_plugin' ) ) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
if ( is_plugin_inactive( '{SQLITE_PLUGIN}' ) ) {
$plugin_file = str_replace( WP_PLUGIN_DIR . '/', '', SQLITE_MAIN_FILE );
if ( is_plugin_inactive( $plugin_file ) ) {
// If `activate_plugin()` returns a value other than null (like WP_Error),
// the plugin could not be found. Try with a hardcoded string,
// because that probably means the file was directly copy-pasted.
if ( null !== activate_plugin( '{SQLITE_PLUGIN}', '', false, true ) ) {
if ( null !== activate_plugin( $plugin_file, '', false, true ) ) {
activate_plugin( 'sqlite-database-integration/load.php', '', false, true );
}
}