From f9f56fb94260566f82e2bac38b07b02cc52fb7c5 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Thu, 1 Oct 2015 05:36:15 +0000 Subject: [PATCH] WPDB: Allow `null` values in the CRUD functions. Specifically, `::insert()`, `::replace()`, `::update()`, and `::delete()` can now set a column to `NULL`, or add the `IS NULL` condition to the `WHERE` clause. This is based on [backpress 279]. Props pento, nbachiyski, sorich87. Fixes #15158. git-svn-id: https://develop.svn.wordpress.org/trunk@34737 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/wp-db.php | 27 ++++++++ tests/phpunit/tests/db.php | 135 ++++++++++++++++++++++++++++++++++++- 2 files changed, 161 insertions(+), 1 deletion(-) diff --git a/src/wp-includes/wp-db.php b/src/wp-includes/wp-db.php index e52d6fd2f4..008550d2a5 100644 --- a/src/wp-includes/wp-db.php +++ b/src/wp-includes/wp-db.php @@ -1779,6 +1779,7 @@ class wpdb { * @param string $table Table name * @param array $data Data to insert (in column => value pairs). * Both $data columns and $data values should be "raw" (neither should be SQL escaped). + * Sending a null value will cause the column to be set to NULL - the corresponding format is ignored in this case. * @param array|string $format Optional. An array of formats to be mapped to each of the value in $data. * If string, that format will be used for all of the values in $data. * A format is one of '%d', '%f', '%s' (integer, float, string). @@ -1803,6 +1804,7 @@ class wpdb { * @param string $table Table name * @param array $data Data to insert (in column => value pairs). * Both $data columns and $data values should be "raw" (neither should be SQL escaped). + * Sending a null value will cause the column to be set to NULL - the corresponding format is ignored in this case. * @param array|string $format Optional. An array of formats to be mapped to each of the value in $data. * If string, that format will be used for all of the values in $data. * A format is one of '%d', '%f', '%s' (integer, float, string). @@ -1827,6 +1829,7 @@ class wpdb { * @param string $table Table name * @param array $data Data to insert (in column => value pairs). * Both $data columns and $data values should be "raw" (neither should be SQL escaped). + * Sending a null value will cause the column to be set to NULL - the corresponding format is ignored in this case. * @param array|string $format Optional. An array of formats to be mapped to each of the value in $data. * If string, that format will be used for all of the values in $data. * A format is one of '%d', '%f', '%s' (integer, float, string). @@ -1848,6 +1851,11 @@ class wpdb { $formats = $values = array(); foreach ( $data as $value ) { + if ( is_null( $value['value'] ) ) { + $formats[] = 'NULL'; + continue; + } + $formats[] = $value['format']; $values[] = $value['value']; } @@ -1875,9 +1883,12 @@ class wpdb { * @param string $table Table name * @param array $data Data to update (in column => value pairs). * Both $data columns and $data values should be "raw" (neither should be SQL escaped). + * Sending a null value will cause the column to be set to NULL - the corresponding + * format is ignored in this case. * @param array $where A named array of WHERE clauses (in column => value pairs). * Multiple clauses will be joined with ANDs. * Both $where columns and $where values should be "raw". + * Sending a null value will create an IS NULL comparison - the corresponding format will be ignored in this case. * @param array|string $format Optional. An array of formats to be mapped to each of the values in $data. * If string, that format will be used for all of the values in $data. * A format is one of '%d', '%f', '%s' (integer, float, string). @@ -1904,10 +1915,20 @@ class wpdb { $fields = $conditions = $values = array(); foreach ( $data as $field => $value ) { + if ( is_null( $value['value'] ) ) { + $fields[] = "`$field` = NULL"; + continue; + } + $fields[] = "`$field` = " . $value['format']; $values[] = $value['value']; } foreach ( $where as $field => $value ) { + if ( is_null( $value['value'] ) ) { + $conditions[] = "`$field` IS NULL"; + continue; + } + $conditions[] = "`$field` = " . $value['format']; $values[] = $value['value']; } @@ -1936,6 +1957,7 @@ class wpdb { * @param array $where A named array of WHERE clauses (in column => value pairs). * Multiple clauses will be joined with ANDs. * Both $where columns and $where values should be "raw". + * Sending a null value will create an IS NULL comparison - the corresponding format will be ignored in this case. * @param array|string $where_format Optional. An array of formats to be mapped to each of the values in $where. * If string, that format will be used for all of the items in $where. * A format is one of '%d', '%f', '%s' (integer, float, string). @@ -1954,6 +1976,11 @@ class wpdb { $conditions = $values = array(); foreach ( $where as $field => $value ) { + if ( is_null( $value['value'] ) ) { + $conditions[] = "`$field` IS NULL"; + continue; + } + $conditions[] = "`$field` = " . $value['format']; $values[] = $value['value']; } diff --git a/tests/phpunit/tests/db.php b/tests/phpunit/tests/db.php index 2d8df5e5ad..23274359fd 100644 --- a/tests/phpunit/tests/db.php +++ b/tests/phpunit/tests/db.php @@ -807,5 +807,138 @@ class Tests_DB extends WP_UnitTestCase { function filter_pre_get_col_charset( $charset, $table, $column ) { return 'fake_col_charset'; } -} + /** + * @ticket 15158 + */ + function test_null_insert() { + global $wpdb; + + $key = 'null_insert_key'; + + $wpdb->insert( + $wpdb->postmeta, + array( + 'meta_key' => $key, + 'meta_value' => NULL + ), + array( '%s', '%s' ) + ); + + $row = $wpdb->get_row( "SELECT * FROM $wpdb->postmeta WHERE meta_key='$key'" ); + + $this->assertNull( $row->meta_value ); + } + + /** + * @ticket 15158 + */ + function test_null_update_value() { + global $wpdb; + + $key = 'null_update_value_key'; + $value = 'null_update_value_key'; + + $wpdb->insert( + $wpdb->postmeta, + array( + 'meta_key' => $key, + 'meta_value' => $value + ), + array( '%s', '%s' ) + ); + + $row = $wpdb->get_row( "SELECT * FROM $wpdb->postmeta WHERE meta_key='$key'" ); + + $this->assertSame( $value, $row->meta_value ); + + $wpdb->update( + $wpdb->postmeta, + array( 'meta_value' => NULL ), + array( + 'meta_key' => $key, + 'meta_value' => $value + ), + array( '%s' ), + array( '%s', '%s' ) + ); + + $row = $wpdb->get_row( "SELECT * FROM $wpdb->postmeta WHERE meta_key='$key'" ); + + $this->assertNull( $row->meta_value ); + } + + /** + * @ticket 15158 + */ + function test_null_update_where() { + global $wpdb; + + $key = 'null_update_where_key'; + $value = 'null_update_where_key'; + + $wpdb->insert( + $wpdb->postmeta, + array( + 'meta_key' => $key, + 'meta_value' => NULL + ), + array( '%s', '%s' ) + ); + + $row = $wpdb->get_row( "SELECT * FROM $wpdb->postmeta WHERE meta_key='$key'" ); + + $this->assertNull( $row->meta_value ); + + $wpdb->update( + $wpdb->postmeta, + array( 'meta_value' => $value ), + array( + 'meta_key' => $key, + 'meta_value' => NULL + ), + array( '%s' ), + array( '%s', '%s' ) + ); + + $row = $wpdb->get_row( "SELECT * FROM $wpdb->postmeta WHERE meta_key='$key'" ); + + $this->assertSame( $value, $row->meta_value ); + } + + /** + * @ticket 15158 + */ + function test_null_delete() { + global $wpdb; + + $key = 'null_update_where_key'; + $value = 'null_update_where_key'; + + $wpdb->insert( + $wpdb->postmeta, + array( + 'meta_key' => $key, + 'meta_value' => NULL + ), + array( '%s', '%s' ) + ); + + $row = $wpdb->get_row( "SELECT * FROM $wpdb->postmeta WHERE meta_key='$key'" ); + + $this->assertNull( $row->meta_value ); + + $wpdb->delete( + $wpdb->postmeta, + array( + 'meta_key' => $key, + 'meta_value' => NULL + ), + array( '%s', '%s' ) + ); + + $row = $wpdb->get_row( "SELECT * FROM $wpdb->postmeta WHERE meta_key='$key'" ); + + $this->assertNull( $row ); + } +}