+ $error_reporting = false;
+
+ // Disable warnings, as we don't want to see a multitude of "unable to connect" messages
+ if ( WP_DEBUG ) {
+ $error_reporting = error_reporting();
+ error_reporting( $error_reporting & ~E_WARNING );
+ }
+
+ for ( $tries = 1; $tries <= $this->reconnect_retries; $tries++ ) {
+ // On the last try, re-enable warnings. We want to see a single instance of the
+ // "unable to connect" message on the bail() screen, if it appears.
+ if ( $this->reconnect_retries === $tries && WP_DEBUG ) {
+ error_reporting( $error_reporting );
+ }
+
+ if ( $this->db_connect( false ) ) {
+ if ( $error_reporting ) {
+ error_reporting( $error_reporting );
+ }
+
+ return true;
+ }
+
+ sleep( 1 );
+ }
+
+ // If template_redirect has already happened, it's too late for wp_die()/dead_db().
+ // Let's just return and hope for the best.
+ if ( did_action( 'template_redirect' ) ) {
+ return false;
+ }
+
+ if ( ! $allow_bail ) {
+ return false;
+ }
+
+ // We weren't able to reconnect, so we better bail.
+ $this->bail( sprintf( ( "
+<h1>Error reconnecting to the database</h1>
+<p>This means that we lost contact with the database server at <code>%s</code>. This could mean your host's database server is down.</p>
+<ul>
+ <li>Are you sure that the database server is running?</li>
+ <li>Are you sure that the database server is not under particularly heavy load?</li>
+</ul>
+<p>If you're unsure what these terms mean you should probably contact your host. If you still need help you can always visit the <a href='https://wordpress.org/support/'>WordPress Support Forums</a>.</p>
+" ), htmlspecialchars( $this->dbhost, ENT_QUOTES ) ), 'db_connect_fail' );
+
+ // Call dead_db() if bail didn't die, because this database is no more. It has ceased to be (at least temporarily).
+ dead_db();
+ }
+
+ /**
+ * Perform a MySQL database query, using current database connection.
+ *
+ * More information can be found on the codex page.
+ *
+ * @since 0.71
+ *
+ * @param string $query Database query
+ * @return int|false Number of rows affected/selected or false on error
+ */
+ public function query( $query ) {
+ if ( ! $this->ready ) {
+ $this->check_current_query = true;
+ return false;
+ }
+
+ /**
+ * Filter the database query.
+ *
+ * Some queries are made before the plugins have been loaded,
+ * and thus cannot be filtered with this method.
+ *
+ * @since 2.1.0
+ *
+ * @param string $query Database query.
+ */
+ $query = apply_filters( 'query', $query );
+
+ $this->flush();
+
+ // Log how the function was called
+ $this->func_call = "\$db->query(\"$query\")";
+
+ // If we're writing to the database, make sure the query will write safely.
+ if ( $this->check_current_query && ! $this->check_ascii( $query ) ) {
+ $stripped_query = $this->strip_invalid_text_from_query( $query );
+ // strip_invalid_text_from_query() can perform queries, so we need
+ // to flush again, just to make sure everything is clear.
+ $this->flush();
+ if ( $stripped_query !== $query ) {
+ $this->insert_id = 0;
+ return false;
+ }
+ }
+
+ $this->check_current_query = true;
+
+ // Keep track of the last query for debug..
+ $this->last_query = $query;
+
+ $this->_do_query( $query );
+
+ // MySQL server has gone away, try to reconnect
+ $mysql_errno = 0;
+ if ( ! empty( $this->dbh ) ) {
+ if ( $this->use_mysqli ) {
+ $mysql_errno = mysqli_errno( $this->dbh );
+ } else {
+ $mysql_errno = mysql_errno( $this->dbh );
+ }
+ }
+
+ if ( empty( $this->dbh ) || 2006 == $mysql_errno ) {
+ if ( $this->check_connection() ) {
+ $this->_do_query( $query );
+ } else {
+ $this->insert_id = 0;
+ return false;
+ }
+ }
+
+ // If there is an error then take note of it..
+ if ( $this->use_mysqli ) {
+ $this->last_error = mysqli_error( $this->dbh );
+ } else {
+ $this->last_error = mysql_error( $this->dbh );
+ }
+
+ if ( $this->last_error ) {
+ // Clear insert_id on a subsequent failed insert.
+ if ( $this->insert_id && preg_match( '/^\s*(insert|replace)\s/i', $query ) )
+ $this->insert_id = 0;
+
+ $this->print_error();
+ return false;
+ }
+
+ if ( preg_match( '/^\s*(create|alter|truncate|drop)\s/i', $query ) ) {
+ $return_val = $this->result;
+ } elseif ( preg_match( '/^\s*(insert|delete|update|replace)\s/i', $query ) ) {
+ if ( $this->use_mysqli ) {
+ $this->rows_affected = mysqli_affected_rows( $this->dbh );
+ } else {
+ $this->rows_affected = mysql_affected_rows( $this->dbh );
+ }
+ // Take note of the insert_id
+ if ( preg_match( '/^\s*(insert|replace)\s/i', $query ) ) {
+ if ( $this->use_mysqli ) {
+ $this->insert_id = mysqli_insert_id( $this->dbh );
+ } else {
+ $this->insert_id = mysql_insert_id( $this->dbh );
+ }
+ }
+ // Return number of rows affected
+ $return_val = $this->rows_affected;
+ } else {
+ $num_rows = 0;
+ if ( $this->use_mysqli && $this->result instanceof mysqli_result ) {
+ while ( $row = @mysqli_fetch_object( $this->result ) ) {
+ $this->last_result[$num_rows] = $row;
+ $num_rows++;
+ }
+ } elseif ( is_resource( $this->result ) ) {
+ while ( $row = @mysql_fetch_object( $this->result ) ) {
+ $this->last_result[$num_rows] = $row;
+ $num_rows++;
+ }
+ }
+
+ // Log number of rows the query returned
+ // and return number of rows selected
+ $this->num_rows = $num_rows;
+ $return_val = $num_rows;
+ }
+
+ return $return_val;
+ }
+
+ /**
+ * Internal function to perform the mysql_query() call.
+ *
+ * @since 3.9.0
+ *
+ * @access private
+ * @see wpdb::query()
+ *
+ * @param string $query The query to run.
+ */
+ private function _do_query( $query ) {
+ if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) {
+ $this->timer_start();
+ }
+
+ if ( $this->use_mysqli ) {
+ $this->result = @mysqli_query( $this->dbh, $query );
+ } else {
+ $this->result = @mysql_query( $query, $this->dbh );
+ }
+ $this->num_queries++;
+
+ if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) {
+ $this->queries[] = array( $query, $this->timer_stop(), $this->get_caller() );
+ }
+ }
+
+ /**
+ * Insert a row into a table.
+ *
+ * wpdb::insert( 'table', array( 'column' => 'foo', 'field' => 'bar' ) )
+ * wpdb::insert( 'table', array( 'column' => 'foo', 'field' => 1337 ), array( '%s', '%d' ) )
+ *
+ * @since 2.5.0
+ * @see wpdb::prepare()
+ * @see wpdb::$field_types
+ * @see wp_set_wpdb_vars()
+ *
+ * @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).
+ * @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). If omitted, all values in $data will be treated as strings unless otherwise specified in wpdb::$field_types.
+ * @return int|false The number of rows inserted, or false on error.
+ */
+ public function insert( $table, $data, $format = null ) {
+ return $this->_insert_replace_helper( $table, $data, $format, 'INSERT' );
+ }
+
+ /**
+ * Replace a row into a table.
+ *
+ * wpdb::replace( 'table', array( 'column' => 'foo', 'field' => 'bar' ) )
+ * wpdb::replace( 'table', array( 'column' => 'foo', 'field' => 1337 ), array( '%s', '%d' ) )
+ *
+ * @since 3.0.0
+ * @see wpdb::prepare()
+ * @see wpdb::$field_types
+ * @see wp_set_wpdb_vars()
+ *
+ * @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).
+ * @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). If omitted, all values in $data will be treated as strings unless otherwise specified in wpdb::$field_types.
+ * @return int|false The number of rows affected, or false on error.
+ */
+ public function replace( $table, $data, $format = null ) {
+ return $this->_insert_replace_helper( $table, $data, $format, 'REPLACE' );
+ }
+
+ /**
+ * Helper function for insert and replace.
+ *
+ * Runs an insert or replace query based on $type argument.
+ *
+ * @access private
+ * @since 3.0.0
+ * @see wpdb::prepare()
+ * @see wpdb::$field_types
+ * @see wp_set_wpdb_vars()
+ *
+ * @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).
+ * @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). If omitted, all values in $data will be treated as strings unless otherwise specified in wpdb::$field_types.
+ * @param string $type Optional. What type of operation is this? INSERT or REPLACE. Defaults to INSERT.
+ * @return int|false The number of rows affected, or false on error.
+ */
+ function _insert_replace_helper( $table, $data, $format = null, $type = 'INSERT' ) {
+ $this->insert_id = 0;
+
+ if ( ! in_array( strtoupper( $type ), array( 'REPLACE', 'INSERT' ) ) ) {
+ return false;
+ }
+
+ $data = $this->process_fields( $table, $data, $format );
+ if ( false === $data ) {
+ return false;
+ }
+
+ $formats = $values = array();
+ foreach ( $data as $value ) {
+ $formats[] = $value['format'];
+ $values[] = $value['value'];
+ }
+
+ $fields = '`' . implode( '`, `', array_keys( $data ) ) . '`';
+ $formats = implode( ', ', $formats );
+
+ $sql = "$type INTO `$table` ($fields) VALUES ($formats)";
+
+ $this->check_current_query = false;
+ return $this->query( $this->prepare( $sql, $values ) );
+ }
+
+ /**
+ * Update a row in the table
+ *
+ * wpdb::update( 'table', array( 'column' => 'foo', 'field' => 'bar' ), array( 'ID' => 1 ) )
+ * wpdb::update( 'table', array( 'column' => 'foo', 'field' => 1337 ), array( 'ID' => 1 ), array( '%s', '%d' ), array( '%d' ) )
+ *
+ * @since 2.5.0
+ * @see wpdb::prepare()
+ * @see wpdb::$field_types
+ * @see wp_set_wpdb_vars()
+ *
+ * @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).
+ * @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".
+ * @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). If omitted, all values in $data will be treated as strings unless otherwise specified in wpdb::$field_types.
+ * @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). If omitted, all values in $where will be treated as strings.
+ * @return int|false The number of rows updated, or false on error.
+ */
+ public function update( $table, $data, $where, $format = null, $where_format = null ) {
+ if ( ! is_array( $data ) || ! is_array( $where ) ) {
+ return false;
+ }
+
+ $data = $this->process_fields( $table, $data, $format );
+ if ( false === $data ) {
+ return false;
+ }
+ $where = $this->process_fields( $table, $where, $where_format );
+ if ( false === $where ) {
+ return false;
+ }
+
+ $fields = $conditions = $values = array();
+ foreach ( $data as $field => $value ) {
+ $fields[] = "`$field` = " . $value['format'];
+ $values[] = $value['value'];
+ }
+ foreach ( $where as $field => $value ) {
+ $conditions[] = "`$field` = " . $value['format'];
+ $values[] = $value['value'];
+ }
+
+ $fields = implode( ', ', $fields );
+ $conditions = implode( ' AND ', $conditions );
+
+ $sql = "UPDATE `$table` SET $fields WHERE $conditions";
+
+ $this->check_current_query = false;
+ return $this->query( $this->prepare( $sql, $values ) );
+ }
+
+ /**
+ * Delete a row in the table
+ *
+ * wpdb::delete( 'table', array( 'ID' => 1 ) )
+ * wpdb::delete( 'table', array( 'ID' => 1 ), array( '%d' ) )
+ *
+ * @since 3.4.0
+ * @see wpdb::prepare()
+ * @see wpdb::$field_types
+ * @see wp_set_wpdb_vars()
+ *
+ * @param string $table table name
+ * @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".
+ * @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). If omitted, all values in $where will be treated as strings unless otherwise specified in wpdb::$field_types.
+ * @return int|false The number of rows updated, or false on error.
+ */
+ public function delete( $table, $where, $where_format = null ) {
+ if ( ! is_array( $where ) ) {
+ return false;
+ }
+
+ $where = $this->process_fields( $table, $where, $where_format );
+ if ( false === $where ) {
+ return false;
+ }
+
+ $conditions = $values = array();
+ foreach ( $where as $field => $value ) {
+ $conditions[] = "`$field` = " . $value['format'];
+ $values[] = $value['value'];
+ }
+
+ $conditions = implode( ' AND ', $conditions );
+
+ $sql = "DELETE FROM `$table` WHERE $conditions";
+
+ $this->check_current_query = false;
+ return $this->query( $this->prepare( $sql, $values ) );
+ }
+
+ /**
+ * Processes arrays of field/value pairs and field formats.
+ *
+ * This is a helper method for wpdb's CRUD methods, which take field/value
+ * pairs for inserts, updates, and where clauses. This method first pairs
+ * each value with a format. Then it determines the charset of that field,
+ * using that to determine if any invalid text would be stripped. If text is
+ * stripped, then field processing is rejected and the query fails.
+ *
+ * @since 4.2.0
+ * @access protected
+ *
+ * @param string $table Table name.
+ * @param array $data Field/value pair.
+ * @param mixed $format Format for each field.
+ * @return array|bool Returns an array of fields that contain paired values
+ * and formats. Returns false for invalid values.
+ */
+ protected function process_fields( $table, $data, $format ) {
+ $data = $this->process_field_formats( $data, $format );
+ if ( false === $data ) {
+ return false;
+ }
+
+ $data = $this->process_field_charsets( $data, $table );
+ if ( false === $data ) {
+ return false;
+ }
+
+ $data = $this->process_field_lengths( $data, $table );
+ if ( false === $data ) {
+ return false;
+ }
+
+ $converted_data = $this->strip_invalid_text( $data );
+
+ if ( $data !== $converted_data ) {
+ return false;
+ }
+
+ return $data;
+ }
+
+ /**
+ * Prepares arrays of value/format pairs as passed to wpdb CRUD methods.
+ *
+ * @since 4.2.0
+ * @access protected
+ *
+ * @param array $data Array of fields to values.
+ * @param mixed $format Formats to be mapped to the values in $data.
+ * @return array Array, keyed by field names with values being an array
+ * of 'value' and 'format' keys.
+ */
+ protected function process_field_formats( $data, $format ) {
+ $formats = $original_formats = (array) $format;
+
+ foreach ( $data as $field => $value ) {
+ $value = array(
+ 'value' => $value,
+ 'format' => '%s',
+ );
+
+ if ( ! empty( $format ) ) {
+ $value['format'] = array_shift( $formats );
+ if ( ! $value['format'] ) {
+ $value['format'] = reset( $original_formats );
+ }
+ } elseif ( isset( $this->field_types[ $field ] ) ) {
+ $value['format'] = $this->field_types[ $field ];
+ }
+
+ $data[ $field ] = $value;
+ }
+
+ return $data;
+ }
+
+ /**
+ * Adds field charsets to field/value/format arrays generated by
+ * the wpdb::process_field_formats() method.
+ *
+ * @since 4.2.0
+ * @access protected
+ *
+ * @param array $data As it comes from the wpdb::process_field_formats() method.
+ * @param string $table Table name.
+ * @return The same array as $data with additional 'charset' keys.
+ */
+ protected function process_field_charsets( $data, $table ) {
+ foreach ( $data as $field => $value ) {
+ if ( '%d' === $value['format'] || '%f' === $value['format'] ) {
+ // We can skip this field if we know it isn't a string.
+ // This checks %d/%f versus ! %s because it's sprintf() could take more.
+ $value['charset'] = false;
+ } else {
+ $value['charset'] = $this->get_col_charset( $table, $field );
+ if ( is_wp_error( $value['charset'] ) ) {
+ return false;
+ }
+ }
+
+ $data[ $field ] = $value;
+ }
+
+ return $data;
+ }
+
+ /**
+ * For string fields, record the maximum string length that field can safely save.
+ *
+ * @since 4.2.1
+ * @access protected
+ *
+ * @param array $data As it comes from the wpdb::process_field_charsets() method.
+ * @param string $table Table name.
+ * @return array|False The same array as $data with additional 'length' keys, or false if
+ * any of the values were too long for their corresponding field.
+ */
+ protected function process_field_lengths( $data, $table ) {
+ foreach ( $data as $field => $value ) {
+ if ( '%d' === $value['format'] || '%f' === $value['format'] ) {
+ // We can skip this field if we know it isn't a string.
+ // This checks %d/%f versus ! %s because it's sprintf() could take more.
+ $value['length'] = false;
+ } else {
+ $value['length'] = $this->get_col_length( $table, $field );
+ if ( is_wp_error( $value['length'] ) ) {
+ return false;
+ }
+ }
+
+ $data[ $field ] = $value;
+ }
+
+ return $data;
+ }
+
+ /**
+ * Retrieve one variable from the database.
+ *
+ * Executes a SQL query and returns the value from the SQL result.
+ * If the SQL result contains more than one column and/or more than one row, this function returns the value in the column and row specified.
+ * If $query is null, this function returns the value in the specified column and row from the previous SQL result.
+ *
+ * @since 0.71
+ *
+ * @param string|null $query Optional. SQL query. Defaults to null, use the result from the previous query.
+ * @param int $x Optional. Column of value to return. Indexed from 0.
+ * @param int $y Optional. Row of value to return. Indexed from 0.
+ * @return string|null Database query result (as string), or null on failure
+ */
+ public function get_var( $query = null, $x = 0, $y = 0 ) {
+ $this->func_call = "\$db->get_var(\"$query\", $x, $y)";
+
+ if ( $this->check_safe_collation( $query ) ) {
+ $this->check_current_query = false;
+ }
+
+ if ( $query ) {
+ $this->query( $query );
+ }
+
+ // Extract var out of cached results based x,y vals
+ if ( !empty( $this->last_result[$y] ) ) {
+ $values = array_values( get_object_vars( $this->last_result[$y] ) );
+ }
+
+ // If there is a value return it else return null
+ return ( isset( $values[$x] ) && $values[$x] !== '' ) ? $values[$x] : null;
+ }
+
+ /**
+ * Retrieve one row from the database.
+ *
+ * Executes a SQL query and returns the row from the SQL result.
+ *
+ * @since 0.71
+ *
+ * @param string|null $query SQL query.
+ * @param string $output Optional. one of ARRAY_A | ARRAY_N | OBJECT constants. Return an associative array (column => value, ...),
+ * a numerically indexed array (0 => value, ...) or an object ( ->column = value ), respectively.
+ * @param int $y Optional. Row to return. Indexed from 0.
+ * @return mixed Database query result in format specified by $output or null on failure
+ */
+ public function get_row( $query = null, $output = OBJECT, $y = 0 ) {
+ $this->func_call = "\$db->get_row(\"$query\",$output,$y)";
+
+ if ( $this->check_safe_collation( $query ) ) {
+ $this->check_current_query = false;
+ }
+
+ if ( $query ) {
+ $this->query( $query );
+ } else {
+ return null;
+ }
+
+ if ( !isset( $this->last_result[$y] ) )
+ return null;
+
+ if ( $output == OBJECT ) {
+ return $this->last_result[$y] ? $this->last_result[$y] : null;
+ } elseif ( $output == ARRAY_A ) {
+ return $this->last_result[$y] ? get_object_vars( $this->last_result[$y] ) : null;
+ } elseif ( $output == ARRAY_N ) {
+ return $this->last_result[$y] ? array_values( get_object_vars( $this->last_result[$y] ) ) : null;
+ } elseif ( strtoupper( $output ) === OBJECT ) {
+ // Back compat for OBJECT being previously case insensitive.
+ return $this->last_result[$y] ? $this->last_result[$y] : null;
+ } else {
+ $this->print_error( " \$db->get_row(string query, output type, int offset) -- Output type must be one of: OBJECT, ARRAY_A, ARRAY_N" );
+ }
+ }
+
+ /**
+ * Retrieve one column from the database.
+ *
+ * Executes a SQL query and returns the column from the SQL result.
+ * If the SQL result contains more than one column, this function returns the column specified.
+ * If $query is null, this function returns the specified column from the previous SQL result.
+ *
+ * @since 0.71
+ *
+ * @param string|null $query Optional. SQL query. Defaults to previous query.
+ * @param int $x Optional. Column to return. Indexed from 0.
+ * @return array Database query result. Array indexed from 0 by SQL result row number.
+ */
+ public function get_col( $query = null , $x = 0 ) {
+ if ( $this->check_safe_collation( $query ) ) {
+ $this->check_current_query = false;
+ }
+
+ if ( $query ) {
+ $this->query( $query );
+ }
+
+ $new_array = array();
+ // Extract the column values
+ for ( $i = 0, $j = count( $this->last_result ); $i < $j; $i++ ) {
+ $new_array[$i] = $this->get_var( null, $x, $i );
+ }
+ return $new_array;
+ }
+
+ /**
+ * Retrieve an entire SQL result set from the database (i.e., many rows)
+ *
+ * Executes a SQL query and returns the entire SQL result.
+ *
+ * @since 0.71
+ *
+ * @param string $query SQL query.
+ * @param string $output Optional. Any of ARRAY_A | ARRAY_N | OBJECT | OBJECT_K constants. With one of the first three, return an array of rows indexed from 0 by SQL result row number.
+ * Each row is an associative array (column => value, ...), a numerically indexed array (0 => value, ...), or an object. ( ->column = value ), respectively.
+ * With OBJECT_K, return an associative array of row objects keyed by the value of each row's first column's value. Duplicate keys are discarded.
+ * @return mixed Database query results
+ */
+ public function get_results( $query = null, $output = OBJECT ) {
+ $this->func_call = "\$db->get_results(\"$query\", $output)";
+
+ if ( $this->check_safe_collation( $query ) ) {
+ $this->check_current_query = false;
+ }
+
+ if ( $query ) {
+ $this->query( $query );
+ } else {
+ return null;
+ }
+
+ $new_array = array();
+ if ( $output == OBJECT ) {
+ // Return an integer-keyed array of row objects
+ return $this->last_result;
+ } elseif ( $output == OBJECT_K ) {
+ // Return an array of row objects with keys from column 1
+ // (Duplicates are discarded)
+ foreach ( $this->last_result as $row ) {
+ $var_by_ref = get_object_vars( $row );
+ $key = array_shift( $var_by_ref );
+ if ( ! isset( $new_array[ $key ] ) )
+ $new_array[ $key ] = $row;
+ }
+ return $new_array;
+ } elseif ( $output == ARRAY_A || $output == ARRAY_N ) {
+ // Return an integer-keyed array of...
+ if ( $this->last_result ) {
+ foreach( (array) $this->last_result as $row ) {
+ if ( $output == ARRAY_N ) {
+ // ...integer-keyed row arrays
+ $new_array[] = array_values( get_object_vars( $row ) );
+ } else {
+ // ...column name-keyed row arrays
+ $new_array[] = get_object_vars( $row );
+ }
+ }
+ }
+ return $new_array;
+ } elseif ( strtoupper( $output ) === OBJECT ) {
+ // Back compat for OBJECT being previously case insensitive.
+ return $this->last_result;
+ }
+ return null;
+ }
+
+ /**
+ * Retrieves the character set for the given table.
+ *
+ * @since 4.2.0
+ * @access protected
+ *
+ * @param string $table Table name.
+ * @return string|WP_Error Table character set, WP_Error object if it couldn't be found.
+ */
+ protected function get_table_charset( $table ) {
+ $tablekey = strtolower( $table );
+
+ /**
+ * Filter the table charset value before the DB is checked.
+ *
+ * Passing a non-null value to the filter will effectively short-circuit
+ * checking the DB for the charset, returning that value instead.
+ *
+ * @since 4.2.0
+ *
+ * @param string $charset The character set to use. Default null.
+ * @param string $table The name of the table being checked.
+ */
+ $charset = apply_filters( 'pre_get_table_charset', null, $table );
+ if ( null !== $charset ) {
+ return $charset;
+ }
+
+ if ( isset( $this->table_charset[ $tablekey ] ) ) {
+ return $this->table_charset[ $tablekey ];
+ }
+
+ $charsets = $columns = array();
+
+ $table_parts = explode( '.', $table );
+ $table = '`' . implode( '`.`', $table_parts ) . '`';
+ $results = $this->get_results( "SHOW FULL COLUMNS FROM $table" );
+ if ( ! $results ) {
+ return new WP_Error( 'wpdb_get_table_charset_failure' );
+ }
+
+ foreach ( $results as $column ) {
+ $columns[ strtolower( $column->Field ) ] = $column;
+ }
+
+ $this->col_meta[ $tablekey ] = $columns;
+
+ foreach ( $columns as $column ) {
+ if ( ! empty( $column->Collation ) ) {
+ list( $charset ) = explode( '_', $column->Collation );
+
+ // If the current connection can't support utf8mb4 characters, let's only send 3-byte utf8 characters.
+ if ( 'utf8mb4' === $charset && ! $this->has_cap( 'utf8mb4' ) ) {
+ $charset = 'utf8';
+ }
+
+ $charsets[ strtolower( $charset ) ] = true;
+ }
+
+ list( $type ) = explode( '(', $column->Type );
+
+ // A binary/blob means the whole query gets treated like this.
+ if ( in_array( strtoupper( $type ), array( 'BINARY', 'VARBINARY', 'TINYBLOB', 'MEDIUMBLOB', 'BLOB', 'LONGBLOB' ) ) ) {
+ $this->table_charset[ $tablekey ] = 'binary';
+ return 'binary';
+ }
+ }
+
+ // utf8mb3 is an alias for utf8.
+ if ( isset( $charsets['utf8mb3'] ) ) {
+ $charsets['utf8'] = true;
+ unset( $charsets['utf8mb3'] );
+ }
+
+ // Check if we have more than one charset in play.
+ $count = count( $charsets );
+ if ( 1 === $count ) {
+ $charset = key( $charsets );
+ } elseif ( 0 === $count ) {
+ // No charsets, assume this table can store whatever.
+ $charset = false;
+ } else {
+ // More than one charset. Remove latin1 if present and recalculate.
+ unset( $charsets['latin1'] );
+ $count = count( $charsets );
+ if ( 1 === $count ) {
+ // Only one charset (besides latin1).
+ $charset = key( $charsets );
+ } elseif ( 2 === $count && isset( $charsets['utf8'], $charsets['utf8mb4'] ) ) {
+ // Two charsets, but they're utf8 and utf8mb4, use utf8.
+ $charset = 'utf8';
+ } else {
+ // Two mixed character sets. ascii.
+ $charset = 'ascii';
+ }
+ }
+
+ $this->table_charset[ $tablekey ] = $charset;
+ return $charset;
+ }