From 08492dd79577e7cc53a7cd2ec9d1541e417c3893 Mon Sep 17 00:00:00 2001 From: wpdev Date: Sat, 26 Sep 2026 04:24:14 +0800 Subject: [PATCH] fix(2meet-data-optimizer): compare empty strings correctly when retiring a group - retire() read native meta with wpdb::get_col(), which (via get_var()) returns null for an empty string, so a flat '' written back as '' was counted as a mismatch and blocked the retirement. It now reads raw rows with get_results(). - The integration test wpdb stub's get_var() / get_col() now read '' as null like the real wpdb, so tests see WordPress behaviour. - Found writing back the sso group on dev21 / dev22 (picture_url = ''). - Verify: core unit 658 / integration 480 green, phpcs clean - PR: PR-042 follow-up --- includes/migration/class-tmdo-native-restorer.php | 5 +++-- tests/integration/NativeRestorerRetireTest.php | 9 +++++++++ tests/integration/bootstrap.php | 6 ++++-- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/includes/migration/class-tmdo-native-restorer.php b/includes/migration/class-tmdo-native-restorer.php index 4bd8c1d..cf97d42 100644 --- a/includes/migration/class-tmdo-native-restorer.php +++ b/includes/migration/class-tmdo-native-restorer.php @@ -168,8 +168,9 @@ final class TMDO_Native_Restorer { if ( '' === $col || ! isset( $row[ $col ] ) ) { continue; } - $want = (string) maybe_serialize( TMDO_Type_Caster::from_db( $row[ $col ], $field ) ); - $native = $wpdb->get_col( $wpdb->prepare( "SELECT meta_value FROM `{$native_table}` WHERE `{$id_col}` = %d AND meta_key = %s", (int) $row[ $id_col ], $field['key'] ) ); + $want = (string) maybe_serialize( TMDO_Type_Caster::from_db( $row[ $col ], $field ) ); + // get_results(), not get_col(): wpdb reads an empty string as null. + $native = array_column( (array) $wpdb->get_results( $wpdb->prepare( "SELECT meta_value FROM `{$native_table}` WHERE `{$id_col}` = %d AND meta_key = %s", (int) $row[ $id_col ], $field['key'] ), ARRAY_A ), 'meta_value' ); if ( array( $want ) !== $native ) { ++$result['mismatches']; } diff --git a/tests/integration/NativeRestorerRetireTest.php b/tests/integration/NativeRestorerRetireTest.php index 4b88f10..cec6483 100644 --- a/tests/integration/NativeRestorerRetireTest.php +++ b/tests/integration/NativeRestorerRetireTest.php @@ -129,6 +129,15 @@ class NativeRestorerRetireTest extends TestCase { $this->assertSame( 3, $result['mismatches'], 't1, ["1.1.1.1"], t2 are not native yet' ); } + public function test_empty_string_values_count_as_written_back(): void { + global $wpdb; + $wpdb->query( 'UPDATE `' . self::A . "` SET ips = '' WHERE user_id = 2" ); + TMDO_Native_Restorer::run( 'user', false, 500, false, 'rt_a' ); + self::register( false ); + + $this->assertSame( 'retired', TMDO_Native_Restorer::retire( 'user', 'rt_a' )['status'], "wpdb::get_col() reads '' as null" ); + } + public function test_retire_forgets_the_group_and_keeps_its_table_as_a_backup(): void { global $wpdb; TMDO_Native_Restorer::run( 'user', false, 500, false, 'rt_a' ); diff --git a/tests/integration/bootstrap.php b/tests/integration/bootstrap.php index 0ab1764..c19554b 100644 --- a/tests/integration/bootstrap.php +++ b/tests/integration/bootstrap.php @@ -129,7 +129,8 @@ $wpdb = new class( $_mysqli ) { public function get_var( string $sql ): ?string { $result = $this->db->query( $sql ); if ( ! $result || ! ( $row = $result->fetch_row() ) ) { return null; } - return $row[0] !== null ? (string) $row[0] : null; + // Like wpdb::get_var(): an empty string reads as null. + return null !== $row[0] && '' !== $row[0] ? (string) $row[0] : null; } public function get_row( string $sql, $output = 'OBJECT' ) { @@ -152,7 +153,8 @@ $wpdb = new class( $_mysqli ) { $result = $this->db->query( $sql ); if ( ! $result ) { return []; } $values = []; - while ( $row = $result->fetch_row() ) { $values[] = $row[ $col_index ] ?? null; } + // Like wpdb::get_col() (per-row get_var()): an empty string reads as null. + while ( $row = $result->fetch_row() ) { $values[] = isset( $row[ $col_index ] ) && '' !== $row[ $col_index ] ? $row[ $col_index ] : null; } return $values; }