Support inserting NULL values for strict DB mode (#39396)

* Support inserting NULL values for strict DB mode

* Set default date for placeholder order to support strict MySQL.

* Add unit test to verify strict mode also works.

* Make HPOS behavior of modified date consistent with WP_Post.

In HPOS we were leaving modified date to be empty, while WP_Post set it to the created date if modified date is null.
This commit is contained in:
Vedanshu Jain 2023-07-25 18:00:03 +05:30 committed by GitHub
parent 58dfbd2c4e
commit 9b7570f8b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 65 additions and 8 deletions

View File

@ -0,0 +1,4 @@
Significance: patch
Type: fix
Support inserting NULL values for strict DB mode for DataBase Util's insert_on_duplicate_key_update method.

View File

@ -1656,9 +1656,10 @@ FROM $order_meta_table
if ( 'create' === $context ) { if ( 'create' === $context ) {
$post_id = wp_insert_post( $post_id = wp_insert_post(
array( array(
'post_type' => $data_sync->data_sync_is_enabled() ? $order->get_type() : $data_sync::PLACEHOLDER_ORDER_POST_TYPE, 'post_type' => $data_sync->data_sync_is_enabled() ? $order->get_type() : $data_sync::PLACEHOLDER_ORDER_POST_TYPE,
'post_status' => 'draft', 'post_status' => 'draft',
'post_parent' => $order->get_changes()['parent_id'] ?? $order->get_data()['parent_id'] ?? 0, 'post_parent' => $order->get_changes()['parent_id'] ?? $order->get_data()['parent_id'] ?? 0,
'post_date_gmt' => current_time( 'mysql', 1 ), // We set the date to prevent invalid date errors when using MySQL strict mode.
) )
); );
@ -2287,6 +2288,10 @@ FROM $order_meta_table
$order->set_date_created( time() ); $order->set_date_created( time() );
} }
if ( ! $order->get_date_modified( 'edit' ) ) {
$order->set_date_modified( current_time( 'mysql' ) );
}
$this->update_order_meta( $order ); $this->update_order_meta( $order );
$this->persist_order_to_db( $order, $force_all_fields ); $this->persist_order_to_db( $order, $force_all_fields );
@ -2370,7 +2375,7 @@ FROM $order_meta_table
$changes = $order->get_changes(); $changes = $order->get_changes();
if ( ! isset( $changes['date_modified'] ) ) { if ( ! isset( $changes['date_modified'] ) ) {
$order->set_date_modified( time() ); $order->set_date_modified( current_time( 'mysql' ) );
} }
$this->persist_order_to_db( $order ); $this->persist_order_to_db( $order );

View File

@ -233,19 +233,35 @@ class DatabaseUtil {
*/ */
public function insert_on_duplicate_key_update( $table_name, $data, $format ) : int { public function insert_on_duplicate_key_update( $table_name, $data, $format ) : int {
global $wpdb; global $wpdb;
if ( empty( $data ) ) {
return 0;
}
$columns = array_keys( $data ); $columns = array_keys( $data );
$value_format = array();
$values = array();
$index = 0;
// Directly use NULL for placeholder if the value is NULL, since otherwise $wpdb->prepare will convert it to empty string.
foreach ( $data as $key => $value ) {
if ( is_null( $value ) ) {
$value_format[] = 'NULL';
} else {
$values[] = $value;
$value_format[] = $format[ $index ];
}
$index++;
}
$column_clause = '`' . implode( '`, `', $columns ) . '`'; $column_clause = '`' . implode( '`, `', $columns ) . '`';
$value_placeholders = implode( ', ', array_values( $format ) ); $value_format_clause = implode( ', ', $value_format );
$on_duplicate_clause = $this->generate_on_duplicate_statement_clause( $columns ); $on_duplicate_clause = $this->generate_on_duplicate_statement_clause( $columns );
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare -- Values are escaped in $wpdb->prepare. // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare -- Values are escaped in $wpdb->prepare.
$sql = $wpdb->prepare( $sql = $wpdb->prepare(
" "
INSERT INTO $table_name ( $column_clause ) INSERT INTO $table_name ( $column_clause )
VALUES ( $value_placeholders ) VALUES ( $value_format_clause )
$on_duplicate_clause $on_duplicate_clause
", ",
array_values( $data ) $values
); );
// phpcs:enable // phpcs:enable
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- $sql is prepared. // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- $sql is prepared.

View File

@ -68,6 +68,7 @@ class OrdersTableDataStoreTests extends HposTestCase {
* Destroys system under test. * Destroys system under test.
*/ */
public function tearDown(): void { public function tearDown(): void {
global $wpdb;
//phpcs:ignore WordPress.DateTime.RestrictedFunctions.timezone_change_date_default_timezone_set -- We need to change the timezone to test the date sync fields. //phpcs:ignore WordPress.DateTime.RestrictedFunctions.timezone_change_date_default_timezone_set -- We need to change the timezone to test the date sync fields.
update_option( 'timezone_string', $this->original_time_zone ); update_option( 'timezone_string', $this->original_time_zone );
$this->toggle_cot_feature_and_usage( $this->cot_state ); $this->toggle_cot_feature_and_usage( $this->cot_state );
@ -1996,6 +1997,37 @@ class OrdersTableDataStoreTests extends HposTestCase {
$this->assertEquals( $modified_date->format( 'Y-m-d H:i:s' ), $post->post_modified_gmt ); $this->assertEquals( $modified_date->format( 'Y-m-d H:i:s' ), $post->post_modified_gmt );
} }
/**
* @testDox Test that inserting with strict SQL mode is also supported.
*/
public function test_order_create_with_strict_mode_and_null_values() {
global $wpdb;
$this->toggle_cot_feature_and_usage( true );
$sql_mode = $wpdb->get_var( 'SELECT @@sql_mode' );
// Set SQL mode to strict to disallow 0 dates.
$wpdb->query( "SET sql_mode = 'TRADITIONAL'" );
$order = new WC_Order();
$this->switch_data_store( $order, $this->sut );
$order->save();
$this->assertTrue( $order->get_id() > 0 );
// Let's also repeat with sync off.
$this->enable_cot_sync();
$order = new WC_Order();
$this->switch_data_store( $order, $this->sut );
$order->save();
$this->assertTrue( $order->get_id() > 0 );
$order = wc_get_order( $order->get_id() );
$post = get_post( $order->get_id() );
$this->assertEquals( $order->get_date_modified()->format( 'Y-m-d H:i:s' ), $post->post_date );
// phpcs:ignore -- Hardcoded value.
$wpdb->query( "SET sql_mode = '$sql_mode' " );
}
/** /**
* @testDox Test that multiple calls to read don't try to sync again. * @testDox Test that multiple calls to read don't try to sync again.
*/ */