Make WordPress Core

Ticket #15682: wp-db.php

File wp-db.php, 42.9 KB (added by zippykid, 13 years ago)

my attempt at an elegant fix for this.. try it out, if it's acceptable I'll send a patch.

Line 
1<?php
2/**
3 * WordPress DB Class
4 *
5 * Original code from {@link http://php.justinvincent.com Justin Vincent (justin@visunet.ie)}
6 *
7 * @package WordPress
8 * @subpackage Database
9 * @since 0.71
10 */
11
12/**
13 * @since 0.71
14 */
15define( 'EZSQL_VERSION', 'WP1.25' );
16
17/**
18 * @since 0.71
19 */
20define( 'OBJECT', 'OBJECT', true );
21
22/**
23 * @since 2.5.0
24 */
25define( 'OBJECT_K', 'OBJECT_K' );
26
27/**
28 * @since 0.71
29 */
30define( 'ARRAY_A', 'ARRAY_A' );
31
32/**
33 * @since 0.71
34 */
35define( 'ARRAY_N', 'ARRAY_N' );
36
37/**
38 * WordPress Database Access Abstraction Object
39 *
40 * It is possible to replace this class with your own
41 * by setting the $wpdb global variable in wp-content/db.php
42 * file with your class. You can name it wpdb also, since
43 * this file will not be included, if the other file is
44 * available.
45 *
46 * @link http://codex.wordpress.org/Function_Reference/wpdb_Class
47 *
48 * @package WordPress
49 * @subpackage Database
50 * @since 0.71
51 */
52class wpdb {
53
54        /**
55         * Whether to show SQL/DB errors
56         *
57         * @since 0.71
58         * @access private
59         * @var bool
60         */
61        var $show_errors = false;
62
63        /**
64         * Whether to suppress errors during the DB bootstrapping.
65         *
66         * @access private
67         * @since 2.5
68         * @var bool
69         */
70        var $suppress_errors = false;
71
72        /**
73         * The last error during query.
74         *
75         * @see get_last_error()
76         * @since 2.5
77         * @access private
78         * @var string
79         */
80        var $last_error = '';
81
82        /**
83         * Amount of queries made
84         *
85         * @since 1.2.0
86         * @access private
87         * @var int
88         */
89        var $num_queries = 0;
90
91        /**
92         * Count of rows returned by previous query
93         *
94         * @since 1.2
95         * @access private
96         * @var int
97         */
98        var $num_rows = 0;
99
100        /**
101         * Count of affected rows by previous query
102         *
103         * @since 0.71
104         * @access private
105         * @var int
106         */
107        var $rows_affected = 0;
108
109        /**
110         * The ID generated for an AUTO_INCREMENT column by the previous query (usually INSERT).
111         *
112         * @since 0.71
113         * @access public
114         * @var int
115         */
116        var $insert_id = 0;
117
118        /**
119         * Saved result of the last query made
120         *
121         * @since 1.2.0
122         * @access private
123         * @var array
124         */
125        var $last_query;
126
127        /**
128         * Results of the last query made
129         *
130         * @since 1.0.0
131         * @access private
132         * @var array|null
133         */
134        var $last_result;
135
136        /**
137         * Saved info on the table column
138         *
139         * @since 1.2.0
140         * @access private
141         * @var array
142         */
143        var $col_info;
144
145        /**
146         * Saved queries that were executed
147         *
148         * @since 1.5.0
149         * @access private
150         * @var array
151         */
152        var $queries;
153
154        /**
155         * WordPress table prefix
156         *
157         * You can set this to have multiple WordPress installations
158         * in a single database. The second reason is for possible
159         * security precautions.
160         *
161         * @since 0.71
162         * @access private
163         * @var string
164         */
165        var $prefix = '';
166
167        /**
168         * Whether the database queries are ready to start executing.
169         *
170         * @since 2.5.0
171         * @access private
172         * @var bool
173         */
174        var $ready = false;
175
176        /**
177         * {@internal Missing Description}}
178         *
179         * @since 3.0.0
180         * @access public
181         * @var int
182         */
183        var $blogid = 0;
184
185        /**
186         * {@internal Missing Description}}
187         *
188         * @since 3.0.0
189         * @access public
190         * @var int
191         */
192        var $siteid = 0;
193
194        /**
195         * List of WordPress per-blog tables
196         *
197         * @since 2.5.0
198         * @access private
199         * @see wpdb::tables()
200         * @var array
201         */
202        var $tables = array( 'posts', 'comments', 'links', 'options', 'postmeta',
203                'terms', 'term_taxonomy', 'term_relationships', 'commentmeta' );
204
205        /**
206         * List of deprecated WordPress tables
207         *
208         * categories, post2cat, and link2cat were deprecated in 2.3.0, db version 5539
209         *
210         * @since 2.9.0
211         * @access private
212         * @see wpdb::tables()
213         * @var array
214         */
215        var $old_tables = array( 'categories', 'post2cat', 'link2cat' );
216
217        /**
218         * List of WordPress global tables
219         *
220         * @since 3.0.0
221         * @access private
222         * @see wpdb::tables()
223         * @var array
224         */
225        var $global_tables = array( 'users', 'usermeta' );
226
227        /**
228         * List of Multisite global tables
229         *
230         * @since 3.0.0
231         * @access private
232         * @see wpdb::tables()
233         * @var array
234         */
235        var $ms_global_tables = array( 'blogs', 'signups', 'site', 'sitemeta',
236                'sitecategories', 'registration_log', 'blog_versions' );
237
238        /**
239         * WordPress Comments table
240         *
241         * @since 1.5.0
242         * @access public
243         * @var string
244         */
245        var $comments;
246
247        /**
248         * WordPress Comment Metadata table
249         *
250         * @since 2.9.0
251         * @access public
252         * @var string
253         */
254        var $commentmeta;
255
256        /**
257         * WordPress Links table
258         *
259         * @since 1.5.0
260         * @access public
261         * @var string
262         */
263        var $links;
264
265        /**
266         * WordPress Options table
267         *
268         * @since 1.5.0
269         * @access public
270         * @var string
271         */
272        var $options;
273
274        /**
275         * WordPress Post Metadata table
276         *
277         * @since 1.5.0
278         * @access public
279         * @var string
280         */
281        var $postmeta;
282
283        /**
284         * WordPress Posts table
285         *
286         * @since 1.5.0
287         * @access public
288         * @var string
289         */
290        var $posts;
291
292        /**
293         * WordPress Terms table
294         *
295         * @since 2.3.0
296         * @access public
297         * @var string
298         */
299        var $terms;
300
301        /**
302         * WordPress Term Relationships table
303         *
304         * @since 2.3.0
305         * @access public
306         * @var string
307         */
308        var $term_relationships;
309
310        /**
311         * WordPress Term Taxonomy table
312         *
313         * @since 2.3.0
314         * @access public
315         * @var string
316         */
317        var $term_taxonomy;
318
319        /*
320         * Global and Multisite tables
321         */
322
323        /**
324         * WordPress User Metadata table
325         *
326         * @since 2.3.0
327         * @access public
328         * @var string
329         */
330        var $usermeta;
331
332        /**
333         * WordPress Users table
334         *
335         * @since 1.5.0
336         * @access public
337         * @var string
338         */
339        var $users;
340
341        /**
342         * Multisite Blogs table
343         *
344         * @since 3.0.0
345         * @access public
346         * @var string
347         */
348        var $blogs;
349
350        /**
351         * Multisite Blog Versions table
352         *
353         * @since 3.0.0
354         * @access public
355         * @var string
356         */
357        var $blog_versions;
358
359        /**
360         * Multisite Registration Log table
361         *
362         * @since 3.0.0
363         * @access public
364         * @var string
365         */
366        var $registration_log;
367
368        /**
369         * Multisite Signups table
370         *
371         * @since 3.0.0
372         * @access public
373         * @var string
374         */
375        var $signups;
376
377        /**
378         * Multisite Sites table
379         *
380         * @since 3.0.0
381         * @access public
382         * @var string
383         */
384        var $site;
385
386        /**
387         * Multisite Sitewide Terms table
388         *
389         * @since 3.0.0
390         * @access public
391         * @var string
392         */
393        var $sitecategories;
394
395        /**
396         * Multisite Site Metadata table
397         *
398         * @since 3.0.0
399         * @access public
400         * @var string
401         */
402        var $sitemeta;
403
404        /**
405         * Format specifiers for DB columns. Columns not listed here default to %s. Initialized during WP load.
406         *
407         * Keys are column names, values are format types: 'ID' => '%d'
408         *
409         * @since 2.8.0
410         * @see wpdb:prepare()
411         * @see wpdb:insert()
412         * @see wpdb:update()
413         * @see wp_set_wpdb_vars()
414         * @access public
415         * @var array
416         */
417        var $field_types = array();
418
419        /**
420         * Database table columns charset
421         *
422         * @since 2.2.0
423         * @access public
424         * @var string
425         */
426        var $charset;
427
428        /**
429         * Database table columns collate
430         *
431         * @since 2.2.0
432         * @access public
433         * @var string
434         */
435        var $collate;
436
437        /**
438         * Whether to use mysql_real_escape_string
439         *
440         * @since 2.8.0
441         * @access public
442         * @var bool
443         */
444        var $real_escape = false;
445
446        /**
447         * Database Username
448         *
449         * @since 2.9.0
450         * @access private
451         * @var string
452         */
453        var $dbuser;
454
455        /**
456         * A textual description of the last query/get_row/get_var call
457         *
458         * @since unknown
459         * @access public
460         * @var string
461         */
462        var $func_call;
463
464        /**
465         * Connects to the database server and selects a database
466         *
467         * PHP4 compatibility layer for calling the PHP5 constructor.
468         *
469         * @uses wpdb::__construct() Passes parameters and returns result
470         * @since 0.71
471         *
472         * @param string $dbuser MySQL database user
473         * @param string $dbpassword MySQL database password
474         * @param string $dbname MySQL database name
475         * @param string $dbhost MySQL database host
476         */
477        function wpdb( $dbuser, $dbpassword, $dbname, $dbhost ) {
478                return $this->__construct( $dbuser, $dbpassword, $dbname, $dbhost );
479        }
480
481        /**
482         * Connects to the database server and selects a database
483         *
484         * PHP5 style constructor for compatibility with PHP5. Does
485         * the actual setting up of the class properties and connection
486         * to the database.
487         *
488         * @link http://core.trac.wordpress.org/ticket/3354
489         * @since 2.0.8
490         *
491         * @param string $dbuser MySQL database user
492         * @param string $dbpassword MySQL database password
493         * @param string $dbname MySQL database name
494         * @param string $dbhost MySQL database host
495         */
496        function __construct( $dbuser, $dbpassword, $dbname, $dbhost ) {
497                register_shutdown_function( array( &$this, '__destruct' ) );
498       
499                define('WP_DEBUG', true); 
500               
501                if ( WP_DEBUG )
502                        $this->show_errors();
503
504                $this->init_charset();
505
506                $this->dbuser = $dbuser;
507                $this->dbpassword = $dbpassword;
508                $this->dbname = $dbname;
509                $this->dbhost = $dbhost;
510
511                $this->db_connect();
512        }
513
514        /**
515         * PHP5 style destructor and will run when database object is destroyed.
516         *
517         * @see wpdb::__construct()
518         * @since 2.0.8
519         * @return bool true
520         */
521        function __destruct() {
522                return true;
523        }
524
525        /**
526         * Set $this->charset and $this->collate
527         */
528        function init_charset() {
529                if ( function_exists('is_multisite') && is_multisite() ) {
530                        $this->charset = 'utf8';
531                        if ( defined( 'DB_COLLATE' ) && DB_COLLATE )
532                                $this->collate = DB_COLLATE;
533                        else
534                                $this->collate = 'utf8_general_ci';
535                } elseif ( defined( 'DB_COLLATE' ) ) {
536                        $this->collate = DB_COLLATE;
537                }
538
539                if ( defined( 'DB_CHARSET' ) )
540                        $this->charset = DB_CHARSET;
541        }
542
543        /**
544         * Sets the connection's character set.
545         *
546         * @param resource $dbh     The resource given by mysql_connect
547         * @param string   $charset The character set (optional)
548         * @param string   $collate The collation (optional)
549         */
550        function set_charset($dbh, $charset = null, $collate = null) {
551                if ( !isset($charset) )
552                        $charset = $this->charset;
553                if ( !isset($collate) )
554                        $collate = $this->collate;
555                if ( $this->has_cap( 'collation', $dbh ) && !empty( $charset ) ) {
556                        if ( function_exists( 'mysql_set_charset' ) && $this->has_cap( 'set_charset', $dbh ) ) {
557                                mysql_set_charset( $charset, $dbh );
558                                $this->real_escape = true;
559                        } else {
560                                $query = $this->prepare( 'SET NAMES %s', $charset );
561                                if ( ! empty( $collate ) )
562                                        $query .= $this->prepare( ' COLLATE %s', $collate );
563                                mysql_query( $query, $dbh );
564                        }
565                }
566        }
567
568        /**
569         * Sets the table prefix for the WordPress tables.
570         *
571         * @since 2.5.0
572         *
573         * @param string $prefix Alphanumeric name for the new prefix.
574         * @return string|WP_Error Old prefix or WP_Error on error
575         */
576        function set_prefix( $prefix, $set_table_names = true ) {
577
578                if ( preg_match( '|[^a-z0-9_]|i', $prefix ) )
579                        return new WP_Error('invalid_db_prefix', /*WP_I18N_DB_BAD_PREFIX*/'Invalid database prefix'/*/WP_I18N_DB_BAD_PREFIX*/);
580
581                $old_prefix = is_multisite() ? '' : $prefix;
582
583                if ( isset( $this->base_prefix ) )
584                        $old_prefix = $this->base_prefix;
585
586                $this->base_prefix = $prefix;
587
588                if ( $set_table_names ) {
589                        foreach ( $this->tables( 'global' ) as $table => $prefixed_table )
590                                $this->$table = $prefixed_table;
591
592                        if ( is_multisite() && empty( $this->blogid ) )
593                                return $old_prefix;
594
595                        $this->prefix = $this->get_blog_prefix();
596
597                        foreach ( $this->tables( 'blog' ) as $table => $prefixed_table )
598                                $this->$table = $prefixed_table;
599
600                        foreach ( $this->tables( 'old' ) as $table => $prefixed_table )
601                                $this->$table = $prefixed_table;
602                }
603                return $old_prefix;
604        }
605
606        /**
607         * Sets blog id.
608         *
609         * @since 3.0.0
610         * @access public
611         * @param int $blog_id
612         * @param int $site_id Optional.
613         * @return string previous blog id
614         */
615        function set_blog_id( $blog_id, $site_id = 0 ) {
616                if ( ! empty( $site_id ) )
617                        $this->siteid = $site_id;
618
619                $old_blog_id  = $this->blogid;
620                $this->blogid = $blog_id;
621
622                $this->prefix = $this->get_blog_prefix();
623
624                foreach ( $this->tables( 'blog' ) as $table => $prefixed_table )
625                        $this->$table = $prefixed_table;
626
627                foreach ( $this->tables( 'old' ) as $table => $prefixed_table )
628                        $this->$table = $prefixed_table;
629
630                return $old_blog_id;
631        }
632
633        /**
634         * Gets blog prefix.
635         *
636         * @uses is_multisite()
637         * @since 3.0.0
638         * @param int $blog_id Optional.
639         * @return string Blog prefix.
640         */
641        function get_blog_prefix( $blog_id = null ) {
642                if ( is_multisite() ) {
643                        if ( null === $blog_id )
644                                $blog_id = $this->blogid;
645                        if ( defined( 'MULTISITE' ) && ( 0 == $blog_id || 1 == $blog_id ) )
646                                return $this->base_prefix;
647                        else
648                                return $this->base_prefix . $blog_id . '_';
649                } else {
650                        return $this->base_prefix;
651                }
652        }
653
654        /**
655         * Returns an array of WordPress tables.
656         *
657         * Also allows for the CUSTOM_USER_TABLE and CUSTOM_USER_META_TABLE to
658         * override the WordPress users and usersmeta tables that would otherwise
659         * be determined by the prefix.
660         *
661         * The scope argument can take one of the following:
662         *
663         * 'all' - returns 'all' and 'global' tables. No old tables are returned.
664         * 'blog' - returns the blog-level tables for the queried blog.
665         * 'global' - returns the global tables for the installation, returning multisite tables only if running multisite.
666         * 'ms_global' - returns the multisite global tables, regardless if current installation is multisite.
667         * 'old' - returns tables which are deprecated.
668         *
669         * @since 3.0.0
670         * @uses wpdb::$tables
671         * @uses wpdb::$old_tables
672         * @uses wpdb::$global_tables
673         * @uses wpdb::$ms_global_tables
674         * @uses is_multisite()
675         *
676         * @param string $scope Optional. Can be all, global, ms_global, blog, or old tables. Defaults to all.
677         * @param bool $prefix Optional. Whether to include table prefixes. Default true. If blog
678         *      prefix is requested, then the custom users and usermeta tables will be mapped.
679         * @param int $blog_id Optional. The blog_id to prefix. Defaults to wpdb::$blogid. Used only when prefix is requested.
680         * @return array Table names. When a prefix is requested, the key is the unprefixed table name.
681         */
682        function tables( $scope = 'all', $prefix = true, $blog_id = 0 ) {
683                switch ( $scope ) {
684                        case 'all' :
685                                $tables = array_merge( $this->global_tables, $this->tables );
686                                if ( is_multisite() )
687                                        $tables = array_merge( $tables, $this->ms_global_tables );
688                                break;
689                        case 'blog' :
690                                $tables = $this->tables;
691                                break;
692                        case 'global' :
693                                $tables = $this->global_tables;
694                                if ( is_multisite() )
695                                        $tables = array_merge( $tables, $this->ms_global_tables );
696                                break;
697                        case 'ms_global' :
698                                $tables = $this->ms_global_tables;
699                                break;
700                        case 'old' :
701                                $tables = $this->old_tables;
702                                break;
703                        default :
704                                return array();
705                                break;
706                }
707
708                if ( $prefix ) {
709                        if ( ! $blog_id )
710                                $blog_id = $this->blogid;
711                        $blog_prefix = $this->get_blog_prefix( $blog_id );
712                        $base_prefix = $this->base_prefix;
713                        $global_tables = array_merge( $this->global_tables, $this->ms_global_tables );
714                        foreach ( $tables as $k => $table ) {
715                                if ( in_array( $table, $global_tables ) )
716                                        $tables[ $table ] = $base_prefix . $table;
717                                else
718                                        $tables[ $table ] = $blog_prefix . $table;
719                                unset( $tables[ $k ] );
720                        }
721
722                        if ( isset( $tables['users'] ) && defined( 'CUSTOM_USER_TABLE' ) )
723                                $tables['users'] = CUSTOM_USER_TABLE;
724
725                        if ( isset( $tables['usermeta'] ) && defined( 'CUSTOM_USER_META_TABLE' ) )
726                                $tables['usermeta'] = CUSTOM_USER_META_TABLE;
727                }
728
729                return $tables;
730        }
731
732        /**
733         * Selects a database using the current database connection.
734         *
735         * The database name will be changed based on the current database
736         * connection. On failure, the execution will bail and display an DB error.
737         *
738         * @since 0.71
739         *
740         * @param string $db MySQL database name
741         * @param resource $dbh Optional link identifier.
742         * @return null Always null.
743         */
744        function select( $db, $dbh = null) {
745                if ( is_null($dbh) )
746                        $dbh = $this->dbh;
747
748                if ( !@mysql_select_db( $db, $dbh ) ) {
749                        $this->ready = false;
750                        $this->bail( sprintf( /*WP_I18N_DB_SELECT_DB*/'<h1>Can&#8217;t select database</h1>
751<p>We were able to connect to the database server (which means your username and password is okay) but not able to select the <code>%1$s</code> database.</p>
752<ul>
753<li>Are you sure it exists?</li>
754<li>Does the user <code>%2$s</code> have permission to use the <code>%1$s</code> database?</li>
755<li>On some systems the name of your database is prefixed with your username, so it would be like <code>username_%1$s</code>. Could that be the problem?</li>
756</ul>
757<p>If you don\'t know how to set up a database you should <strong>contact your host</strong>. If all else fails you may find help at the <a href="http://wordpress.org/support/">WordPress Support Forums</a>.</p>'/*/WP_I18N_DB_SELECT_DB*/, $db, $this->dbuser ), 'db_select_fail' );
758                        return;
759                }
760        }
761
762        /**
763         * Weak escape, using addslashes()
764         *
765         * @see addslashes()
766         * @since 2.8.0
767         * @access private
768         *
769         * @param string $string
770         * @return string
771         */
772        function _weak_escape( $string ) {
773                return addslashes( $string );
774        }
775
776        /**
777         * Real escape, using mysql_real_escape_string() or addslashes()
778         *
779         * @see mysql_real_escape_string()
780         * @see addslashes()
781         * @since 2.8
782         * @access private
783         *
784         * @param  string $string to escape
785         * @return string escaped
786         */
787        function _real_escape( $string ) {
788                if ( $this->dbh && $this->real_escape )
789                        return mysql_real_escape_string( $string, $this->dbh );
790                else
791                        return addslashes( $string );
792        }
793
794        /**
795         * Escape data. Works on arrays.
796         *
797         * @uses wpdb::_escape()
798         * @uses wpdb::_real_escape()
799         * @since  2.8
800         * @access private
801         *
802         * @param  string|array $data
803         * @return string|array escaped
804         */
805        function _escape( $data ) {
806                if ( is_array( $data ) ) {
807                        foreach ( (array) $data as $k => $v ) {
808                                if ( is_array($v) )
809                                        $data[$k] = $this->_escape( $v );
810                                else
811                                        $data[$k] = $this->_real_escape( $v );
812                        }
813                } else {
814                        $data = $this->_real_escape( $data );
815                }
816
817                return $data;
818        }
819
820        /**
821         * Escapes content for insertion into the database using addslashes(), for security.
822         *
823         * Works on arrays.
824         *
825         * @since 0.71
826         * @param string|array $data to escape
827         * @return string|array escaped as query safe string
828         */
829        function escape( $data ) {
830                if ( is_array( $data ) ) {
831                        foreach ( (array) $data as $k => $v ) {
832                                if ( is_array( $v ) )
833                                        $data[$k] = $this->escape( $v );
834                                else
835                                        $data[$k] = $this->_weak_escape( $v );
836                        }
837                } else {
838                        $data = $this->_weak_escape( $data );
839                }
840
841                return $data;
842        }
843
844        /**
845         * Escapes content by reference for insertion into the database, for security
846         *
847         * @uses wpdb::_real_escape()
848         * @since 2.3.0
849         * @param string $string to escape
850         * @return void
851         */
852        function escape_by_ref( &$string ) {
853                $string = $this->_real_escape( $string );
854        }
855
856        /**
857         * Prepares a SQL query for safe execution. Uses sprintf()-like syntax.
858         *
859         * The following directives can be used in the query format string:
860         *   %d (decimal number)
861         *   %s (string)
862         *   %% (literal percentage sign - no argument needed)
863         *
864         * Both %d and %s are to be left unquoted in the query string and they need an argument passed for them.
865         * Literals (%) as parts of the query must be properly written as %%.
866         *
867         * This function only supports a small subset of the sprintf syntax; it only supports %d (decimal number), %s (string).
868         * Does not support sign, padding, alignment, width or precision specifiers.
869         * Does not support argument numbering/swapping.
870         *
871         * May be called like {@link http://php.net/sprintf sprintf()} or like {@link http://php.net/vsprintf vsprintf()}.
872         *
873         * Both %d and %s should be left unquoted in the query string.
874         *
875         * <code>
876         * wpdb::prepare( "SELECT * FROM `table` WHERE `column` = %s AND `field` = %d", 'foo', 1337 )
877         * wpdb::prepare( "SELECT DATE_FORMAT(`field`, '%%c') FROM `table` WHERE `column` = %s", 'foo' );
878         * </code>
879         *
880         * @link http://php.net/sprintf Description of syntax.
881         * @since 2.3.0
882         *
883         * @param string $query Query statement with sprintf()-like placeholders
884         * @param array|mixed $args The array of variables to substitute into the query's placeholders if being called like
885         *      {@link http://php.net/vsprintf vsprintf()}, or the first variable to substitute into the query's placeholders if
886         *      being called like {@link http://php.net/sprintf sprintf()}.
887         * @param mixed $args,... further variables to substitute into the query's placeholders if being called like
888         *      {@link http://php.net/sprintf sprintf()}.
889         * @return null|false|string Sanitized query string, null if there is no query, false if there is an error and string
890         *      if there was something to prepare
891         */
892        function prepare( $query = null ) { // ( $query, *$args )
893                if ( is_null( $query ) )
894                        return;
895
896                $args = func_get_args();
897                array_shift( $args );
898                // If args were passed as an array (as in vsprintf), move them up
899                if ( isset( $args[0] ) && is_array($args[0]) )
900                        $args = $args[0];
901                $query = str_replace( "'%s'", '%s', $query ); // in case someone mistakenly already singlequoted it
902                $query = str_replace( '"%s"', '%s', $query ); // doublequote unquoting
903                $query = preg_replace( '|(?<!%)%s|', "'%s'", $query ); // quote the strings, avoiding escaped strings like %%s
904                array_walk( $args, array( &$this, 'escape_by_ref' ) );
905                return @vsprintf( $query, $args );
906        }
907
908        /**
909         * Print SQL/DB error.
910         *
911         * @since 0.71
912         * @global array $EZSQL_ERROR Stores error information of query and error string
913         *
914         * @param string $str The error to display
915         * @return bool False if the showing of errors is disabled.
916         */
917        function print_error( $str = '' ) {
918                global $EZSQL_ERROR;
919
920                if ( !$str )
921                        $str = mysql_error( $this->dbh );
922                $EZSQL_ERROR[] = array( 'query' => $this->last_query, 'error_str' => $str );
923
924                if ( $this->suppress_errors )
925                        return false;
926
927                if ( $caller = $this->get_caller() )
928                        $error_str = sprintf( /*WP_I18N_DB_QUERY_ERROR_FULL*/'WordPress database error %1$s for query %2$s made by %3$s'/*/WP_I18N_DB_QUERY_ERROR_FULL*/, $str, $this->last_query, $caller );
929                else
930                        $error_str = sprintf( /*WP_I18N_DB_QUERY_ERROR*/'WordPress database error %1$s for query %2$s'/*/WP_I18N_DB_QUERY_ERROR*/, $str, $this->last_query );
931
932                if ( function_exists( 'error_log' )
933                        && ( $log_file = @ini_get( 'error_log' ) )
934                        && ( 'syslog' == $log_file || @is_writable( $log_file ) )
935                        )
936                        @error_log( $error_str );
937
938                // Are we showing errors?
939                if ( ! $this->show_errors )
940                        return false;
941
942                // If there is an error then take note of it
943                if ( is_multisite() ) {
944                        $msg = "WordPress database error: [$str]\n{$this->last_query}\n";
945                        if ( defined( 'ERRORLOGFILE' ) )
946                                error_log( $msg, 3, ERRORLOGFILE );
947                        if ( defined( 'DIEONDBERROR' ) )
948                                wp_die( $msg );
949                } else {
950                        $str   = htmlspecialchars( $str, ENT_QUOTES );
951                        $query = htmlspecialchars( $this->last_query, ENT_QUOTES );
952
953                        print "<div id='error'>
954                        <p class='wpdberror'><strong>WordPress database error:</strong> [$str]<br />
955                        <code>$query</code></p>
956                        </div>";
957                }
958        }
959
960        /**
961         * Enables showing of database errors.
962         *
963         * This function should be used only to enable showing of errors.
964         * wpdb::hide_errors() should be used instead for hiding of errors. However,
965         * this function can be used to enable and disable showing of database
966         * errors.
967         *
968         * @since 0.71
969         * @see wpdb::hide_errors()
970         *
971         * @param bool $show Whether to show or hide errors
972         * @return bool Old value for showing errors.
973         */
974        function show_errors( $show = true ) {
975               
976                $errors = $this->show_errors;
977                $this->show_errors = $show;
978                return $errors;
979        }
980
981        /**
982         * Disables showing of database errors.
983         *
984         * By default database errors are not shown.
985         *
986         * @since 0.71
987         * @see wpdb::show_errors()
988         *
989         * @return bool Whether showing of errors was active
990         */
991        function hide_errors() {
992                $show = $this->show_errors;
993                $this->show_errors = false;
994                return $show;
995        }
996
997        /**
998         * Whether to suppress database errors.
999         *
1000         * By default database errors are suppressed, with a simple
1001         * call to this function they can be enabled.
1002         *
1003         * @since 2.5
1004         * @see wpdb::hide_errors()
1005         * @param bool $suppress Optional. New value. Defaults to true.
1006         * @return bool Old value
1007         */
1008        function suppress_errors( $suppress = true ) {
1009                $errors = $this->suppress_errors;
1010                $this->suppress_errors = (bool) $suppress;
1011                return $errors;
1012        }
1013
1014        /**
1015         * Kill cached query results.
1016         *
1017         * @since 0.71
1018         * @return void
1019         */
1020        function flush() {
1021                $this->last_result = array();
1022                $this->col_info    = null;
1023                $this->last_query  = null;
1024        }
1025
1026        /**
1027         * Connect to and select database
1028         */
1029        function db_connect() {
1030                global $db_list, $global_db_list;
1031
1032                if ( WP_DEBUG ) {
1033                        $this->dbh = mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, true );
1034                } else {
1035                        $this->dbh = @mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, true );
1036                }
1037
1038
1039                if ( !$this->dbh ) {
1040                       
1041                        if(WP_INSTALLING === true) {
1042                           
1043                                 $this->show_errors(true); 
1044                                $this->bail( sprintf( /*WP_I18N_DB_CONN_ERROR*/"
1045<h1> We got the following error with your database credentials </h1>
1046<code> %s </code>
1047<p> 
1048You may want to check your credentials once again?
1049</p> 
1050"/*/WP_I18N_DB_CONN_ERROR*/, mysql_error()),  'db_connect_fail');
1051                                die(); 
1052                        }       else { 
1053
1054                $this->bail( sprintf( /*WP_I18N_DB_CONN_ERROR*/"
1055<h1>Error establishing a database connection</h1>
1056<p>This either means that the username and password information in your <code>wp-config.php</code> file is incorrect or we can't contact the database server at <code>%s</code>. This could mean your host's database server is down.</p>
1057<ul>
1058        <li>Are you sure you have the correct username and password?</li>
1059        <li>Are you sure that you have typed the correct hostname?</li>
1060        <li>Are you sure that the database server is running?</li>
1061</ul>
1062<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='http://wordpress.org/support/'>WordPress Support Forums</a>.</p>
1063"/*/WP_I18N_DB_CONN_ERROR*/, $this->dbhost ), 'db_connect_fail' );
1064
1065                        //If show errors is disabled then we need to die anyway as we don't have a working DB connection
1066                        die();
1067                        }
1068                }
1069
1070                $this->set_charset( $this->dbh );
1071
1072                $this->ready = true;
1073
1074                $this->select( $this->dbname, $this->dbh );
1075        }
1076
1077        /**
1078         * Perform a MySQL database query, using current database connection.
1079         *
1080         * More information can be found on the codex page.
1081         *
1082         * @since 0.71
1083         *
1084         * @param string $query Database query
1085         * @return int|false Number of rows affected/selected or false on error
1086         */
1087        function query( $query ) {
1088                if ( ! $this->ready )
1089                        return false;
1090
1091                // some queries are made before the plugins have been loaded, and thus cannot be filtered with this method
1092                if ( function_exists( 'apply_filters' ) )
1093                        $query = apply_filters( 'query', $query );
1094
1095                $return_val = 0;
1096                $this->flush();
1097
1098                // Log how the function was called
1099                $this->func_call = "\$db->query(\"$query\")";
1100
1101                // Keep track of the last query for debug..
1102                $this->last_query = $query;
1103
1104                if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES )
1105                        $this->timer_start();
1106
1107                $this->result = @mysql_query( $query, $this->dbh );
1108                $this->num_queries++;
1109
1110                if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES )
1111                        $this->queries[] = array( $query, $this->timer_stop(), $this->get_caller() );
1112
1113                // If there is an error then take note of it..
1114                if ( $this->last_error = mysql_error( $this->dbh ) ) {
1115                        $this->print_error();
1116                        return false;
1117                }
1118
1119                if ( preg_match( "/^\\s*(insert|delete|update|replace|alter) /i", $query ) ) {
1120                        $this->rows_affected = mysql_affected_rows( $this->dbh );
1121                        // Take note of the insert_id
1122                        if ( preg_match( "/^\\s*(insert|replace) /i", $query ) ) {
1123                                $this->insert_id = mysql_insert_id($this->dbh);
1124                        }
1125                        // Return number of rows affected
1126                        $return_val = $this->rows_affected;
1127                } else {
1128                        $i = 0;
1129                        while ( $i < @mysql_num_fields( $this->result ) ) {
1130                                $this->col_info[$i] = @mysql_fetch_field( $this->result );
1131                                $i++;
1132                        }
1133                        $num_rows = 0;
1134                        while ( $row = @mysql_fetch_object( $this->result ) ) {
1135                                $this->last_result[$num_rows] = $row;
1136                                $num_rows++;
1137                        }
1138
1139                        @mysql_free_result( $this->result );
1140
1141                        // Log number of rows the query returned
1142                        // and return number of rows selected
1143                        $this->num_rows = $num_rows;
1144                        $return_val     = $num_rows;
1145                }
1146
1147                return $return_val;
1148        }
1149
1150        /**
1151         * Insert a row into a table.
1152         *
1153         * <code>
1154         * wpdb::insert( 'table', array( 'column' => 'foo', 'field' => 'bar' ) )
1155         * wpdb::insert( 'table', array( 'column' => 'foo', 'field' => 1337 ), array( '%s', '%d' ) )
1156         * </code>
1157         *
1158         * @since 2.5.0
1159         * @see wpdb::prepare()
1160         * @see wpdb::$field_types
1161         * @see wp_set_wpdb_vars()
1162         *
1163         * @param string $table table name
1164         * @param array $data Data to insert (in column => value pairs). Both $data columns and $data values should be "raw" (neither should be SQL escaped).
1165         * @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.
1166         *      A format is one of '%d', '%s' (decimal number, string). If omitted, all values in $data will be treated as strings unless otherwise specified in wpdb::$field_types.
1167         * @return int|false The number of rows inserted, or false on error.
1168         */
1169        function insert( $table, $data, $format = null ) {
1170                return $this->_insert_replace_helper( $table, $data, $format, 'INSERT' );
1171        }
1172
1173        /**
1174         * Replace a row into a table.
1175         *
1176         * <code>
1177         * wpdb::replace( 'table', array( 'column' => 'foo', 'field' => 'bar' ) )
1178         * wpdb::replace( 'table', array( 'column' => 'foo', 'field' => 1337 ), array( '%s', '%d' ) )
1179         * </code>
1180         *
1181         * @since 3.0.0
1182         * @see wpdb::prepare()
1183         * @see wpdb::$field_types
1184         * @see wp_set_wpdb_vars()
1185         *
1186         * @param string $table table name
1187         * @param array $data Data to insert (in column => value pairs). Both $data columns and $data values should be "raw" (neither should be SQL escaped).
1188         * @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.
1189         *      A format is one of '%d', '%s' (decimal number, string). If omitted, all values in $data will be treated as strings unless otherwise specified in wpdb::$field_types.
1190         * @return int|false The number of rows affected, or false on error.
1191         */
1192        function replace( $table, $data, $format = null ) {
1193                return $this->_insert_replace_helper( $table, $data, $format, 'REPLACE' );
1194        }
1195
1196        /**
1197         * Helper function for insert and replace.
1198         *
1199         * Runs an insert or replace query based on $type argument.
1200         *
1201         * @access private
1202         * @since 3.0.0
1203         * @see wpdb::prepare()
1204         * @see wpdb::$field_types
1205         * @see wp_set_wpdb_vars()
1206         *
1207         * @param string $table table name
1208         * @param array $data Data to insert (in column => value pairs).  Both $data columns and $data values should be "raw" (neither should be SQL escaped).
1209         * @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.
1210         *      A format is one of '%d', '%s' (decimal number, string). If omitted, all values in $data will be treated as strings unless otherwise specified in wpdb::$field_types.
1211         * @return int|false The number of rows affected, or false on error.
1212         */
1213        function _insert_replace_helper( $table, $data, $format = null, $type = 'INSERT' ) {
1214                if ( ! in_array( strtoupper( $type ), array( 'REPLACE', 'INSERT' ) ) )
1215                        return false;
1216                $formats = $format = (array) $format;
1217                $fields = array_keys( $data );
1218                $formatted_fields = array();
1219                foreach ( $fields as $field ) {
1220                        if ( !empty( $format ) )
1221                                $form = ( $form = array_shift( $formats ) ) ? $form : $format[0];
1222                        elseif ( isset( $this->field_types[$field] ) )
1223                                $form = $this->field_types[$field];
1224                        else
1225                                $form = '%s';
1226                        $formatted_fields[] = $form;
1227                }
1228                $sql = "{$type} INTO `$table` (`" . implode( '`,`', $fields ) . "`) VALUES ('" . implode( "','", $formatted_fields ) . "')";
1229                return $this->query( $this->prepare( $sql, $data ) );
1230        }
1231
1232        /**
1233         * Update a row in the table
1234         *
1235         * <code>
1236         * wpdb::update( 'table', array( 'column' => 'foo', 'field' => 'bar' ), array( 'ID' => 1 ) )
1237         * wpdb::update( 'table', array( 'column' => 'foo', 'field' => 1337 ), array( 'ID' => 1 ), array( '%s', '%d' ), array( '%d' ) )
1238         * </code>
1239         *
1240         * @since 2.5.0
1241         * @see wpdb::prepare()
1242         * @see wpdb::$field_types
1243         * @see wp_set_wpdb_vars()
1244         *
1245         * @param string $table table name
1246         * @param array $data Data to update (in column => value pairs). Both $data columns and $data values should be "raw" (neither should be SQL escaped).
1247         * @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".
1248         * @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.
1249         *      A format is one of '%d', '%s' (decimal number, string). If omitted, all values in $data will be treated as strings unless otherwise specified in wpdb::$field_types.
1250         * @param array|string $format_where 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', '%s' (decimal number, string).  If omitted, all values in $where will be treated as strings.
1251         * @return int|false The number of rows updated, or false on error.
1252         */
1253        function update( $table, $data, $where, $format = null, $where_format = null ) {
1254                if ( ! is_array( $data ) || ! is_array( $where ) )
1255                        return false;
1256
1257                $formats = $format = (array) $format;
1258                $bits = $wheres = array();
1259                foreach ( (array) array_keys( $data ) as $field ) {
1260                        if ( !empty( $format ) )
1261                                $form = ( $form = array_shift( $formats ) ) ? $form : $format[0];
1262                        elseif ( isset($this->field_types[$field]) )
1263                                $form = $this->field_types[$field];
1264                        else
1265                                $form = '%s';
1266                        $bits[] = "`$field` = {$form}";
1267                }
1268
1269                $where_formats = $where_format = (array) $where_format;
1270                foreach ( (array) array_keys( $where ) as $field ) {
1271                        if ( !empty( $where_format ) )
1272                                $form = ( $form = array_shift( $where_formats ) ) ? $form : $where_format[0];
1273                        elseif ( isset( $this->field_types[$field] ) )
1274                                $form = $this->field_types[$field];
1275                        else
1276                                $form = '%s';
1277                        $wheres[] = "`$field` = {$form}";
1278                }
1279
1280                $sql = "UPDATE `$table` SET " . implode( ', ', $bits ) . ' WHERE ' . implode( ' AND ', $wheres );
1281                return $this->query( $this->prepare( $sql, array_merge( array_values( $data ), array_values( $where ) ) ) );
1282        }
1283
1284        /**
1285         * Retrieve one variable from the database.
1286         *
1287         * Executes a SQL query and returns the value from the SQL result.
1288         * 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.
1289         * If $query is null, this function returns the value in the specified column and row from the previous SQL result.
1290         *
1291         * @since 0.71
1292         *
1293         * @param string|null $query Optional. SQL query. Defaults to null, use the result from the previous query.
1294         * @param int $x Optional. Column of value to return.  Indexed from 0.
1295         * @param int $y Optional. Row of value to return.  Indexed from 0.
1296         * @return string|null Database query result (as string), or null on failure
1297         */
1298        function get_var( $query = null, $x = 0, $y = 0 ) {
1299                $this->func_call = "\$db->get_var(\"$query\", $x, $y)";
1300                if ( $query )
1301                        $this->query( $query );
1302
1303                // Extract var out of cached results based x,y vals
1304                if ( !empty( $this->last_result[$y] ) ) {
1305                        $values = array_values( get_object_vars( $this->last_result[$y] ) );
1306                }
1307
1308                // If there is a value return it else return null
1309                return ( isset( $values[$x] ) && $values[$x] !== '' ) ? $values[$x] : null;
1310        }
1311
1312        /**
1313         * Retrieve one row from the database.
1314         *
1315         * Executes a SQL query and returns the row from the SQL result.
1316         *
1317         * @since 0.71
1318         *
1319         * @param string|null $query SQL query.
1320         * @param string $output Optional. one of ARRAY_A | ARRAY_N | OBJECT constants. Return an associative array (column => value, ...),
1321         *      a numerically indexed array (0 => value, ...) or an object ( ->column = value ), respectively.
1322         * @param int $y Optional. Row to return. Indexed from 0.
1323         * @return mixed Database query result in format specifed by $output or null on failure
1324         */
1325        function get_row( $query = null, $output = OBJECT, $y = 0 ) {
1326                $this->func_call = "\$db->get_row(\"$query\",$output,$y)";
1327                if ( $query )
1328                        $this->query( $query );
1329                else
1330                        return null;
1331
1332                if ( !isset( $this->last_result[$y] ) )
1333                        return null;
1334
1335                if ( $output == OBJECT ) {
1336                        return $this->last_result[$y] ? $this->last_result[$y] : null;
1337                } elseif ( $output == ARRAY_A ) {
1338                        return $this->last_result[$y] ? get_object_vars( $this->last_result[$y] ) : null;
1339                } elseif ( $output == ARRAY_N ) {
1340                        return $this->last_result[$y] ? array_values( get_object_vars( $this->last_result[$y] ) ) : null;
1341                } else {
1342                        $this->print_error(/*WP_I18N_DB_GETROW_ERROR*/" \$db->get_row(string query, output type, int offset) -- Output type must be one of: OBJECT, ARRAY_A, ARRAY_N"/*/WP_I18N_DB_GETROW_ERROR*/);
1343                }
1344        }
1345
1346        /**
1347         * Retrieve one column from the database.
1348         *
1349         * Executes a SQL query and returns the column from the SQL result.
1350         * If the SQL result contains more than one column, this function returns the column specified.
1351         * If $query is null, this function returns the specified column from the previous SQL result.
1352         *
1353         * @since 0.71
1354         *
1355         * @param string|null $query Optional. SQL query. Defaults to previous query.
1356         * @param int $x Optional. Column to return. Indexed from 0.
1357         * @return array Database query result. Array indexed from 0 by SQL result row number.
1358         */
1359        function get_col( $query = null , $x = 0 ) {
1360                if ( $query )
1361                        $this->query( $query );
1362
1363                $new_array = array();
1364                // Extract the column values
1365                for ( $i = 0, $j = count( $this->last_result ); $i < $j; $i++ ) {
1366                        $new_array[$i] = $this->get_var( null, $x, $i );
1367                }
1368                return $new_array;
1369        }
1370
1371        /**
1372         * Retrieve an entire SQL result set from the database (i.e., many rows)
1373         *
1374         * Executes a SQL query and returns the entire SQL result.
1375         *
1376         * @since 0.71
1377         *
1378         * @param string $query SQL query.
1379         * @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.
1380         *      Each row is an associative array (column => value, ...), a numerically indexed array (0 => value, ...), or an object. ( ->column = value ), respectively.
1381         *      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.
1382         * @return mixed Database query results
1383         */
1384        function get_results( $query = null, $output = OBJECT ) {
1385                $this->func_call = "\$db->get_results(\"$query\", $output)";
1386
1387                if ( $query )
1388                        $this->query( $query );
1389                else
1390                        return null;
1391
1392                $new_array = array();
1393                if ( $output == OBJECT ) {
1394                        // Return an integer-keyed array of row objects
1395                        return $this->last_result;
1396                } elseif ( $output == OBJECT_K ) {
1397                        // Return an array of row objects with keys from column 1
1398                        // (Duplicates are discarded)
1399                        foreach ( $this->last_result as $row ) {
1400                                $key = array_shift( $var_by_ref = get_object_vars( $row ) );
1401                                if ( ! isset( $new_array[ $key ] ) )
1402                                        $new_array[ $key ] = $row;
1403                        }
1404                        return $new_array;
1405                } elseif ( $output == ARRAY_A || $output == ARRAY_N ) {
1406                        // Return an integer-keyed array of...
1407                        if ( $this->last_result ) {
1408                                foreach( (array) $this->last_result as $row ) {
1409                                        if ( $output == ARRAY_N ) {
1410                                                // ...integer-keyed row arrays
1411                                                $new_array[] = array_values( get_object_vars( $row ) );
1412                                        } else {
1413                                                // ...column name-keyed row arrays
1414                                                $new_array[] = get_object_vars( $row );
1415                                        }
1416                                }
1417                        }
1418                        return $new_array;
1419                }
1420                return null;
1421        }
1422
1423        /**
1424         * Retrieve column metadata from the last query.
1425         *
1426         * @since 0.71
1427         *
1428         * @param string $info_type Optional. Type one of name, table, def, max_length, not_null, primary_key, multiple_key, unique_key, numeric, blob, type, unsigned, zerofill
1429         * @param int $col_offset Optional. 0: col name. 1: which table the col's in. 2: col's max length. 3: if the col is numeric. 4: col's type
1430         * @return mixed Column Results
1431         */
1432        function get_col_info( $info_type = 'name', $col_offset = -1 ) {
1433                if ( $this->col_info ) {
1434                        if ( $col_offset == -1 ) {
1435                                $i = 0;
1436                                $new_array = array();
1437                                foreach( (array) $this->col_info as $col ) {
1438                                        $new_array[$i] = $col->{$info_type};
1439                                        $i++;
1440                                }
1441                                return $new_array;
1442                        } else {
1443                                return $this->col_info[$col_offset]->{$info_type};
1444                        }
1445                }
1446        }
1447
1448        /**
1449         * Starts the timer, for debugging purposes.
1450         *
1451         * @since 1.5.0
1452         *
1453         * @return true
1454         */
1455        function timer_start() {
1456                $mtime            = explode( ' ', microtime() );
1457                $this->time_start = $mtime[1] + $mtime[0];
1458                return true;
1459        }
1460
1461        /**
1462         * Stops the debugging timer.
1463         *
1464         * @since 1.5.0
1465         *
1466         * @return int Total time spent on the query, in milliseconds
1467         */
1468        function timer_stop() {
1469                $mtime      = explode( ' ', microtime() );
1470                $time_end   = $mtime[1] + $mtime[0];
1471                $time_total = $time_end - $this->time_start;
1472                return $time_total;
1473        }
1474
1475        /**
1476         * Wraps errors in a nice header and footer and dies.
1477         *
1478         * Will not die if wpdb::$show_errors is true
1479         *
1480         * @since 1.5.0
1481         *
1482         * @param string $message The Error message
1483         * @param string $error_code Optional. A Computer readable string to identify the error.
1484         * @return false|void
1485         */
1486        function bail( $message, $error_code = '500' ) {
1487             
1488                if ( !$this->show_errors ) {
1489                        if ( class_exists( 'WP_Error' ) )
1490                                $this->error = new WP_Error($error_code, $message);
1491                        else
1492                                $this->error = $message;
1493                        return false;
1494                }
1495                wp_die($message);
1496        }
1497
1498        /**
1499         * Whether MySQL database is at least the required minimum version.
1500         *
1501         * @since 2.5.0
1502         * @uses $wp_version
1503         * @uses $required_mysql_version
1504         *
1505         * @return WP_Error
1506         */
1507        function check_database_version() {
1508                global $wp_version, $required_mysql_version;
1509                // Make sure the server has the required MySQL version
1510                if ( version_compare($this->db_version(), $required_mysql_version, '<') )
1511                        return new WP_Error('database_version', sprintf( __( '<strong>ERROR</strong>: WordPress %1$s requires MySQL %2$s or higher' ), $wp_version, $required_mysql_version ));
1512        }
1513
1514        /**
1515         * Whether the database supports collation.
1516         *
1517         * Called when WordPress is generating the table scheme.
1518         *
1519         * @since 2.5.0
1520         *
1521         * @return bool True if collation is supported, false if version does not
1522         */
1523        function supports_collation() {
1524                return $this->has_cap( 'collation' );
1525        }
1526
1527        /**
1528         * Determine if a database supports a particular feature
1529         *
1530         * @since 2.7
1531         * @see   wpdb::db_version()
1532         *
1533         * @param string $db_cap the feature
1534         * @return bool
1535         */
1536        function has_cap( $db_cap ) {
1537                $version = $this->db_version();
1538
1539                switch ( strtolower( $db_cap ) ) {
1540                        case 'collation' :    // @since 2.5.0
1541                        case 'group_concat' : // @since 2.7
1542                        case 'subqueries' :   // @since 2.7
1543                                return version_compare( $version, '4.1', '>=' );
1544                        case 'set_charset' :
1545                                return version_compare($version, '5.0.7', '>=');
1546                };
1547
1548                return false;
1549        }
1550
1551        /**
1552         * Retrieve the name of the function that called wpdb.
1553         *
1554         * Searches up the list of functions until it reaches
1555         * the one that would most logically had called this method.
1556         *
1557         * @since 2.5.0
1558         *
1559         * @return string The name of the calling function
1560         */
1561        function get_caller() {
1562                $trace  = array_reverse( debug_backtrace() );
1563                $caller = array();
1564
1565                foreach ( $trace as $call ) {
1566                        if ( isset( $call['class'] ) && __CLASS__ == $call['class'] )
1567                                continue; // Filter out wpdb calls.
1568                        $caller[] = isset( $call['class'] ) ? "{$call['class']}->{$call['function']}" : $call['function'];
1569                }
1570
1571                return join( ', ', $caller );
1572        }
1573
1574        /**
1575         * The database version number.
1576         *
1577         * @return false|string false on failure, version number on success
1578         */
1579        function db_version() {
1580                return preg_replace( '/[^0-9.].*/', '', mysql_get_server_info( $this->dbh ) );
1581        }
1582}
1583
1584?>