Followup to r77713, rename quote_ident to addIdentifierQuotes to follow naming conven...
[lhc/web/wiklou.git] / includes / db / Database.php
index c9a45e1..7248bb9 100644 (file)
@@ -604,7 +604,7 @@ abstract class DatabaseBase implements DatabaseType {
         *     comment (you can use __METHOD__ or add some extra info)
         * @param  $tempIgnore Boolean:   Whether to avoid throwing an exception on errors...
         *     maybe best to catch the exception instead?
-        * @return true for a successful write query, ResultWrapper object for a successful read query,
+        * @return boolean or ResultWrapper. true for a successful write query, ResultWrapper object for a successful read query,
         *     or false on failure if $tempIgnore set
         * @throws DBQueryError Thrown when the database returns an error of any kind
         */
@@ -1012,7 +1012,7 @@ abstract class DatabaseBase implements DatabaseType {
        /**
         * SELECT wrapper
         *
-        * @param $table   Mixed:  Array or string, table name(s) (prefix auto-added)
+        * @param $table   Mixed:  Array or string, table name(s) (prefix auto-added). Array keys are table aliases (optional)
         * @param $vars    Mixed:  Array or string, field name(s) to be retrieved
         * @param $conds   Mixed:  Array or string, condition(s) for WHERE
         * @param $fname   String: Calling function name (use __METHOD__) for logs/profiling
@@ -1035,7 +1035,7 @@ abstract class DatabaseBase implements DatabaseType {
                        if ( !empty( $join_conds ) || ( isset( $options['USE INDEX'] ) && is_array( @$options['USE INDEX'] ) ) ) {
                                $from = ' FROM ' . $this->tableNamesWithUseIndexOrJOIN( $table, @$options['USE INDEX'], $join_conds );
                        } else {
-                               $from = ' FROM ' . implode( ',', array_map( array( &$this, 'tableName' ), $table ) );
+                               $from = ' FROM ' . implode( ',', $this->tableNamesWithAlias( $table ) );
                        }
                } elseif ( $table != '' ) {
                        if ( $table { 0 } == ' ' ) {
@@ -1575,6 +1575,39 @@ abstract class DatabaseBase implements DatabaseType {
                return $retVal;
        }
 
+       /**
+        * Get an aliased table name
+        * e.g. tableName AS newTableName
+        *
+        * @param $name string Table name, see tableName()
+        * @param $alias string Alias (optional)
+        * @return string SQL name for aliased table. Will not alias a table to its own name
+        */
+       public function tableNameWithAlias( $name, $alias = false ) {
+               if ( !$alias || $alias == $name ) {
+                       return $this->tableName( $name );
+               } else {
+                       return $this->tableName( $name ) . ' `' . $alias . '`';
+               }
+       }
+
+       /**
+        * Gets an array of aliased table names
+        *
+        * @param $tables array( [alias] => table )
+        * @return array of strings, see tableNameWithAlias()
+        */
+       public function tableNamesWithAlias( $tables ) {
+               $retval = array();
+               foreach ( $tables as $alias => $table ) {
+                       if ( is_numeric( $alias ) ) {
+                               $alias = $table;
+                       }
+                       $retval[] = $this->tableNameWithAlias( $table, $alias );
+               }
+               return $retval;
+       }
+
        /**
         * @private
         */
@@ -1584,35 +1617,37 @@ abstract class DatabaseBase implements DatabaseType {
                $use_index_safe = is_array( $use_index ) ? $use_index : array();
                $join_conds_safe = is_array( $join_conds ) ? $join_conds : array();
 
-               foreach ( $tables as $table ) {
+               foreach ( $tables as $alias => $table ) {
+                       if ( !is_string( $alias ) ) {
+                               // No alias? Set it equal to the table name
+                               $alias = $table;
+                       }
                        // Is there a JOIN and INDEX clause for this table?
-                       if ( isset( $join_conds_safe[$table] ) && isset( $use_index_safe[$table] ) ) {
-                               $tableClause = $join_conds_safe[$table][0] . ' ' . $this->tableName( $table );
-                               $tableClause .= ' ' . $this->useIndexClause( implode( ',', (array)$use_index_safe[$table] ) );
-                               $on = $this->makeList( (array)$join_conds_safe[$table][1], LIST_AND );
-
+                       if ( isset( $join_conds_safe[$alias] ) && isset( $use_index_safe[$alias] ) ) {
+                               $tableClause = $join_conds_safe[$alias][0] . ' ' . $this->tableNameWithAlias( $table, $alias );
+                               $tableClause .= ' ' . $this->useIndexClause( implode( ',', (array)$use_index_safe[$alias] ) );
+                               $on = $this->makeList( (array)$join_conds_safe[$alias][1], LIST_AND );
                                if ( $on != '' ) {
                                        $tableClause .= ' ON (' . $on . ')';
                                }
 
                                $retJOIN[] = $tableClause;
                        // Is there an INDEX clause?
-                       } else if ( isset( $use_index_safe[$table] ) ) {
-                               $tableClause = $this->tableName( $table );
-                               $tableClause .= ' ' . $this->useIndexClause( implode( ',', (array)$use_index_safe[$table] ) );
+                       } else if ( isset( $use_index_safe[$alias] ) ) {
+                               $tableClause = $this->tableNameWithAlias( $table, $alias );
+                               $tableClause .= ' ' . $this->useIndexClause( implode( ',', (array)$use_index_safe[$alias] ) );
                                $ret[] = $tableClause;
                        // Is there a JOIN clause?
-                       } else if ( isset( $join_conds_safe[$table] ) ) {
-                               $tableClause = $join_conds_safe[$table][0] . ' ' . $this->tableName( $table );
-                               $on = $this->makeList( (array)$join_conds_safe[$table][1], LIST_AND );
-
+                       } else if ( isset( $join_conds_safe[$alias] ) ) {
+                               $tableClause = $join_conds_safe[$alias][0] . ' ' . $this->tableNameWithAlias( $table, $alias );
+                               $on = $this->makeList( (array)$join_conds_safe[$alias][1], LIST_AND );
                                if ( $on != '' ) {
                                        $tableClause .= ' ON (' . $on . ')';
                                }
 
                                $retJOIN[] = $tableClause;
                        } else {
-                               $tableClause = $this->tableName( $table );
+                               $tableClause = $this->tableNameWithAlias( $table, $alias );
                                $ret[] = $tableClause;
                        }
                }
@@ -1659,6 +1694,26 @@ abstract class DatabaseBase implements DatabaseType {
                }
        }
 
+       /**
+        * Quotes a string using `backticks` for things like database, table, and field
+        * names, other databases which use something other than backticks can replace
+        * this with something else
+        */      
+       public function addIdentifierQuotes( $s ) {
+               return "`" . $this->strencode( $s ) . "`";
+       }
+
+       /**
+        * Backwards compatibility, identifier quoting originated in DatabasePostgres
+        * which used quote_ident which does not follow our naming conventions
+        * was renamed to addIdentifierQuotes.
+        * @deprecated use addIdentifierQuotes
+        */
+       function quote_ident( $s ) {
+               wfDeprecated( __METHOD__ );
+               return $this->addIdentifierQuotes( $s );
+       }
+
        /**
         * Escape string for safe LIKE usage.
         * WARNING: you should almost never use this function directly,
@@ -1988,6 +2043,16 @@ abstract class DatabaseBase implements DatabaseType {
                return "REPLACE({$orig}, {$old}, {$new})";
        }
 
+       /**
+        * Convert a field to an unix timestamp
+        *
+        * @param $field String: field name
+        * @return String: SQL statement
+        */
+       public function unixTimestamp( $field ) {
+               return "EXTRACT(epoch FROM $field)";
+       }
+
        /**
         * Determines if the last failure was due to a deadlock
         * STUB
@@ -2455,6 +2520,32 @@ abstract class DatabaseBase implements DatabaseType {
                return true;
        }
 
+       /**
+        * Database independent variable replacement, replaces a set of named variables
+        * in a sql statement with the contents of their global variables.
+        * Supports '{$var}' `{$var}` and / *$var* / (without the spaces) style variables
+        * 
+        * '{$var}' should be used for text and is passed through the database's addQuotes method
+        * `{$var}` should be used for identifiers (eg: table and database names), it is passed through
+        *          the database's addIdentifierQuotes method which can be overridden if the database
+        *          uses something other than backticks.
+        * / *$var* / is just encoded, besides traditional dbprefix and tableoptions it's use should be avoided
+        * 
+        * @param $ins String: SQL statement to replace variables in
+        * @param $varnames Array: Array of global variable names to replace
+        * @return String The new SQL statement with variables replaced
+        */
+       protected function replaceGlobalVars( $ins, $varnames ) {
+               foreach ( $varnames as $var ) {
+                       if ( isset( $GLOBALS[$var] ) ) {
+                               $ins = str_replace( '\'{$' . $var . '}\'', $this->addQuotes( $GLOBALS[$var] ), $ins ); // replace '{$var}'
+                               $ins = str_replace( '`{$' . $var . '}`', $this->addIdentifierQuotes( $GLOBALS[$var] ), $ins ); // replace `{$var}`
+                               $ins = str_replace( '/*$' . $var . '*/', $this->strencode( $GLOBALS[$var] ) , $ins ); // replace /*$var*/
+                       }
+               }
+               return $ins;
+       }
+
        /**
         * Replace variables in sourced SQL
         */
@@ -2465,15 +2556,7 @@ abstract class DatabaseBase implements DatabaseType {
                        'wgDBadminuser', 'wgDBadminpassword', 'wgDBTableOptions',
                );
 
-               // Ordinary variables
-               foreach ( $varnames as $var ) {
-                       if ( isset( $GLOBALS[$var] ) ) {
-                               $val = addslashes( $GLOBALS[$var] ); // FIXME: safety check?
-                               $ins = str_replace( '{$' . $var . '}', $val, $ins );
-                               $ins = str_replace( '/*$' . $var . '*/`', '`' . $val, $ins );
-                               $ins = str_replace( '/*$' . $var . '*/', $val, $ins );
-                       }
-               }
+               $ins = $this->replaceGlobalVars( $ins, $varnames );
 
                // Table prefixes
                $ins = preg_replace_callback( '!/\*(?:\$wgDBprefix|_)\*/([a-zA-Z_0-9]*)!',
@@ -2795,7 +2878,7 @@ class DBConnectionError extends DBError {
        }
 
        function searchForm() {
-               global $wgSitename, $wgServer, $wgLang, $wgInputEncoding;
+               global $wgSitename, $wgServer, $wgLang;
 
                $usegoogle = "You can try searching via Google in the meantime.";
                $outofdate = "Note that their indexes of our content may be out of date.";
@@ -2809,20 +2892,23 @@ class DBConnectionError extends DBError {
 
                $search = htmlspecialchars( @$_REQUEST['search'] );
 
+               $server = htmlspecialchars( $wgServer );
+               $sitename = htmlspecialchars( $wgSitename );
+
                $trygoogle = <<<EOT
 <div style="margin: 1.5em">$usegoogle<br />
 <small>$outofdate</small></div>
 <!-- SiteSearch Google -->
 <form method="get" action="http://www.google.com/search" id="googlesearch">
-       <input type="hidden" name="domains" value="$wgServer" />
+       <input type="hidden" name="domains" value="$server" />
        <input type="hidden" name="num" value="50" />
-       <input type="hidden" name="ie" value="$wgInputEncoding" />
-       <input type="hidden" name="oe" value="$wgInputEncoding" />
+       <input type="hidden" name="ie" value="UTF-8" />
+       <input type="hidden" name="oe" value="UTF-8" />
 
        <input type="text" name="q" size="31" maxlength="255" value="$search" />
        <input type="submit" name="btnG" value="$googlesearch" />
   <div>
-       <input type="radio" name="sitesearch" id="gwiki" value="$wgServer" checked="checked" /><label for="gwiki">$wgSitename</label>
+       <input type="radio" name="sitesearch" id="gwiki" value="$server" checked="checked" /><label for="gwiki">$sitename</label>
        <input type="radio" name="sitesearch" id="gWWW" value="" /><label for="gWWW">WWW</label>
   </div>
 </form>