From 9382bc7a858cf5c6a41794aba51f437efbf093c7 Mon Sep 17 00:00:00 2001 From: Tim Starling Date: Thu, 5 Jul 2007 19:42:18 +0000 Subject: [PATCH] Return a ResultWrapper from Database::query() and query builder functions, instead of a raw DB result resource. Backwards compatibility is maintained, except with naughty code that was calling database driver functions directly on result objects. --- includes/Database.php | 98 ++++++++++++++++++++++++++++------- includes/DatabasePostgres.php | 52 +++++++++++++++---- 2 files changed, 122 insertions(+), 28 deletions(-) diff --git a/includes/Database.php b/includes/Database.php index 4df5c123f5..f56b7a3947 100644 --- a/includes/Database.php +++ b/includes/Database.php @@ -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); diff --git a/includes/DatabasePostgres.php b/includes/DatabasePostgres.php index 9bc055c7c0..b04af1d445 100644 --- a/includes/DatabasePostgres.php +++ b/includes/DatabasePostgres.php @@ -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, ". -- 2.20.1