Changeset 106

Show
Ignore:
Timestamp:
08/08/08 19:46:23 (5 months ago)
Author:
mdawaffe
Message:

bring db classes more inline with wp, hyperdb. $conn -> $dbhs, better get_table_from_query(), better docs, get rid of return_errors, add get_error(), better OBJECT_K, ARRAY_K

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/includes/class.bpdb-multi.php

    r78 r106  
    99 
    1010class BPDB_Multi extends BPDB { 
    11         var $conn = array(); 
     11        /** 
     12         * Associative array (dbhname => dbh) for established mysql connections 
     13         * @var array 
     14         */ 
     15        var $dbhs = array(); 
     16 
    1217        var $_force_dbhname = false; 
    1318        var $last_table = ''; 
     
    2732        } 
    2833 
     34        /** 
     35         * Figure out which database server should handle the query, and connect to it. 
     36         * @param string query 
     37         * @return resource mysql database connection 
     38         */ 
    2939        function &db_connect( $query = '' ) { 
    3040                $false = false; 
     
    4858                        return $false; 
    4959 
    50                 if ( isset($this->conn[$dbhname]) && is_resource($this->conn[$dbhname]) ) // We're already connected! 
    51                         return $this->conn[$dbhname]; 
     60                if ( isset($this->dbhs[$dbhname]) && is_resource($this->dbhs[$dbhname]) ) // We're already connected! 
     61                        return $this->dbhs[$dbhname]; 
    5262                 
    5363                $success = $this->db_connect_host( $this->db_servers[$dbhname] ); 
    5464 
    5565                if ( $success && is_resource($this->dbh) ) { 
    56                         $this->conn[$dbhname] =& $this->dbh; 
     66                        $this->dbhs[$dbhname] =& $this->dbh; 
    5767                } else { 
    58                         unset($this->conn[$dbhname]); 
     68                        unset($this->dbhs[$dbhname]); 
    5969                        unset($this->dbh); 
    6070                        return $false; 
    6171                } 
    6272 
    63                 return $this->conn[$dbhname]; 
     73                return $this->dbhs[$dbhname]; 
    6474        } 
    6575 
     76        /** 
     77         * Sets the prefix of the database tables 
     78         * @param string prefix 
     79         * @param false|array tables (optional: false) 
     80         *      table identifiers are array keys 
     81         *      array values 
     82         *              empty: set prefix 
     83         *              string: set to that array value 
     84         *              array: array[0] is DB identifier, array[1] is table name 
     85         * @return string the previous prefix (mostly only meaningful if all $table parameter was false) 
     86         */ 
    6687        function set_prefix( $prefix, $tables = false ) { 
    6788                $old_prefix = parent::set_prefix( $prefix, $tables ); 
     
    86107        } 
    87108 
    88         function get_table_from_query( $q ) { 
    89                 if ( substr( $q, -1 ) == ';' ) 
    90                         $q = substr( $q, 0, -1 ); 
    91                 if ( preg_match('/^\s*SELECT.*?\s+FROM\s+`?(\w+)`?\s*/is', $q, $maybe) ) 
     109        /** 
     110         * Find the first table name referenced in a query 
     111         * @param string query 
     112         * @return string table 
     113         */ 
     114        function get_table_from_query ( $q ) { 
     115                // Remove characters that can legally trail the table name 
     116                rtrim($q, ';/-#'); 
     117 
     118                // Quickly match most common queries 
     119                if ( preg_match('/^\s*(?:' 
     120                                . 'SELECT.*?\s+FROM' 
     121                                . '|INSERT(?:\s+IGNORE)?(?:\s+INTO)?' 
     122                                . '|REPLACE(?:\s+INTO)?' 
     123                                . '|UPDATE(?:\s+IGNORE)?' 
     124                                . '|DELETE(?:\s+IGNORE)?(?:\s+FROM)?' 
     125                                . ')\s+`?(\w+)`?/is', $q, $maybe) ) 
    92126                        return $maybe[1]; 
    93                 if ( preg_match('/^\s*UPDATE IGNORE\s+`?(\w+)`?\s*/is', $q, $maybe) ) 
    94                         return $maybe[1]; 
    95                 if ( preg_match('/^\s*UPDATE\s+`?(\w+)`?\s*/is', $q, $maybe) ) 
    96                         return $maybe[1]; 
    97                 if ( preg_match('/^\s*INSERT INTO\s+`?(\w+)`?\s*/is', $q, $maybe) ) 
    98                         return $maybe[1]; 
    99                 if ( preg_match('/^\s*REPLACE INTO\s+`?(\w+)`?\s*/is', $q, $maybe) ) 
    100                         return $maybe[1]; 
    101                 if ( preg_match('/^\s*INSERT IGNORE INTO\s+`?(\w+)`?\s*/is', $q, $maybe) ) 
    102                         return $maybe[1]; 
    103                 if ( preg_match('/^\s*DELETE\s+FROM\s+`?(\w+)`?\s*/is', $q, $maybe) ) 
    104                         return $maybe[1]; 
    105                 if ( preg_match('/^\s*(?:TRUNCATE|RENAME|OPTIMIZE|LOCK|UNLOCK)\s+TABLE\s+`?(\w+)`?\s*/is', $q, $maybe) ) 
    106                         return $maybe[1]; 
    107                 if ( preg_match('/^SHOW TABLE STATUS (LIKE|FROM) \'?`?(\w+)\'?`?\s*/is', $q, $maybe) ) 
    108                         return $maybe[1]; 
    109                 if ( preg_match('/^SHOW INDEX FROM `?(\w+)`?\s*/is', $q, $maybe) ) 
    110                         return $maybe[1]; 
    111                 if ( preg_match('/^\s*CREATE\s+TABLE\s+IF\s+NOT\s+EXISTS\s+`?(\w+)`?\s*/is', $q, $maybe) ) 
    112                         return $maybe[1]; 
    113                 if ( preg_match('/^\s*SHOW CREATE TABLE `?(\w+?)`?\s*/is', $q, $maybe) ) 
    114                         return $maybe[1]; 
    115                 if ( preg_match('/^\s*CREATE\s+TABLE\s+`?(\w+)`?\s*/is', $q, $maybe) ) 
    116                         return $maybe[1]; 
    117                 if ( preg_match('/^\s*DROP\s+TABLE\s+IF\s+EXISTS\s+`?(\w+)`?\s*/is', $q, $maybe) ) 
    118                         return $maybe[1]; 
    119                 if ( preg_match('/^\s*DROP\s+TABLE\s+`?(\w+)`?\s*/is', $q, $maybe) ) 
    120                         return $maybe[1]; 
    121                 if ( preg_match('/^\s*DESCRIBE\s+`?(\w+)`?\s*/is', $q, $maybe) ) 
    122                         return $maybe[1]; 
    123                 if ( preg_match('/^\s*ALTER\s+TABLE\s+`?(\w+)`?\s*/is', $q, $maybe) ) 
    124                         return $maybe[1]; 
     127 
     128                // Refer to the previous query 
    125129                if ( preg_match('/^\s*SELECT.*?\s+FOUND_ROWS\(\)/is', $q) ) 
    126130                        return $this->last_table; 
    127131 
     132                // Big pattern for the rest of the table-related queries in MySQL 5.0 
     133                if ( preg_match('/^\s*(?:' 
     134                                . '(?:EXPLAIN\s+(?:EXTENDED\s+)?)?SELECT.*?\s+FROM' 
     135                                . '|INSERT(?:\s+LOW_PRIORITY|\s+DELAYED|\s+HIGH_PRIORITY)?(?:\s+IGNORE)?(?:\s+INTO)?' 
     136                                . '|REPLACE(?:\s+LOW_PRIORITY|\s+DELAYED)?(?:\s+INTO)?' 
     137                                . '|UPDATE(?:\s+LOW_PRIORITY)?(?:\s+IGNORE)?' 
     138                                . '|DELETE(?:\s+LOW_PRIORITY|\s+QUICK|\s+IGNORE)*(?:\s+FROM)?' 
     139                                . '|DESCRIBE|DESC|EXPLAIN|HANDLER' 
     140                                . '|(?:LOCK|UNLOCK)\s+TABLE(?:S)?' 
     141                                . '|(?:RENAME|OPTIMIZE|BACKUP|RESTORE|CHECK|CHECKSUM|ANALYZE|OPTIMIZE|REPAIR).*\s+TABLE' 
     142                                . '|TRUNCATE(?:\s+TABLE)?' 
     143                                . '|CREATE(?:\s+TEMPORARY)?\s+TABLE(?:\s+IF\s+NOT\s+EXISTS)?' 
     144                                . '|ALTER(?:\s+IGNORE)?' 
     145                                . '|DROP\s+TABLE(?:\s+IF\s+EXISTS)?' 
     146                                . '|CREATE(?:\s+\w+)?\s+INDEX.*\s+ON' 
     147                                . '|DROP\s+INDEX.*\s+ON' 
     148                                . '|LOAD\s+DATA.*INFILE.*INTO\s+TABLE' 
     149                                . '|(?:GRANT|REVOKE).*ON\s+TABLE' 
     150                                . '|SHOW\s+(?:.*FROM|.*TABLE)' 
     151                                . ')\s+`?(\w+)`?/is', $q, $maybe) ) 
     152                        return $maybe[1]; 
     153 
     154                // All unmatched queries automatically fall to the global master 
    128155                return ''; 
    129156        } 
    130157 
     158        /** 
     159         * Add a database server's information.  Does not automatically connect. 
     160         * @param string $ds Dataset: the name of the dataset. 
     161         * @param array $args 
     162         *      name => string DB name (required) 
     163         *      user => string DB user (optional: false) 
     164         *      password => string DB user password (optional: false) 
     165         *      host => string DB hostname (optional: 'localhost') 
     166         *      charset => string DB default charset.  Used in a SET NAMES query. (optional) 
     167         *      collate => string DB default collation.  If charset supplied, optionally added to the SET NAMES query (optional) 
     168         */ 
    131169        function add_db_server( $ds, $args = null ) { 
    132170                $defaults = array( 
     
    145183        } 
    146184 
     185        /** 
     186         * Maps a table to a dataset. 
     187         * @param string $ds Dataset: the name of the dataset. 
     188         * @param string $table 
     189         */ 
    147190        function add_db_table( $ds, $table ) { 
    148191                $this->db_tables[$table] = 'dbh_' . $ds; 
  • trunk/includes/class.bpdb.php

    r82 r106  
    2323        var $col_info; 
    2424        var $queries; 
     25 
     26        /**                      
     27         * Whether to use the query log 
     28         * @var bool 
     29         */ 
     30        var $save_queries = false; 
    2531 
    2632        var $prefix = ''; 
     
    6773                        $this->suppress_errors( true ); 
    6874                        break; 
    69                 case 'return' : 
    70                         $this->return_errors( true ); 
    71                         break; 
    7275                endswitch; 
    7376 
     
    7982        } 
    8083 
     84        /** 
     85         * Figure out which database server should handle the query, and connect to it. 
     86         * @param string query 
     87         * @return resource mysql database connection 
     88         */ 
    8189        function &db_connect( $query = '' ) { 
    8290                $false = false; 
     
    8694        } 
    8795 
     96        /** 
     97         * Connect to and selects a specific database server  
     98         * @param array args 
     99         *      name => string DB name (required) 
     100         *      user => string DB user (optional: false) 
     101         *      password => string DB user password (optional: false) 
     102         *      host => string DB hostname (optional: 'localhost') 
     103         *      charset => string DB default charset.  Used in a SET NAMES query. (optional) 
     104         *      collate => string DB default collation.  If charset supplied, optionally added to the SET NAMES query (optional) 
     105         * @return void|bool void if cannot connect, false if cannot select, true if success 
     106         */ 
    88107        function db_connect_host( $args ) { 
    89108                extract( $args, EXTR_SKIP ); 
     
    109128                        if ( !empty($collation_query) ) 
    110129                                $this->query($collation_query, true); 
    111                          
    112130                } 
    113131 
     
    115133        } 
    116134 
     135        /** 
     136         * Sets the prefix of the database tables 
     137         * @param string prefix 
     138         * @param false|array tables (optional: false) 
     139         *      table identifiers are array keys 
     140         *      array values 
     141         *              empty: set prefix 
     142         *              string: set to that array value 
     143         * @return string the previous prefix (mostly only meaningful if all $table parameter was false) 
     144         */ 
    117145        function set_prefix( $prefix, $tables = false ) { 
    118146                if ( !$prefix ) 
     
    142170         * Selects a database using the current class's $this->dbh 
    143171         * @param string $db name 
     172         * @param resource $dbh mysql database resource 
    144173         */ 
    145174        function select( $db, &$dbh ) { 
     
    170199        } 
    171200 
     201        /** 
     202         * Escapes array recursively for insertion into the database, for security 
     203         * @param array $array 
     204         */ 
    172205        function escape_deep( $array ) { 
    173206                return is_array($array) ? array_map(array(&$this, 'escape_deep'), $array) : $this->escape( $array ); 
     
    189222        } 
    190223 
    191         // ================================================================== 
    192         //      Print SQL/DB error. 
    193  
     224        /** 
     225         * Get SQL/DB error 
     226         * @param string $str Error string 
     227         */ 
     228        function get_error( $str = '' ) { 
     229                if ( empty($str) ) { 
     230                        if ( $this->last_error ) 
     231                                $str = $this->last_error; 
     232                        else 
     233                                return false; 
     234                } 
     235 
     236                $error_str = sprintf( BPDB__ERROR_STRING, $str, $this->last_query, $caller ); 
     237 
     238                if ( $caller = $this->get_caller() ) 
     239                        $error_str .= " made by $caller"; 
     240 
     241                if ( class_exists( 'WP_Error' ) ) 
     242                        return new WP_Error( 'db_query', $error_str, array( 'query' => $this->last_query, 'error' => $str, 'caller' => $caller ) ); 
     243                else 
     244                        return array( 'query' => $this->last_query, 'error' => $str, 'caller' => $caller, 'error_str' => $error_str ); 
     245        } 
     246 
     247        /** 
     248         * Print SQL/DB error 
     249         * @param string $str Error string 
     250         */ 
    194251        function print_error($str = '') { 
    195                 global $EZSQL_ERROR; 
    196  
    197                 if (!$str) $str = mysql_error($this->dbh); 
    198                 $EZSQL_ERROR[] = 
    199                 array ('query' => $this->last_query, 'error_str' => $str); 
    200  
    201252                if ( $this->suppress_errors ) 
    202253                        return false; 
    203254 
    204                 $caller = $this->get_caller(); 
    205                 $error_str = sprintf( BPDB__ERROR_STRING, $str, $this->last_query, $caller ); 
    206  
    207                 $log_error = function_exists('error_log'); 
    208  
    209                 $log_file = @ini_get('error_log')
    210                 if ( !empty($log_file) && ('syslog' != $log_file) && !is_writable($log_file) ) 
    211                         $log_error = false; 
    212  
    213                 if ( $log_error
    214                         @error_log($error_str, 0); 
    215  
    216                 // Is error output turned on or not.. 
     255                $error = $this->get_error( $str ); 
     256                if ( is_object( $error ) && is_a( $error, 'WP_Error' ) ) { 
     257                        $err = $error->get_error_data(); 
     258                       $err['error_str'] = $error->get_error_messag(); 
     259                } else { 
     260                       $err =& $error
     261                } 
     262 
     263                $log_file = ini_get('error_log'); 
     264                if ( !empty($log_file) && ('syslog' != $log_file) && !is_writable($log_file) && function_exists( 'error_log' )
     265                        error_log($err['error_str'], 0); 
     266 
     267                // Is error output turned on or not 
    217268                if ( !$this->show_errors ) 
    218269                        return false; 
    219                 elseif ( 2 === $this->show_errors ) 
    220                         return new WP_Error( 'db_query', $error_str, array( 'query' => $this->last_query, 'error' => $str, 'caller' => $caller ) ); 
    221  
    222                 $str = htmlspecialchars($str, ENT_QUOTES); 
    223                 $query = htmlspecialchars($this->last_query, ENT_QUOTES); 
     270 
     271                $str = htmlspecialchars($err['str'], ENT_QUOTES); 
     272                $query = htmlspecialchars($err['query'], ENT_QUOTES); 
     273                $caller = htmlspecialchars($err['caller'], ENT_QUOTES); 
    224274 
    225275                // If there is an error then take note of it 
    226                 printf( BPDB__ERROR_HTML, $str, $query, htmlspecialchars($caller) ); 
    227         } 
    228  
    229         // ================================================================== 
    230         //      Turn error handling on or off.. 
    231  
     276                printf( BPDB__ERROR_HTML, $str, $query, $caller ); 
     277        } 
     278 
     279        /** 
     280         * Turn error output on or off 
     281         * @param bool $show 
     282         * @return bool previous setting 
     283         */ 
    232284        function show_errors( $show = true ) { 
    233285                $errors = $this->show_errors; 
     
    236288        } 
    237289 
     290        /** 
     291         * Turn error output off 
     292         * @return bool previous setting of show_errors 
     293         */ 
    238294        function hide_errors() { 
    239295                return $this->show_errors( false ); 
    240296        } 
    241297 
    242         function return_errors() { 
    243                 return $this->show_errors( 2 ); 
    244         } 
    245  
     298        /** 
     299         * Turn error logging on or off 
     300         * @param bool $suppress 
     301         * @return bool previous setting 
     302         */ 
    246303        function suppress_errors( $suppress = true ) { 
    247304                $errors = $this->suppress_errors; 
     
    250307        } 
    251308 
    252         // ================================================================== 
    253         //     Kill cached query results 
    254  
     309        /** 
     310        * Kill cached query results 
     311         */ 
    255312        function flush() { 
    256313                $this->last_result = array(); 
    257314                $this->col_info = null; 
    258315                $this->last_query = null; 
    259         } 
    260  
    261         // ================================================================== 
    262         //      Basic Query     - see docs for more detail 
    263  
     316                $this->last_error = ''; 
     317                $this->num_rows = 0; 
     318        } 
     319 
     320        /** 
     321         * Basic query. See docs for more details. 
     322         * @param string $query 
     323         * @return int number of rows 
     324         */ 
    264325        function query($query, $use_current = false) { 
    265326                if ( ! $this->ready ) 
     
    450511                        // Return an integer-keyed array of row objects 
    451512                        return $this->last_result; 
    452                 } elseif ( $output == OBJECT_K ) { 
     513                } elseif ( $output == OBJECT_K || $output == ARRAY_K ) { 
    453514                        // Return an array of row objects with keys from column 1 
    454515                        // (Duplicates are discarded) 
    455                         foreach ( $this->last_result as $row ) { 
    456                                 $key = array_shift( get_object_vars( $row ) ); 
    457                                 if ( !isset( $new_array[ $key ] ) ) 
    458                                         $new_array[ $key ] = $row; 
    459                         } 
     516                        $key = $this->col_info[0]->name; 
     517                        foreach ( $this->last_result as $row ) 
     518                                if ( !isset( $new_array[ $row->$key ] ) ) 
     519                                        $new_array[ $row->$key ] = $row; 
     520                        if ( $output == ARRAY_K ) 
     521                                return array_map('get_object_vars', $new_array); 
    460522                        return $new_array; 
    461523                } elseif ( $output == ARRAY_A || $output == ARRAY_N ) { 
     
    550612         * This function is called when WordPress is generating the table schema to determine wether or not the current database 
    551613         * supports or needs the collation statements. 
     614         * @return bool 
    552615         */ 
    553616        function supports_collation() { 
     
    555618        } 
    556619 
     620        /** 
     621         * Generic function to determine if a database supports a particular feature 
     622         * @param string $db_cap the feature 
     623         * @param false|string|resource $dbh_or_table the databaese (the current database, the database housing the specified table, or the database of the mysql resource) 
     624         * @return bool 
     625         */ 
    557626        function has_cap( $db_cap, $dbh_or_table = false ) { 
    558627                $version = $this->db_version( $dbh_or_table ); 
     
    568637        } 
    569638 
    570         // table name or mysql resource  
     639        /** 
     640         * The database version number 
     641         * @param false|string|resource $dbh_or_table the databaese (the current database, the database housing the specified table, or the database of the mysql resource) 
     642         * @return false|string false on failure, version number on success 
     643         */ 
    571644        function db_version( $dbh_or_table = false ) { 
    572645                if ( !$dbh_or_table ) 
     
    594667                $bt = debug_backtrace(); 
    595668 
    596                 $intermediates = array( 'call_user_func_array', 'call_user_func', 'apply_filters', 'do_action' ); 
     669                $intermediates = array( 'call_user_func_array', 'call_user_func', 'apply_filters', 'do_action', 'do_action_ref_array' ); 
    597670 
    598671                foreach ( $bt as $trace ) { 
    599                         if ( @$trace['class'] == __CLASS__ ) 
     672                        if ( isset($trace['class']) && $trace['class'] == __CLASS__ ) 
     673                                continue; 
     674                        elseif ( !isset($trace['function']) ) 
    600675                                continue; 
    601676                        elseif ( in_array( strtolower(@$trace['function']), $intermediates ) )