Changeset 106
- Timestamp:
- 08/08/08 19:46:23 (5 months ago)
- Files:
-
- trunk/includes/class.bpdb-multi.php (modified) (5 diffs)
- trunk/includes/class.bpdb.php (modified) (16 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/includes/class.bpdb-multi.php
r78 r106 9 9 10 10 class 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 12 17 var $_force_dbhname = false; 13 18 var $last_table = ''; … … 27 32 } 28 33 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 */ 29 39 function &db_connect( $query = '' ) { 30 40 $false = false; … … 48 58 return $false; 49 59 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]; 52 62 53 63 $success = $this->db_connect_host( $this->db_servers[$dbhname] ); 54 64 55 65 if ( $success && is_resource($this->dbh) ) { 56 $this-> conn[$dbhname] =& $this->dbh;66 $this->dbhs[$dbhname] =& $this->dbh; 57 67 } else { 58 unset($this-> conn[$dbhname]);68 unset($this->dbhs[$dbhname]); 59 69 unset($this->dbh); 60 70 return $false; 61 71 } 62 72 63 return $this-> conn[$dbhname];73 return $this->dbhs[$dbhname]; 64 74 } 65 75 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 */ 66 87 function set_prefix( $prefix, $tables = false ) { 67 88 $old_prefix = parent::set_prefix( $prefix, $tables ); … … 86 107 } 87 108 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) ) 92 126 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 125 129 if ( preg_match('/^\s*SELECT.*?\s+FOUND_ROWS\(\)/is', $q) ) 126 130 return $this->last_table; 127 131 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 128 155 return ''; 129 156 } 130 157 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 */ 131 169 function add_db_server( $ds, $args = null ) { 132 170 $defaults = array( … … 145 183 } 146 184 185 /** 186 * Maps a table to a dataset. 187 * @param string $ds Dataset: the name of the dataset. 188 * @param string $table 189 */ 147 190 function add_db_table( $ds, $table ) { 148 191 $this->db_tables[$table] = 'dbh_' . $ds; trunk/includes/class.bpdb.php
r82 r106 23 23 var $col_info; 24 24 var $queries; 25 26 /** 27 * Whether to use the query log 28 * @var bool 29 */ 30 var $save_queries = false; 25 31 26 32 var $prefix = ''; … … 67 73 $this->suppress_errors( true ); 68 74 break; 69 case 'return' :70 $this->return_errors( true );71 break;72 75 endswitch; 73 76 … … 79 82 } 80 83 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 */ 81 89 function &db_connect( $query = '' ) { 82 90 $false = false; … … 86 94 } 87 95 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 */ 88 107 function db_connect_host( $args ) { 89 108 extract( $args, EXTR_SKIP ); … … 109 128 if ( !empty($collation_query) ) 110 129 $this->query($collation_query, true); 111 112 130 } 113 131 … … 115 133 } 116 134 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 */ 117 145 function set_prefix( $prefix, $tables = false ) { 118 146 if ( !$prefix ) … … 142 170 * Selects a database using the current class's $this->dbh 143 171 * @param string $db name 172 * @param resource $dbh mysql database resource 144 173 */ 145 174 function select( $db, &$dbh ) { … … 170 199 } 171 200 201 /** 202 * Escapes array recursively for insertion into the database, for security 203 * @param array $array 204 */ 172 205 function escape_deep( $array ) { 173 206 return is_array($array) ? array_map(array(&$this, 'escape_deep'), $array) : $this->escape( $array ); … … 189 222 } 190 223 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 */ 194 251 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 201 252 if ( $this->suppress_errors ) 202 253 return false; 203 254 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 217 268 if ( !$this->show_errors ) 218 269 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); 224 274 225 275 // 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 */ 232 284 function show_errors( $show = true ) { 233 285 $errors = $this->show_errors; … … 236 288 } 237 289 290 /** 291 * Turn error output off 292 * @return bool previous setting of show_errors 293 */ 238 294 function hide_errors() { 239 295 return $this->show_errors( false ); 240 296 } 241 297 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 */ 246 303 function suppress_errors( $suppress = true ) { 247 304 $errors = $this->suppress_errors; … … 250 307 } 251 308 252 / / ==================================================================253 //Kill cached query results254 309 /** 310 * Kill cached query results 311 */ 255 312 function flush() { 256 313 $this->last_result = array(); 257 314 $this->col_info = null; 258 315 $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 */ 264 325 function query($query, $use_current = false) { 265 326 if ( ! $this->ready ) … … 450 511 // Return an integer-keyed array of row objects 451 512 return $this->last_result; 452 } elseif ( $output == OBJECT_K ) {513 } elseif ( $output == OBJECT_K || $output == ARRAY_K ) { 453 514 // Return an array of row objects with keys from column 1 454 515 // (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); 460 522 return $new_array; 461 523 } elseif ( $output == ARRAY_A || $output == ARRAY_N ) { … … 550 612 * This function is called when WordPress is generating the table schema to determine wether or not the current database 551 613 * supports or needs the collation statements. 614 * @return bool 552 615 */ 553 616 function supports_collation() { … … 555 618 } 556 619 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 */ 557 626 function has_cap( $db_cap, $dbh_or_table = false ) { 558 627 $version = $this->db_version( $dbh_or_table ); … … 568 637 } 569 638 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 */ 571 644 function db_version( $dbh_or_table = false ) { 572 645 if ( !$dbh_or_table ) … … 594 667 $bt = debug_backtrace(); 595 668 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' ); 597 670 598 671 foreach ( $bt as $trace ) { 599 if ( @$trace['class'] == __CLASS__ ) 672 if ( isset($trace['class']) && $trace['class'] == __CLASS__ ) 673 continue; 674 elseif ( !isset($trace['function']) ) 600 675 continue; 601 676 elseif ( in_array( strtolower(@$trace['function']), $intermediates ) )
