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:
parent
58dfbd2c4e
commit
9b7570f8b2
|
@ -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.
|
|
@ -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 );
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue