Return a ResultWrapper from Database::query() and query builder functions, instead...
authorTim Starling <tstarling@users.mediawiki.org>
Thu, 5 Jul 2007 19:42:18 +0000 (19:42 +0000)
committerTim Starling <tstarling@users.mediawiki.org>
Thu, 5 Jul 2007 19:42:18 +0000 (19:42 +0000)
includes/Database.php
includes/DatabasePostgres.php

index 4df5c12..f56b7a3 100644 (file)
@@ -678,9 +678,12 @@ class Database {
         * Usually aborts on failure.  If errors are explicitly ignored, returns success.
         *
         * @param  $sql        String: SQL query
-        * @param  $fname      String: Name of the calling function, for profiling/SHOW PROCESSLIST comment (you can use __METHOD__ or add some extra info)
-        * @param  $tempIgnore Bool:   Whether to avoid throwing an exception on errors... maybe best to catch the exception instead?
-        * @return Result object to feed to fetchObject, fetchRow, ...; or false on failure if $tempIgnore set
+        * @param  $fname      String: Name of the calling function, for profiling/SHOW PROCESSLIST 
+        *     comment (you can use __METHOD__ or add some extra info)
+        * @param  $tempIgnore Bool:   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, 
+        *     or false on failure if $tempIgnore set
         * @throws DBQueryError Thrown when the database returns an error of any kind
         */
        public function query( $sql, $fname = '', $tempIgnore = false ) {
@@ -765,7 +768,7 @@ class Database {
                        wfProfileOut( $queryProf );
                        wfProfileOut( $totalProf );
                }
-               return $ret;
+               return $this->resultObject( $ret );
        }
 
        /**
@@ -909,6 +912,9 @@ class Database {
         * Free a result object
         */
        function freeResult( $res ) {
+               if ( $res instanceof ResultWrapper ) {
+                       $res = $res->result;
+               }
                if ( !@/**/mysql_free_result( $res ) ) {
                        throw new DBUnexpectedError( $this, "Unable to free MySQL result" );
                }
@@ -924,6 +930,9 @@ class Database {
         * @throws DBUnexpectedError Thrown if the database returns an error
         */
        function fetchObject( $res ) {
+               if ( $res instanceof ResultWrapper ) {
+                       $res = $res->result;
+               }
                @/**/$row = mysql_fetch_object( $res );
                if( $this->lastErrno() ) {
                        throw new DBUnexpectedError( $this, 'Error in fetchObject(): ' . htmlspecialchars( $this->lastError() ) );
@@ -940,6 +949,9 @@ class Database {
         * @throws DBUnexpectedError Thrown if the database returns an error
         */
        function fetchRow( $res ) {
+               if ( $res instanceof ResultWrapper ) {
+                       $res = $res->result;
+               }
                @/**/$row = mysql_fetch_array( $res );
                if ( $this->lastErrno() ) {
                        throw new DBUnexpectedError( $this, 'Error in fetchRow(): ' . htmlspecialchars( $this->lastError() ) );
@@ -951,6 +963,9 @@ class Database {
         * Get the number of rows in a result object
         */
        function numRows( $res ) {
+               if ( $res instanceof ResultWrapper ) {
+                       $res = $res->result;
+               }
                @/**/$n = mysql_num_rows( $res );
                if( $this->lastErrno() ) {
                        throw new DBUnexpectedError( $this, 'Error in numRows(): ' . htmlspecialchars( $this->lastError() ) );
@@ -962,14 +977,24 @@ class Database {
         * Get the number of fields in a result object
         * See documentation for mysql_num_fields()
         */
-       function numFields( $res ) { return mysql_num_fields( $res ); }
+       function numFields( $res ) {
+               if ( $res instanceof ResultWrapper ) {
+                       $res = $res->result;
+               }
+               return mysql_num_fields( $res );
+       }
 
        /**
         * Get a field name in a result object
         * See documentation for mysql_field_name():
         * http://www.php.net/mysql_field_name
         */
-       function fieldName( $res, $n ) { return mysql_field_name( $res, $n ); }
+       function fieldName( $res, $n ) {
+               if ( $res instanceof ResultWrapper ) {
+                       $res = $res->result;
+               }
+               return mysql_field_name( $res, $n );
+       }
 
        /**
         * Get the inserted value of an auto-increment row
@@ -987,7 +1012,12 @@ class Database {
         * Change the position of the cursor in a result object
         * See mysql_data_seek()
         */
-       function dataSeek( $res, $row ) { return mysql_data_seek( $res, $row ); }
+       function dataSeek( $res, $row ) {
+               if ( $res instanceof ResultWrapper ) {
+                       $res = $res->result;
+               }
+               return mysql_data_seek( $res, $row );
+       }
 
        /**
         * Get the last error number
@@ -1352,9 +1382,9 @@ class Database {
        function fieldInfo( $table, $field ) {
                $table = $this->tableName( $table );
                $res = $this->query( "SELECT * FROM $table LIMIT 1" );
-               $n = mysql_num_fields( $res );
+               $n = mysql_num_fields( $res->result );
                for( $i = 0; $i < $n; $i++ ) {
-                       $meta = mysql_fetch_field( $res, $i );
+                       $meta = mysql_fetch_field( $res->result, $i );
                        if( $field == $meta->name ) {
                                return new MySQLField($meta);
                        }
@@ -1366,6 +1396,9 @@ class Database {
         * mysql_field_type() wrapper
         */
        function fieldType( $res, $index ) {
+               if ( $res instanceof ResultWrapper ) {
+                       $res = $res->result;
+               }
                return mysql_field_type( $res, $index );
        }
 
@@ -2001,7 +2034,12 @@ class Database {
         */
        function resultObject( $result ) {
                if( empty( $result ) ) {
-                       return NULL;
+                       return false;
+               } elseif ( $result instanceof ResultWrapper ) {
+                       return $result;
+               } elseif ( $result === true ) {
+                       // Successful write query
+                       return $result;
                } else {
                        return new ResultWrapper( $this, $result );
                }
@@ -2176,7 +2214,7 @@ class Database {
                                $cmd = $this->replaceVars( $cmd );
                                $res = $this->query( $cmd, __METHOD__, true );
                                if ( $resultCallback ) {
-                                       call_user_func( $resultCallback, $this->resultObject( $res ) );
+                                       call_user_func( $resultCallback, $res );
                                }
 
                                if ( false === $res ) {
@@ -2248,36 +2286,51 @@ class ResultWrapper {
        var $db, $result;
 
        /**
-        * @todo document
+        * Create a new result object from a result resource and a Database object
         */
-       function ResultWrapper( &$database, $result ) {
-               $this->db =& $database;
-               $this->result =& $result;
+       function ResultWrapper( $database, $result ) {
+               $this->db = $database;
+               if ( $result instanceof ResultWrapper ) {
+                       $this->result = $result->result;
+               } else {
+                       $this->result = $result;
+               }
        }
 
        /**
-        * @todo document
+        * Get the number of rows in a result object
         */
        function numRows() {
                return $this->db->numRows( $this->result );
        }
 
        /**
-        * @todo document
+        * Fetch the next row from the given result object, in object form.
+        * Fields can be retrieved with $row->fieldname, with fields acting like
+        * member variables.
+        *
+        * @param $res SQL result object as returned from Database::query(), etc.
+        * @return MySQL row object
+        * @throws DBUnexpectedError Thrown if the database returns an error
         */
        function fetchObject() {
                return $this->db->fetchObject( $this->result );
        }
 
        /**
-        * @todo document
+        * Fetch the next row from the given result object, in associative array
+        * form.  Fields are retrieved with $row['fieldname'].
+        *
+        * @param $res SQL result object as returned from Database::query(), etc.
+        * @return MySQL row object
+        * @throws DBUnexpectedError Thrown if the database returns an error
         */
        function fetchRow() {
                return $this->db->fetchRow( $this->result );
        }
 
        /**
-        * @todo document
+        * Free a result object
         */
        function free() {
                $this->db->freeResult( $this->result );
@@ -2285,10 +2338,17 @@ class ResultWrapper {
                unset( $this->db );
        }
 
+       /**
+        * Change the position of the cursor in a result object
+        * See mysql_data_seek()
+        */
        function seek( $row ) {
                $this->db->dataSeek( $this->result, $row );
        }
        
+       /**
+        * Reset the cursor to the start of the result set
+        */
        function rewind() {
                if ($this->numRows()) {
                        $this->db->dataSeek($this->result, 0);
index 9bc055c..b04af1d 100644 (file)
@@ -505,12 +505,18 @@ class DatabasePostgres extends Database {
        }
 
        function freeResult( $res ) {
+               if ( $res instanceof ResultWrapper ) {
+                       $res = $res->result;
+               }
                if ( !@pg_free_result( $res ) ) {
                        throw new DBUnexpectedError($this,  "Unable to free Postgres result\n" );
                }
        }
 
        function fetchObject( $res ) {
+               if ( $res instanceof ResultWrapper ) {
+                       $res = $res->result;
+               }
                @$row = pg_fetch_object( $res );
                # FIXME: HACK HACK HACK HACK debug
 
@@ -524,6 +530,9 @@ class DatabasePostgres extends Database {
        }
 
        function fetchRow( $res ) {
+               if ( $res instanceof ResultWrapper ) {
+                       $res = $res->result;
+               }
                @$row = pg_fetch_array( $res );
                if( pg_last_error($this->mConn) ) {
                        throw new DBUnexpectedError($this,  'SQL error: ' . htmlspecialchars( pg_last_error($this->mConn) ) );
@@ -532,14 +541,27 @@ class DatabasePostgres extends Database {
        }
 
        function numRows( $res ) {
+               if ( $res instanceof ResultWrapper ) {
+                       $res = $res->result;
+               }
                @$n = pg_num_rows( $res );
                if( pg_last_error($this->mConn) ) {
                        throw new DBUnexpectedError($this,  'SQL error: ' . htmlspecialchars( pg_last_error($this->mConn) ) );
                }
                return $n;
        }
-       function numFields( $res ) { return pg_num_fields( $res ); }
-       function fieldName( $res, $n ) { return pg_field_name( $res, $n ); }
+       function numFields( $res ) {
+               if ( $res instanceof ResultWrapper ) {
+                       $res = $res->result;
+               }
+               return pg_num_fields( $res );
+       }
+       function fieldName( $res, $n ) {
+               if ( $res instanceof ResultWrapper ) {
+                       $res = $res->result;
+               }
+               return pg_field_name( $res, $n );
+       }
 
        /**
         * This must be called after nextSequenceVal
@@ -548,7 +570,13 @@ class DatabasePostgres extends Database {
                return $this->mInsertId;
        }
 
-       function dataSeek( $res, $row ) { return pg_result_seek( $res, $row ); }
+       function dataSeek( $res, $row ) {
+               if ( $res instanceof ResultWrapper ) {
+                       $res = $res->result;
+               }
+               return pg_result_seek( $res, $row );
+       }
+
        function lastError() {
                if ( $this->mConn ) {
                        return pg_last_error();
@@ -917,7 +945,7 @@ class DatabasePostgres extends Database {
                        . "WHERE c.relnamespace = n.oid AND c.relname = $etable AND n.nspname = $eschema "
                        . "AND c.relkind IN ('" . implode("','", $types) . "')";
                $res = $this->query( $SQL );
-               $count = $res ? pg_num_rows($res) : 0;
+               $count = $res ? $res->numRows() : 0;
                if ($res)
                        $this->freeResult( $res );
                return $count ? true : false;
@@ -950,7 +978,7 @@ END;
                                $this->addQuotes($trigger)));
                if (!$res)
                        return NULL;
-               $rows = pg_num_rows($res);
+               $rows = $res->numRows();
                $this->freeResult($res);
                return $rows;
        }
@@ -974,7 +1002,7 @@ END;
                $res = $this->query($SQL);
                if (!$res)
                        return NULL;
-               $rows = pg_num_rows($res);
+               $rows = $res->numRows();
                $this->freeResult($res);
                return $rows;
        }
@@ -987,7 +1015,12 @@ END;
                $SQL = "SELECT rolname FROM pg_catalog.pg_namespace n, pg_catalog.pg_roles r "
                                ."WHERE n.nspowner=r.oid AND n.nspname = '$eschema'";
                $res = $this->query( $SQL );
-               $owner = $res ? pg_num_rows($res) ? pg_fetch_result($res, 0, 0) : false : false;
+               if ( $res && $res->numRows() ) {
+                       $row = $res->fetchRow();
+                       $owner = $row->rolname;
+               } else {
+                       $owner = false;
+               }
                if ($res)
                        $this->freeResult($res);
                return $owner;
@@ -1005,7 +1038,7 @@ END;
                        . "WHERE c.relnamespace = n.oid AND c.relname = '$etable' AND n.nspname = '$eschema' "
                        . "AND a.attrelid = c.oid AND a.attname = '$ecol'";
                $res = $this->query( $SQL, $fname );
-               $count = $res ? pg_num_rows($res) : 0;
+               $count = $res ? $res->numRows() : 0;
                if ($res)
                        $this->freeResult( $res );
                return $count;
@@ -1071,7 +1104,8 @@ END;
                $tss = $this->addQuotes($wgDBts2schema);
                $pgp = $this->addQuotes($wgDBport);
                $dbn = $this->addQuotes($this->mDBname);
-               $ctype = pg_fetch_result($this->doQuery("SHOW lc_ctype"),0,0);
+               $ctypeRow = $this->doQuery("SHOW lc_ctype")->fetchArray();
+               $ctype = $ctypeRow[0];
 
                $SQL = "UPDATE mediawiki_version SET mw_version=$mwv, pg_version=$pgv, pg_user=$pgu, ".
                                "mw_schema = $mws, ts2_schema = $tss, pg_port=$pgp, pg_dbname=$dbn, ".