Remove foreign key from the wc_download_log table (#34318)

* Remove the FK from the download log table.

It's unnecessary and forces InnoDB engine.

* Delete also related download logs.

To replicate the FK behaviour.

* ON DELETE CASCADE in PHP

* Changelog.

* Bump the version when this will be included.

* Fixed missing select in subquery.

* Fix copypasta error.

* Remove accidentally added file.

* DRYing.

* Bracketing.

* Slight refactor to make it easier to read.

* Remove the FK from the download log table.

It's unnecessary and forces InnoDB engine.

* Delete also related download logs.

To replicate the FK behaviour.

* ON DELETE CASCADE in PHP

* Changelog.

* Bump the version when this will be included.

* Fixed missing select in subquery.

* Fix copypasta error.

* Remove accidentally added file.

* DRYing.

* Bracketing.

* Slight refactor to make it easier to read.

Co-authored-by: Nestor Soriano <konamiman@konamiman.com>
This commit is contained in:
Peter Fabian 2022-09-12 10:42:39 +02:00 committed by GitHub
parent d191ecc275
commit 4eccddf140
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 101 additions and 34 deletions

View File

@ -0,0 +1,4 @@
Significance: minor
Type: tweak
Remove foreign key requirement from download_log table.

View File

@ -213,6 +213,9 @@ class WC_Install {
'wc_update_670_purge_comments_count_cache',
'wc_update_670_delete_deprecated_remote_inbox_notifications_option',
),
'7.0.0' => array(
'wc_update_700_remove_download_log_fk',
),
);
/**
@ -1022,32 +1025,6 @@ class WC_Install {
$wpdb->query( "ALTER TABLE {$wpdb->comments} ADD INDEX woo_idx_comment_type (comment_type)" );
}
// Get tables data types and check it matches before adding constraint.
$download_log_columns = $wpdb->get_results( "SHOW COLUMNS FROM {$wpdb->prefix}wc_download_log WHERE Field = 'permission_id'", ARRAY_A );
$download_log_column_type = '';
if ( isset( $download_log_columns[0]['Type'] ) ) {
$download_log_column_type = $download_log_columns[0]['Type'];
}
$download_permissions_columns = $wpdb->get_results( "SHOW COLUMNS FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions WHERE Field = 'permission_id'", ARRAY_A );
$download_permissions_column_type = '';
if ( isset( $download_permissions_columns[0]['Type'] ) ) {
$download_permissions_column_type = $download_permissions_columns[0]['Type'];
}
// Add constraint to download logs if the columns matches.
if ( ! empty( $download_permissions_column_type ) && ! empty( $download_log_column_type ) && $download_permissions_column_type === $download_log_column_type ) {
$fk_result = $wpdb->get_row( "SHOW CREATE TABLE {$wpdb->prefix}wc_download_log" );
if ( false === strpos( $fk_result->{'Create Table'}, "fk_{$wpdb->prefix}wc_download_log_permission_id" ) ) {
$wpdb->query(
"ALTER TABLE `{$wpdb->prefix}wc_download_log`
ADD CONSTRAINT `fk_{$wpdb->prefix}wc_download_log_permission_id`
FOREIGN KEY (`permission_id`)
REFERENCES `{$wpdb->prefix}woocommerce_downloadable_product_permissions` (`permission_id`) ON DELETE CASCADE;"
);
}
}
// Clear table caches.
delete_transient( 'wc_attribute_taxonomies' );
}

View File

@ -240,13 +240,8 @@ class WC_Customer_Download_Data_Store implements WC_Customer_Download_Data_Store
public function delete( &$download, $args = array() ) {
global $wpdb;
$wpdb->query(
$wpdb->prepare(
"DELETE FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions
WHERE permission_id = %d",
$download->get_id()
)
);
$download_id = $download->get_id();
$this->delete_by_id( $download_id );
$download->set_id( 0 );
}
@ -265,6 +260,50 @@ class WC_Customer_Download_Data_Store implements WC_Customer_Download_Data_Store
$id
)
);
// Delete related records in wc_download_log (aka ON DELETE CASCADE).
$wpdb->query(
$wpdb->prepare(
"DELETE FROM {$wpdb->prefix}wc_download_log
WHERE permission_id = %d",
$id
)
);
}
/**
* Delete download_log related to download permission via $field with value $value.
*
* @param string $field Field used to query download permission table with.
* @param string|int|float $value Value to filter the field by.
*
* @return void
*/
private function delete_download_log_by_field_value( $field, $value ) {
global $wpdb;
$value_placeholder = '';
if ( is_int( $value ) ) {
$value_placeholder = '%d';
} elseif ( is_string( $value ) ) {
$value_placeholder = '%s';
} elseif ( is_float( $value ) ) {
$value_placeholder = '%f';
} else {
wc_doing_it_wrong( __METHOD__, __( 'Unsupported argument type provided as value.', 'woocommerce' ), '7.0' );
// The `prepare` further down would fail if the placeholder was missing, so skip download log removal.
return;
}
$query = "DELETE FROM {$wpdb->prefix}wc_download_log
WHERE permission_id IN (
SELECT permission_id
FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions
WHERE {$field} = {$value_placeholder}
)";
$wpdb->query(
$wpdb->prepare( $query, $value ) // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
);
}
/**
@ -274,6 +313,9 @@ class WC_Customer_Download_Data_Store implements WC_Customer_Download_Data_Store
*/
public function delete_by_order_id( $id ) {
global $wpdb;
// Delete related records in wc_download_log (aka ON DELETE CASCADE).
$this->delete_download_log_by_field_value( 'order_id', $id );
$wpdb->query(
$wpdb->prepare(
"DELETE FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions
@ -290,6 +332,9 @@ class WC_Customer_Download_Data_Store implements WC_Customer_Download_Data_Store
*/
public function delete_by_download_id( $id ) {
global $wpdb;
// Delete related records in wc_download_log (aka ON DELETE CASCADE).
$this->delete_download_log_by_field_value( 'download_id', $id );
$wpdb->query(
$wpdb->prepare(
"DELETE FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions
@ -308,6 +353,9 @@ class WC_Customer_Download_Data_Store implements WC_Customer_Download_Data_Store
*/
public function delete_by_user_id( $id ) {
global $wpdb;
// Delete related records in wc_download_log (aka ON DELETE CASCADE).
$this->delete_download_log_by_field_value( 'user_id', $id );
return (bool) $wpdb->query(
$wpdb->prepare(
"DELETE FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions
@ -326,6 +374,9 @@ class WC_Customer_Download_Data_Store implements WC_Customer_Download_Data_Store
*/
public function delete_by_user_email( $email ) {
global $wpdb;
// Delete related records in wc_download_log (aka ON DELETE CASCADE).
$this->delete_download_log_by_field_value( 'user_email', $email );
return (bool) $wpdb->query(
$wpdb->prepare(
"DELETE FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions

View File

@ -235,5 +235,7 @@ class WC_Customer_Download_Log_Data_Store implements WC_Customer_Download_Log_Da
public function delete_by_permission_id( $id ) {
global $wpdb;
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions WHERE permission_id = %d", $id ) );
// Delete related records in wc_download_log (aka ON DELETE CASCADE).
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}wc_download_log WHERE permission_id = %d", $id ) );
}
}

View File

@ -476,13 +476,24 @@ class WC_REST_System_Status_Tools_V2_Controller extends WC_REST_Controller {
break;
case 'clear_expired_download_permissions':
// Delete related records in wc_download_log (aka ON DELETE CASCADE).
$wpdb->query(
$wpdb->prepare(
"DELETE FROM {$wpdb->prefix}wc_download_log
WHERE permission_id IN (
SELECT permission_id FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions
WHERE ( downloads_remaining != '' AND downloads_remaining = 0 ) OR ( access_expires IS NOT NULL AND access_expires < %s )
)",
current_time( 'Y-m-d' )
)
);
// Delete expired download permissions and ones with 0 downloads remaining.
$result = absint(
$wpdb->query(
$wpdb->prepare(
"DELETE FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions
WHERE ( downloads_remaining != '' AND downloads_remaining = 0 ) OR ( access_expires IS NOT NULL AND access_expires < %s )",
gmdate( 'Y-m-d', current_time( 'timestamp' ) )
current_time( 'Y-m-d' )
)
)
);

View File

@ -2441,3 +2441,25 @@ function wc_update_670_purge_comments_count_cache() {
WC_Comments::delete_comments_count_cache();
}
/**
* Remove unnecessary foreign keys.
*
* @return void
*/
function wc_update_700_remove_download_log_fk() {
global $wpdb;
$results = $wpdb->get_results(
"SELECT CONSTRAINT_NAME
FROM information_schema.TABLE_CONSTRAINTS
WHERE CONSTRAINT_SCHEMA = '{$wpdb->dbname}'
AND CONSTRAINT_TYPE = 'FOREIGN KEY'
AND TABLE_NAME = '{$wpdb->prefix}wc_download_log'"
);
if ( $results ) {
foreach ( $results as $fk ) {
$wpdb->query( "ALTER TABLE {$wpdb->prefix}wc_download_log DROP FOREIGN KEY {$fk->CONSTRAINT_NAME}" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
}
}
}