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.
This commit is contained in:
parent
1e1f1b3dc4
commit
9382bc7a85
2 changed files with 122 additions and 28 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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, ".
|
||||
|
|
|
|||
Loading…
Reference in a new issue