Make WordPress Core

Changeset 32162


Ignore:
Timestamp:
04/20/2015 04:45:12 AM (11 years ago)
Author:
pento
Message:

WPDB: When sanity checking read queries, there are some collations we can skip, for improved performance.

Props pento, nacin.

See #21212.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/wp-db.php

    r32116 r32162  
    170170         */
    171171        protected $check_current_query = true;
     172
     173        /**
     174         * Flag to ensure we don't run into recursion problems when checking the collation.
     175         *
     176         * @since 4.2.0
     177         * @access private
     178         * @see wpdb::check_safe_collation()
     179         * @var boolean
     180         */
     181        private $checking_collation = false;
    172182
    173183        /**
     
    20392049                $this->func_call = "\$db->get_var(\"$query\", $x, $y)";
    20402050
     2051                if ( $this->check_safe_collation( $query ) ) {
     2052                        $this->check_current_query = false;
     2053                }
     2054
    20412055                if ( $query ) {
    20422056                        $this->query( $query );
     
    20672081        public function get_row( $query = null, $output = OBJECT, $y = 0 ) {
    20682082                $this->func_call = "\$db->get_row(\"$query\",$output,$y)";
     2083
     2084                if ( $this->check_safe_collation( $query ) ) {
     2085                        $this->check_current_query = false;
     2086                }
     2087
    20692088                if ( $query ) {
    20702089                        $this->query( $query );
     
    21042123         */
    21052124        public function get_col( $query = null , $x = 0 ) {
     2125                if ( $this->check_safe_collation( $query ) ) {
     2126                        $this->check_current_query = false;
     2127                }
     2128
    21062129                if ( $query ) {
    21072130                        $this->query( $query );
     
    21312154        public function get_results( $query = null, $output = OBJECT ) {
    21322155                $this->func_call = "\$db->get_results(\"$query\", $output)";
     2156
     2157                if ( $this->check_safe_collation( $query ) ) {
     2158                        $this->check_current_query = false;
     2159                }
    21332160
    21342161                if ( $query ) {
     
    23602387
    23612388        /**
     2389         * Check if the query is accessing a collation considered safe on the current version of MySQL.
     2390         *
     2391         * @since 4.2.0
     2392         * @access protected
     2393         *
     2394         * @param string $query The query to check.
     2395         * @return bool True if the collation is safe, false if it isn't.
     2396         */
     2397        protected function check_safe_collation( $query ) {
     2398                if ( $this->checking_collation ) {
     2399                        return true;
     2400                }
     2401
     2402                $table = $this->get_table_from_query( $query );
     2403                if ( ! $table ) {
     2404                        return false;
     2405                }
     2406
     2407                $this->checking_collation = true;
     2408                $this->get_table_charset( $table );
     2409                $this->checking_collation = false;
     2410
     2411                $table = strtolower( $table );
     2412                if ( empty( $this->col_meta[ $table ] ) ) {
     2413                        return false;
     2414                }
     2415
     2416                foreach( $this->col_meta[ $table ] as $col ) {
     2417                        if ( empty( $col->Collation ) ) {
     2418                                continue;
     2419                        }
     2420
     2421                        if ( ! in_array( $col->Collation, array( 'utf8_general_ci', 'utf8_bin', 'utf8mb4_general_ci', 'utf8mb4_bin' ), true ) ) {
     2422                                return false;
     2423                        }
     2424                }
     2425
     2426                return true;
     2427        }
     2428
     2429        /**
    23622430         * Strips any invalid characters based on value/charset pairs.
    23632431         *
  • trunk/tests/phpunit/tests/db/charset.php

    r31953 r32162  
    464464                $this->assertFalse( $wpdb->query( "INSERT INTO {$wpdb->posts} (post_content) VALUES ('foo\xf0\xff\xff\xffbar')" ) );
    465465        }
     466
     467        /**
     468         * @ticket 21212
     469         */
     470        function data_table_collation_check() {
     471                $table_name = 'table_collation_check';
     472                $data = array(
     473                        array(
     474                                // utf8_bin tables don't need extra sanity checking.
     475                                "( a VARCHAR(50) COLLATE utf8_bin )", // create
     476                                true                                  // expected result
     477                        ),
     478                        array(
     479                                // Neither do utf8_general_ci tables.
     480                                "( a VARCHAR(50) COLLATE utf8_general_ci )",
     481                                true
     482                        ),
     483                        array(
     484                                // utf8_unicode_ci tables do.
     485                                "( a VARCHAR(50) COLLATE utf8_unicode_ci )",
     486                                false
     487                        ),
     488                        array(
     489                                // utf8_bin tables don't need extra sanity checking,
     490                                // except for when they're not just utf8_bin.
     491                                "( a VARCHAR(50) COLLATE utf8_bin, b VARCHAR(50) COLLATE big5_chinese_ci )",
     492                                false
     493                        ),
     494                        array(
     495                                // utf8_bin tables don't need extra sanity checking
     496                                // when the other columns aren't strings.
     497                                "( a VARCHAR(50) COLLATE utf8_bin, b INT )",
     498                                true
     499                        ),
     500                );
     501
     502                foreach( $data as &$value ) {
     503                        $this_table_name = $table_name . '_' . rand_str( 5 );
     504
     505                        $value[0] = "CREATE TABLE $this_table_name {$value[0]}";
     506                        $value[2] = "SELECT * FROM $this_table_name";
     507                        $value[3] = "DROP TABLE IF EXISTS $this_table_name";
     508                }
     509                unset( $value );
     510
     511                return $data;
     512        }
     513
     514
     515        /**
     516         * @dataProvider data_table_collation_check
     517         * @ticket 21212
     518         */
     519        function test_table_collation_check( $create, $expected, $query, $drop ) {
     520                self::$_wpdb->query( $drop );
     521
     522                self::$_wpdb->query( $create );
     523
     524                $return = self::$_wpdb->check_safe_collation( $query );
     525                $this->assertEquals( $expected, $return );
     526
     527                self::$_wpdb->query( $drop );
     528        }
    466529}
Note: See TracChangeset for help on using the changeset viewer.