Plugin Directory

Changeset 1410864


Ignore:
Timestamp:
05/05/2016 09:26:19 AM (10 years ago)
Author:
vnsavage
Message:

Various improvements:

  • Add MySQLi support with MySQL fallback
  • Handle and retry MySQL timeouts
  • Add support for track server states
  • Add callbacks for: pre/post connect queries, pre/post query statements, adding query comments
  • Better integration with the latest core wp-db features
File:
1 edited

Legend:

Unmodified
Added
Removed
  • hyperdb/trunk/db.php

    r1398095 r1410864  
    4040define( 'HYPERDB_LAG_UNKNOWN', 3 );
    4141
     42define( 'HYPERDB_CONN_HOST_ERROR', 2003 );   // Can't connect to MySQL server on '%s' (%d)
     43define( 'HYPERDB_SERVER_GONE_ERROR', 2006 ); // MySQL server has gone away
     44
    4245class hyperdb extends wpdb {
    4346    /**
     
    100103
    101104    /**
    102      * Whether to use mysql_pconnect instead of mysql_connect
     105     * Whether to use persistent connections
    103106     * @var bool
    104107     */
     
    113116
    114117    /**
    115      * Whether to check with fsockopen prior to mysql_connect.
     118     * Whether to check with fsockopen prior to connecting to mysql.
    116119     * @var bool
    117120     */
     
    143146
    144147    /**
    145      * Lookup array (dbhname => host:port)
    146      * @var array
    147      */
    148     var $dbh2host = array();
    149 
    150     /**
    151148     * The last server used and the database name selected
    152149     * @var array
     
    172169     */
    173170    var $default_lag_threshold = null;
     171
     172    /**
     173     * Lookup array (dbhname => host:port)
     174     * @var array
     175     */
     176    var $dbh2host = array();
     177
     178    /**
     179     * Keeps track of the dbhname usage and errors.
     180     */
     181    var $dbhname_heartbeats = array();
     182
     183    /**
     184     * Triggers __construct() for backwards compatibility with PHP4
     185     */
     186    function hyperdb( $args = null ) {
     187        return $this->__construct($args);
     188    }
    174189
    175190    /**
     
    183198                    $this->$var = $args[$var];
    184199
     200        $this->use_mysqli = $this->should_use_mysqli();
     201
    185202        $this->init_charset();
    186     }
    187 
    188     /**
    189      * Triggers __construct() for backwards compatibility with PHP4
    190      */
    191     function hyperdb( $args = null ) {
    192         return $this->__construct($args);
    193203    }
    194204
     
    248258     * @return string table
    249259     */
    250     function get_table_from_query ( $q ) {
     260    function get_table_from_query( $q ) {
    251261        // Remove characters that can legally trail the table name
    252262        $q = rtrim($q, ';/-#');
    253263        // allow (select...) union [...] style queries. Use the first queries table name.
    254264        $q = ltrim($q, "\t (");
     265        // Strip everything between parentheses except nested
     266        // selects and use only 1000 chars of the query
     267        $q = preg_replace( '/\((?!\s*select)[^(]*?\)/is', '()', substr( $q, 0, 1000 ) );
     268
     269        // Refer to the previous query
     270        // wpdb doesn't implement last_table, so we run it first.
     271        if ( preg_match('/^\s*SELECT.*?\s+FOUND_ROWS\(\)/is', $q) )
     272            return $this->last_table;
     273
     274        if( method_exists( get_parent_class( $this ), 'get_table_from_query' ) ) {
     275            // WPDB has added support for get_table_from_query, which should take precedence
     276            return parent::get_table_from_query( $q );
     277        }
    255278
    256279        // Quickly match most common queries
     
    263286                . ')\s+`?([\w-]+)`?/is', $q, $maybe) )
    264287            return $maybe[1];
    265 
    266         // Refer to the previous query
    267         if ( preg_match('/^\s*SELECT.*?\s+FOUND_ROWS\(\)/is', $q) )
    268             return $this->last_table;
    269288
    270289        // SHOW TABLE STATUS and SHOW TABLES
     
    321340     */
    322341    function run_callbacks( $group, $args = null) {
    323         if ( !isset( $this->hyper_callbacks[ $group ] ) || !is_array( $this->hyper_callbacks[ $group ] ) )
     342        if ( ! isset( $this->hyper_callbacks[ $group ] ) || ! is_array( $this->hyper_callbacks[ $group ] ) )
    324343            return null;
    325344
    326         if ( !isset($args) ) {
     345        if ( ! isset( $args ) ) {
    327346            $args = array( &$this );
    328347        } elseif ( is_array( $args ) ) {
     
    345364     */
    346365    function db_connect( $query = '' ) {
    347         $connect_function = $this->persistent ? 'mysql_pconnect' : 'mysql_connect';
    348 
    349366        if ( empty( $query ) )
    350367            return false;
     
    373390
    374391        if ( empty( $this->hyper_servers ) ) {
    375             if ( is_resource( $this->dbh ) )
     392            if ( $this->is_mysql_connection( $this->dbh ) )
    376393                return $this->dbh;
    377394            if (
     
    381398                || !defined('DB_NAME') )
    382399                return $this->bail("We were unable to query because there was no database defined.");
    383             $this->dbh = @ $connect_function(DB_HOST, DB_USER, DB_PASSWORD, true);
    384             if ( ! is_resource( $this->dbh ) )
     400            $this->dbh = $this->ex_mysql_connect( DB_HOST, DB_USER, DB_PASSWORD, $this->persistent );
     401            if ( ! $this->is_mysql_connection( $this->dbh ) )
    385402                return $this->bail("We were unable to connect to the database. (DB_HOST)");
    386             if ( ! mysql_select_db(DB_NAME, $this->dbh) )
     403            if ( ! $this->ex_mysql_select_db( DB_NAME, $this->dbh ) )
    387404                return $this->bail("We were unable to select the database.");
    388405            if ( ! empty( $this->charset ) ) {
    389                 $_collate = ! empty( $this->collate ) ? $this->collate : null;
    390                 $this->set_charset( $this->dbh, $this->charset, $_collate );
    391             }
    392 
     406                $collation_query = "SET NAMES '$this->charset'";
     407                if ( !empty( $this->collate ) )
     408                    $collation_query .= " COLLATE '$this->collate'";
     409                $this->ex_mysql_query( $collation_query, $this->dbh );
     410            }
    393411            return $this->dbh;
    394412        }
     
    424442
    425443        // Try to reuse an existing connection
    426         while ( isset( $this->dbhs[$dbhname] ) && is_resource( $this->dbhs[$dbhname] ) ) {
     444        while ( isset( $this->dbhs[$dbhname] ) && $this->is_mysql_connection( $this->dbhs[$dbhname] ) ) {
    427445            // Find the connection for incrementing counters
    428446            foreach ( array_keys($this->db_connections) as $i )
     
    434452                // A callback has specified a database name so it's possible the existing connection selected a different one.
    435453                if ( $name != $this->used_servers[$dbhname]['name'] ) {
    436                     if ( !mysql_select_db($name, $this->dbhs[$dbhname]) ) {
     454                    if ( ! $this->ex_mysql_select_db( $name, $this->dbhs[$dbhname] ) ) {
    437455                        // this can happen when the user varies and lacks permission on the $name database
    438456                        if ( isset( $conn['disconnect (select failed)'] ) )
     
    461479            $this->last_connection = compact('dbhname', 'name');
    462480
    463             if ( !mysql_ping($this->dbhs[$dbhname]) ) {
     481            if ( $this->should_mysql_ping() && ! $this->ex_mysql_ping( $this->dbhs[$dbhname] ) ) {
    464482                if ( isset( $conn['disconnect (ping failed)'] ) )
    465483                    ++$conn['disconnect (ping failed)'];
     
    495513                $keys = array_keys($items);
    496514                shuffle($keys);
    497                 foreach ( $keys as $key ) 
     515                foreach ( $keys as $key )
    498516                    $servers[] = compact('group', 'key');
    499517            }
    500518
    501             if ( !$tries_remaining = count( $servers ) ) 
     519            if ( !$tries_remaining = count( $servers ) )
    502520                return $this->bail("No database servers were found to match the query. ($this->table, $dataset)");
    503521
     
    522540                extract($group_key, EXTR_OVERWRITE);
    523541
    524                 // $host, $user, $password, $name, $read, $write [, $lag_threshold, $connect_function, $timeout ]
     542                // $host, $user, $password, $name, $read, $write [, $lag_threshold, $timeout ]
    525543                extract($this->hyper_servers[$dataset][$operation][$group][$key], EXTR_OVERWRITE);
    526544                $port = null;
     
    574592
    575593                // Connect if necessary or possible
    576                 $tcp = null;
    577                 if ( $use_master || !$tries_remaining || !$this->check_tcp_responsiveness
    578                     || true === $tcp = $this->check_tcp_responsiveness($host, $port, $timeout) )
     594                $server_state = null;
     595                if ( $use_master || ! $tries_remaining ||
     596                    'up' == $server_state = $this->get_server_state( $host, $port, $timeout ) )
    579597                {
    580                     $this->dbhs[$dbhname] = @ $connect_function( "$host:$port", $user, $password, true );
     598                    $this->set_connect_timeout( 'pre_connect', $use_master, $tries_remaining );
     599                    $this->dbhs[$dbhname] = $this->ex_mysql_connect( "$host:$port", $user, $password, $this->persistent );
     600                    $this->set_connect_timeout( 'post_connect', $use_master, $tries_remaining );
    581601                } else {
    582602                    $this->dbhs[$dbhname] = false;
     
    585605                $elapsed = $this->timer_stop();
    586606
    587                 if ( is_resource( $this->dbhs[$dbhname] ) ) {
     607                if ( $this->is_mysql_connection( $this->dbhs[$dbhname] ) ) {
    588608                    /**
    589609                     * If we care about lag, disconnect lagged slaves and try to find others.
     
    607627                        $this->print_error( $msg );
    608628                        continue;
    609                     } elseif ( mysql_select_db( $name, $this->dbhs[ $dbhname ] ) ) {
     629                    } elseif ( $this->ex_mysql_select_db( $name, $this->dbhs[$dbhname] ) ) {
    610630                        $success = true;
    611631                        $this->current_host = "$host:$port";
     
    620640                }
    621641
     642                if ( 'down' == $server_state )
     643                    continue; // don't flood the logs if already down
     644
     645                if ( HYPERDB_CONN_HOST_ERROR == $this->ex_mysql_errno() &&
     646                    ( 'up' == $server_state || ! $tries_remaining ) )
     647                {
     648                    $this->mark_server_as_down( $host, $port );
     649                    $server_state = 'down';
     650                }
     651
    622652                $success = false;
    623653                $this->last_connection = compact('dbhname', 'host', 'port', 'user', 'name', 'tcp', 'elapsed', 'success');
     
    627657                $msg .= "'server' => {$server},\n";
    628658                $msg .= "'host' => {$host},\n";
    629                 $msg .= "'error' => " . mysql_error() . ",\n";
    630                 $msg .= "'errno' => " . mysql_errno() . ",\n";
    631                 $msg .= "'tcp_responsive' => " . ( $tcp === true ? 'true' : $tcp ) . ",\n";
     659                $msg .= "'error' => " . $this->ex_mysql_error() . ",\n";
     660                $msg .= "'errno' => " . $this->ex_mysql_errno() . ",\n";
     661                $msg .= "'server_state' => $server_state\n";
    632662                $msg .= "'lagged_status' => " . ( isset( $lagged_status ) ? $lagged_status : HYPERDB_LAG_UNKNOWN );
    633663
     
    635665            }
    636666
    637             if ( !$success || !isset($this->dbhs[$dbhname]) || !is_resource( $this->dbhs[$dbhname] ) ) {
     667            if ( ! $success || ! isset( $this->dbhs[$dbhname] ) || ! $this->is_mysql_connection( $this->dbhs[$dbhname] ) ) {
    638668                if ( !isset( $ignore_slave_lag ) && count( $unique_lagged_slaves ) ) {
    639669                    // Lagged slaves were not used. Ignore the lag for this connection attempt and retry.
     
    682712    }
    683713
     714    /**
     715     * Sets the connection's character set.
     716     * @param resource $dbh     The resource given by ex_mysql_connect
     717     * @param string   $charset The character set (optional)
     718     * @param string   $collate The collation (optional)
     719     */
     720    function set_charset($dbh, $charset = null, $collate = null) {
     721        if ( !isset($charset) )
     722            $charset = $this->charset;
     723        if ( !isset($collate) )
     724            $collate = $this->collate;
     725
     726        if ( ! $this->has_cap( 'collation', $dbh ) || empty( $charset ) )
     727            return;
     728
     729        if ( ! in_array( strtolower( $charset ), array( 'utf8', 'latin1' ) ) )
     730            wp_die( "$charset charset isn't supported in HyperDB for security reasons" );
     731
     732        if ( $this->is_mysql_set_charset_callable() && $this->has_cap( 'set_charset', $dbh ) ) {
     733            $this->ex_mysql_set_charset( $charset, $dbh );
     734            $this->real_escape = true;
     735        } else {
     736            $query = $this->prepare( 'SET NAMES %s', $charset );
     737            if ( ! empty( $collate ) )
     738                $query .= $this->prepare( ' COLLATE %s', $collate );
     739            $this->ex_mysql_query( $query, $dbh );
     740        }
     741    }
    684742
    685743    /*
     
    690748     * This is also the reason why we don't allow certain charsets. See set_charset().
    691749     */
    692     function _real_escape( $string ) {
     750    function _real_escape( $string ) {
    693751        return addslashes( $string );
    694     }
    695 
    696     /**
    697      * Sets the connection's character set.
    698      * @param resource $dbh     The resource given by mysql_connect
    699      * @param string   $charset The character set (optional)
    700      * @param string   $collate The collation (optional)
    701      */
    702     function set_charset($dbh, $charset = null, $collate = null) {
    703         if ( ! isset( $charset ) )
    704             $charset = $this->charset;
    705         if ( ! isset( $collate ) )
    706             $collate = $this->collate;
    707 
    708         if ( ! in_array( strtolower( $charset ), array( 'utf8', 'latin1' ) ) )
    709             wp_die( "$charset charset isn't supported in HyperDB for security reasons" );
    710 
    711         if ( $this->has_cap( 'collation', $dbh ) && !empty( $charset ) ) {
    712             if ( function_exists( 'mysql_set_charset' ) && $this->has_cap( 'set_charset', $dbh ) ) {
    713                 mysql_set_charset( $charset, $dbh );
    714                 $this->real_escape = true;
    715             } else {
    716                 $query = $this->prepare( 'SET NAMES %s', $charset );
    717                 if ( ! empty( $collate ) )
    718                     $query .= $this->prepare( ' COLLATE %s', $collate );
    719                 mysql_query( $query, $dbh );
    720             }
    721         }
    722752    }
    723753
     
    727757     */
    728758    function disconnect($dbhname) {
    729         if ( $k = array_search($dbhname, $this->open_connections) )
     759        if ( false !== $k = array_search($dbhname, $this->open_connections) )
    730760            unset($this->open_connections[$k]);
    731761
    732         if ( is_resource($this->dbhs[$dbhname]) )
    733             mysql_close($this->dbhs[$dbhname]);
     762        if ( $this->is_mysql_connection( $this->dbhs[$dbhname] ) )
     763            $this->ex_mysql_close( $this->dbhs[$dbhname] );
    734764
    735765        unset($this->dbhs[$dbhname]);
     
    750780     * @return int number of rows
    751781     */
    752     function query($query) {
     782    function query( $query ) {
    753783        // some queries are made before the plugins have been loaded, and thus cannot be filtered with this method
    754784        if ( function_exists('apply_filters') )
     
    765795        $this->last_query = $query;
    766796
    767         if ( preg_match('/^\s*SELECT\s+FOUND_ROWS(\s*)/i', $query) && is_resource($this->last_found_rows_result) ) {
     797        if ( preg_match( '/^\s*SELECT\s+FOUND_ROWS(\s*)/i', $query ) && $this->is_mysql_result( $this->last_found_rows_result ) ) {
    768798            $this->result = $this->last_found_rows_result;
    769799            $elapsed = 0;
     
    771801            $this->dbh = $this->db_connect( $query );
    772802
    773             if ( ! is_resource($this->dbh) )
     803            if ( ! $this->is_mysql_connection( $this->dbh ) ) {
     804                $this->check_current_query = true;
    774805                return false;
     806            }
     807
     808            $query_comment = $this->run_callbacks( 'get_query_comment', $query );
     809            if ( ! empty( $query_comment ) )
     810                $query = rtrim( $query, ";\t \n\r" ) . ' /* ' . $query_comment . ' */';
     811
     812            // If we're writing to the database, make sure the query will write safely.
     813            if ( $this->check_current_query && method_exists( $this, 'check_ascii' ) && ! $this->check_ascii( $query ) ) {
     814                $stripped_query = $this->strip_invalid_text_from_query( $query );
     815                if ( $stripped_query !== $query ) {
     816                    $this->insert_id = 0;
     817                    return false;
     818                }
     819            }
     820
     821            $this->check_current_query = true;
     822
     823            // Inject setup and teardown statements
     824            $statement_before_query = $this->run_callbacks( 'statement_before_query' );
     825            $statement_after_query = $this->run_callbacks( 'statement_after_query' );
     826            $query_for_log = $query;
    775827
    776828            $this->timer_start();
    777             $this->result = mysql_query($query, $this->dbh);
     829            if ( $statement_before_query ) {
     830                $query_for_log = "$statement_before_query; $query_for_log";
     831                $this->ex_mysql_query( $statement_before_query, $this->dbh );
     832            }
     833
     834            $this->result = $this->ex_mysql_query( $query, $this->dbh );
     835
     836            if ( $statement_after_query ) {
     837                $query_for_log = "$query_for_log; $statement_after_query";
     838                $this->ex_mysql_query( $statement_after_query, $this->dbh );
     839            }
    778840            $elapsed = $this->timer_stop();
    779841            ++$this->num_queries;
     
    782844                if ( false === strpos($query, "NO_SELECT_FOUND_ROWS") ) {
    783845                    $this->timer_start();
    784                     $this->last_found_rows_result = mysql_query("SELECT FOUND_ROWS()", $this->dbh);
     846                    $this->last_found_rows_result = $this->ex_mysql_query( "SELECT FOUND_ROWS()", $this->dbh );
    785847                    $elapsed += $this->timer_stop();
    786848                    ++$this->num_queries;
     
    791853            }
    792854
     855            $this->dbhname_heartbeats[$this->dbhname]['last_used'] = microtime( true );
     856
    793857            if ( $this->save_queries ) {
    794858                if ( is_callable($this->save_query_callback) )
    795                     $this->queries[] = call_user_func_array( $this->save_query_callback, array( $query, $elapsed, $this->save_backtrace ? debug_backtrace( false ) : null, &$this ) );
     859                    $this->queries[] = call_user_func_array( $this->save_query_callback, array( $query_for_log, $elapsed, $this->save_backtrace ? debug_backtrace( false ) : null, &$this ) );
    796860                else
    797                     $this->queries[] = array( $query, $elapsed, $this->get_caller() );
     861                    $this->queries[] = array( $query_for_log, $elapsed, $this->get_caller() );
    798862            }
    799863        }
    800864
    801865        // If there is an error then take note of it
    802         if ( $this->last_error = mysql_error($this->dbh) ) {
     866        if ( $this->last_error = $this->ex_mysql_error( $this->dbh ) ) {
     867            $this->dbhname_heartbeats[$this->dbhname]['last_errno'] = $this->ex_mysql_errno( $this->dbh );
    803868            $this->print_error($this->last_error);
    804869            return false;
    805870        }
    806871
    807         if ( preg_match("/^\\s*(insert|delete|update|replace|alter) /i",$query) ) {
    808             $this->rows_affected = mysql_affected_rows($this->dbh);
     872        if ( preg_match('/^\s*(insert|delete|update|replace|alter)\s/i',$query) ) {
     873            $this->rows_affected = $this->ex_mysql_affected_rows( $this->dbh );
    809874
    810875            // Take note of the insert_id
    811             if ( preg_match("/^\\s*(insert|replace) /i",$query) ) {
    812                 $this->insert_id = mysql_insert_id($this->dbh);
     876            if ( preg_match('/^\s*(insert|replace)\s/i',$query) ) {
     877                $this->insert_id = $this->ex_mysql_insert_id( $this->dbh );
    813878            }
    814879            // Return number of rows affected
     
    817882            $i = 0;
    818883            $this->col_info = array();
    819             while ($i < @mysql_num_fields($this->result)) {
    820                 $this->col_info[$i] = @mysql_fetch_field($this->result);
     884            while ( $i < $this->ex_mysql_num_fields( $this->result ) ) {
     885                $this->col_info[$i] = $this->ex_mysql_fetch_field( $this->result );
    821886                $i++;
    822887            }
    823888            $num_rows = 0;
    824889            $this->last_result = array();
    825             while ( $row = @mysql_fetch_object($this->result) ) {
     890            while ( $row = $this->ex_mysql_fetch_object( $this->result ) ) {
    826891                $this->last_result[$num_rows] = $row;
    827892                $num_rows++;
    828893            }
    829894
    830             @mysql_free_result($this->result);
     895            $this->ex_mysql_free_result( $this->result );
     896            $this->result = null;
    831897
    832898            // Log number of rows the query returned
     
    897963        if ( !$dbh_or_table && $this->dbh )
    898964            $dbh =& $this->dbh;
    899         elseif ( is_resource( $dbh_or_table ) )
     965        elseif ( $this->is_mysql_connection( $dbh_or_table ) )
    900966            $dbh =& $dbh_or_table;
    901967        else
     
    903969
    904970        if ( $dbh )
    905             return preg_replace('/[^0-9.].*/', '', mysql_get_server_info( $dbh ));
     971            return preg_replace( '/[^0-9.].*/', '', $this->ex_mysql_get_server_info( $dbh ) );
    906972        return false;
    907973    }
     
    9421008    /**
    9431009     * Check the responsiveness of a tcp/ip daemon
    944      * @return (bool) true when $host:$post responds within $float_timeout seconds, else (bool) false
     1010     * @return (string) 'up' when $host:$post responds within $float_timeout seconds,
     1011     * otherwise a string with details about the failure.
    9451012     */
    9461013    function check_tcp_responsiveness( $host, $port, $float_timeout ) {
    9471014        if ( function_exists( 'apc_store' ) ) {
    9481015            $use_apc = true;
    949             $apc_key = "{$host}{$port}";
     1016            $apc_key = "tcp_responsive_{$host}{$port}";
    9501017            $apc_ttl = 10;
    9511018        } else {
     
    9541021
    9551022        if ( $use_apc ) {
    956             $cached_value = apc_fetch( $apc_key );
    957             switch ( $cached_value ) {
    958                 case 'up':
    959                     $this->tcp_responsive = 'true';
    960                     return true;
    961                 case 'down':
    962                     $this->tcp_responsive = 'false';
    963                     return false;
    964             }
     1023            $server_state = apc_fetch( $apc_key );
     1024            if ( $server_state )
     1025                return $server_state;
    9651026        }
    9661027
    9671028        $socket = @ fsockopen( $host, $port, $errno, $errstr, $float_timeout );
    9681029        if ( $socket === false ) {
     1030            $server_state = "down [ > $float_timeout ] ($errno) '$errstr'";
    9691031            if ( $use_apc )
    970                 apc_store( $apc_key, 'down', $apc_ttl );
    971             return "[ > $float_timeout ] ($errno) '$errstr'";
     1032                apc_store( $apc_key, $server_state, $apc_ttl );
     1033
     1034            return $server_state;
    9721035        }
    9731036
     
    9771040            apc_store( $apc_key, 'up', $apc_ttl );
    9781041
    979         return true;
     1042        return 'up';
     1043    }
     1044
     1045    function get_server_state( $host, $port, $timeout ) {
     1046        // We still do the check_tcp_responsiveness() until we have
     1047        // mysql connect function with less than 1 second timeout
     1048        if ( $this->check_tcp_responsiveness ) {
     1049            $server_state = $this->check_tcp_responsiveness( $host, $port, $timeout );
     1050            if ( 'up' !== $server_state )
     1051                return $server_state;
     1052        }
     1053
     1054        if ( ! function_exists( 'apc_store' ) )
     1055            return 'up';
     1056
     1057        $server_state = apc_fetch( "server_state_$host$port" );
     1058        if ( ! $server_state )
     1059            return 'up';
     1060
     1061        return $server_state;
     1062    }
     1063
     1064    function mark_server_as_down( $host, $port, $apc_ttl = 10 ) {
     1065        if ( ! function_exists( 'apc_store' ) )
     1066            return;
     1067
     1068        apc_add( "server_state_$host$port", 'down', $apc_ttl );
     1069    }
     1070
     1071    function set_connect_timeout( $tag, $use_master, $tries_remaining ) {
     1072        static $default_connect_timeout;
     1073
     1074        if ( ! isset ( $default_connect_timeout ) )
     1075            $default_connect_timeout = $this->ex_mysql_connect_timeout();
     1076
     1077        switch ( $tag ) {
     1078            case 'pre_connect':
     1079                if ( ! $use_master && $tries_remaining )
     1080                    $this->ex_mysql_connect_timeout( 1 );
     1081                break;
     1082            case 'post_connect':
     1083            default:
     1084                if ( ! $use_master && $tries_remaining )
     1085                    $this->ex_mysql_connect_timeout( $default_connect_timeout );
     1086                break;
     1087        }
    9801088    }
    9811089
     
    10021110    }
    10031111
     1112    function should_use_mysqli() {
     1113        if ( ! function_exists( 'mysqli_connect' ) )
     1114            return false;
     1115
     1116        if ( defined( 'WP_USE_EXT_MYSQL' ) && WP_USE_EXT_MYSQL )
     1117            return false;
     1118
     1119        return true;
     1120    }
     1121
     1122    function should_mysql_ping() {
     1123        // Shouldn't happen
     1124        if ( ! isset( $this->dbhname_heartbeats[$this->dbhname] ) )
     1125            return true;
     1126
     1127        // MySQL server has gone away
     1128        if ( isset( $this->dbhname_heartbeats[$this->dbhname]['last_errno'] ) &&
     1129            HYPERDB_SERVER_GONE_ERROR == $this->dbhname_heartbeats[$this->dbhname]['last_errno'] )
     1130        {
     1131            unset( $this->dbhname_heartbeats[$this->dbhname]['last_errno'] );
     1132            return true;
     1133        }
     1134
     1135        // More than 0.1 seconds of inactivity on that dbhname
     1136        if ( microtime( true ) - $this->dbhname_heartbeats[$this->dbhname]['last_used'] > 0.1 )
     1137            return true;
     1138
     1139        return false;
     1140    }
     1141
     1142    function is_mysql_connection( $dbh ) {
     1143        if ( ! $this->use_mysqli )
     1144            return is_resource( $dbh );
     1145
     1146        return $dbh instanceof mysqli;
     1147    }
     1148
     1149    function is_mysql_result( $result ) {
     1150        if ( ! $this->use_mysqli )
     1151            return is_resource( $result );
     1152
     1153        return $result instanceof mysqli_result;
     1154    }
     1155
     1156    function is_mysql_set_charset_callable() {
     1157        if ( ! $this->use_mysqli )
     1158            return function_exists( 'mysql_set_charset' );
     1159
     1160        return function_exists( 'mysqli_set_charset' );
     1161    }
     1162
     1163    // MySQL execution functions.
     1164    // They perform the appropriate calls based on whether we use MySQLi.
     1165
     1166    function ex_mysql_query( $query, $dbh ) {
     1167        if ( ! $this->use_mysqli )
     1168            return mysql_query( $query, $dbh );
     1169
     1170        return mysqli_query( $dbh, $query );
     1171    }
     1172
     1173    function ex_mysql_unbuffered_query( $query, $dbh ) {
     1174        if ( ! $this->use_mysqli )
     1175            return mysql_unbuffered_query( $query, $dbh );
     1176
     1177        return mysqli_query( $dbh, $query, MYSQLI_USE_RESULT );
     1178    }
     1179
     1180    function ex_mysql_connect( $db_host, $db_user, $db_password, $persistent ) {
     1181        if ( ! $this->use_mysqli ) {
     1182            $connect_function = $persistent ? 'mysql_pconnect' : 'mysql_connect';
     1183            return @$connect_function( $db_host, $db_user, $db_password, true );
     1184        }
     1185
     1186        $dbh = mysqli_init();
     1187
     1188        // mysqli_real_connect doesn't support the host param including a port or socket
     1189        // like mysql_connect does. This duplicates how mysql_connect detects a port and/or socket file.
     1190        $port = null;
     1191        $socket = null;
     1192        $port_or_socket = strstr( $db_host, ':' );
     1193        if ( ! empty( $port_or_socket ) ) {
     1194            $db_host = substr( $db_host, 0, strpos( $db_host, ':' ) );
     1195            $port_or_socket = substr( $port_or_socket, 1 );
     1196            if ( 0 !== strpos( $port_or_socket, '/' ) ) {
     1197                $port = intval( $port_or_socket );
     1198                $maybe_socket = strstr( $port_or_socket, ':' );
     1199                if ( ! empty( $maybe_socket ) ) {
     1200                    $socket = substr( $maybe_socket, 1 );
     1201                }
     1202            } else {
     1203                $socket = $port_or_socket;
     1204            }
     1205        }
     1206
     1207        if ( $persistent )
     1208            $db_host = "p:{$db_host}";
     1209
     1210        $retval = mysqli_real_connect( $dbh, $db_host, $db_user, $db_password, null, $port, $socket );
     1211
     1212        if ( ! $retval || $dbh->connect_errno )
     1213            return false;
     1214
     1215        return $dbh;
     1216    }
     1217
     1218    function ex_mysql_select_db( $db_name, $dbh ) {
     1219        if ( ! $this->use_mysqli )
     1220            return @mysql_select_db( $db_name, $dbh );
     1221
     1222        return @mysqli_select_db( $dbh, $db_name );
     1223    }
     1224
     1225    function ex_mysql_close( $dbh ) {
     1226        if ( ! $this->use_mysqli )
     1227            return mysql_close( $dbh );
     1228
     1229        return mysqli_close( $dbh );
     1230    }
     1231
     1232    function ex_mysql_set_charset( $charset, $dbh ) {
     1233        if ( ! $this->use_mysqli )
     1234            return mysql_set_charset( $charset, $dbh );
     1235
     1236        return mysqli_set_charset( $dbh, $charset );
     1237    }
     1238
     1239    function ex_mysql_errno( $dbh = null ) {
     1240        if ( ! $this->use_mysqli )
     1241            return is_resource( $dbh ) ? mysql_errno( $dbh ) : mysql_errno();
     1242
     1243        if ( is_null( $dbh ) )
     1244            return mysqli_connect_errno();
     1245
     1246        return mysqli_errno( $dbh );
     1247    }
     1248
     1249    function ex_mysql_error( $dbh = null ) {
     1250        if ( ! $this->use_mysqli )
     1251            return is_resource( $dbh ) ? mysql_error( $dbh ) : mysql_error();
     1252
     1253        if ( is_null( $dbh ) )
     1254            return mysqli_connect_error();
     1255
     1256        if ( ! $this->is_mysql_connection( $dbh ) )
     1257            return false;
     1258
     1259        return mysqli_error( $dbh );
     1260    }
     1261
     1262    function ex_mysql_ping( $dbh ) {
     1263        if ( ! $this->use_mysqli )
     1264            return @mysql_ping( $dbh );
     1265
     1266        return @mysqli_ping( $dbh );
     1267    }
     1268
     1269    function ex_mysql_affected_rows( $dbh ) {
     1270        if ( ! $this->use_mysqli )
     1271            return mysql_affected_rows( $dbh );
     1272
     1273        return mysqli_affected_rows( $dbh );
     1274    }
     1275
     1276    function ex_mysql_insert_id( $dbh ) {
     1277        if ( ! $this->use_mysqli )
     1278            return mysql_insert_id( $dbh );
     1279
     1280        return mysqli_insert_id( $dbh );
     1281    }
     1282
     1283    function ex_mysql_num_fields( $result ) {
     1284        if ( ! $this->use_mysqli )
     1285            return @mysql_num_fields( $result );
     1286
     1287        return @mysqli_num_fields( $result );
     1288    }
     1289
     1290    function ex_mysql_fetch_field( $result ) {
     1291        if ( ! $this->use_mysqli )
     1292            return @mysql_fetch_field( $result );
     1293
     1294        return @mysqli_fetch_field( $result );
     1295    }
     1296
     1297    function ex_mysql_fetch_object( $result ) {
     1298        if ( ! $this->use_mysqli )
     1299            return @mysql_fetch_object( $result );
     1300
     1301        if ( ! $this->is_mysql_result( $result ) )
     1302            return false;
     1303
     1304        $object = @mysqli_fetch_object( $result );
     1305
     1306        return ! is_null( $object ) ? $object : false;
     1307    }
     1308
     1309    function ex_mysql_fetch_row( $result ) {
     1310        if ( ! $this->use_mysqli )
     1311            return mysql_fetch_row( $result );
     1312
     1313        if ( ! $this->is_mysql_result( $result ) )
     1314            return false;
     1315
     1316        $row = mysqli_fetch_row( $result );
     1317
     1318        return ! is_null( $row ) ? $row : false;
     1319
     1320    }
     1321
     1322    function ex_mysql_num_rows( $result ) {
     1323        if ( ! $this->use_mysqli )
     1324            return mysql_num_rows( $result );
     1325
     1326        return mysqli_num_rows( $result );
     1327    }
     1328
     1329    function ex_mysql_free_result( $result ) {
     1330        if ( ! $this->use_mysqli )
     1331            return @mysql_free_result( $result );
     1332
     1333        return @mysqli_free_result( $result );
     1334    }
     1335
     1336    function ex_mysql_get_server_info( $dbh ) {
     1337        if ( ! $this->use_mysqli )
     1338            return mysql_get_server_info( $dbh );
     1339
     1340        return mysqli_get_server_info( $dbh );
     1341    }
     1342
     1343    function ex_mysql_connect_timeout( $timeout = null ) {
     1344        if ( is_null( $timeout ) ) {
     1345            if ( ! $this->use_mysqli )
     1346                return ini_get( 'mysql.connect_timeout' );
     1347
     1348            return ini_get( 'default_socket_timeout' );
     1349        }
     1350
     1351        if ( ! $this->use_mysqli )
     1352            return ini_set( 'mysql.connect_timeout', $timeout );
     1353
     1354        return ini_set( 'default_socket_timeout', $timeout );
     1355    }
    10041356    // Helper functions for configuration
    10051357
Note: See TracChangeset for help on using the changeset viewer.