database.php
来自「php 开发的内容管理系统」· PHP 代码 · 共 2,046 行 · 第 1/4 页
PHP
2,046 行
}
return $this->query( $sql, $fname );
}
/**
* INSERT SELECT wrapper
* $varMap must be an associative array of the form array( 'dest1' => 'source1', ...)
* Source items may be literals rather than field names, but strings should be quoted with Database::addQuotes()
* $conds may be "*" to copy the whole table
* srcTable may be an array of tables.
*/
function insertSelect( $destTable, $srcTable, $varMap, $conds, $fname = 'mwDatabase::insertSelect',
$insertOptions = array(), $selectOptions = array() )
{
$destTable = $this->tableName( $destTable );
if ( is_array( $insertOptions ) ) {
$insertOptions = implode( ' ', $insertOptions );
}
if( !is_array( $selectOptions ) ) {
$selectOptions = array( $selectOptions );
}
list( $startOpts, $useIndex, $tailOpts ) = $this->makeSelectOptions( $selectOptions );
if( is_array( $srcTable ) ) {
$srcTable = implode( ',', array_map( array( &$this, 'tableName' ), $srcTable ) );
} else {
$srcTable = $this->tableName( $srcTable );
}
$sql = "INSERT $insertOptions INTO $destTable (" . implode( ',', array_keys( $varMap ) ) . ')' .
" SELECT $startOpts " . implode( ',', $varMap ) .
" FROM $srcTable $useIndex ";
if ( $conds != '*' ) {
$sql .= ' WHERE ' . $this->makeList( $conds, LIST_AND );
}
$sql .= " $tailOpts";
return $this->query( $sql, $fname );
}
/**
* Construct a LIMIT query with optional offset
* This is used for query pages
* $sql string SQL query we will append the limit too
* $limit integer the SQL limit
* $offset integer the SQL offset (default false)
*/
function limitResult($sql, $limit, $offset=false) {
if( !is_numeric($limit) ) {
throw new DBUnexpectedError( $this, "Invalid non-numeric limit passed to limitResult()\n" );
}
return " $sql LIMIT "
. ( (is_numeric($offset) && $offset != 0) ? "{$offset}," : "" )
. "{$limit} ";
}
function limitResultForUpdate($sql, $num) {
return $this->limitResult($sql, $num, 0);
}
/**
* Returns an SQL expression for a simple conditional.
* Uses IF on MySQL.
*
* @param string $cond SQL expression which will result in a boolean value
* @param string $trueVal SQL expression to return if true
* @param string $falseVal SQL expression to return if false
* @return string SQL fragment
*/
function conditional( $cond, $trueVal, $falseVal ) {
return " IF($cond, $trueVal, $falseVal) ";
}
/**
* Determines if the last failure was due to a deadlock
*/
function wasDeadlock() {
return $this->lastErrno() == 1213;
}
/**
* Perform a deadlock-prone transaction.
*
* This function invokes a callback function to perform a set of write
* queries. If a deadlock occurs during the processing, the transaction
* will be rolled back and the callback function will be called again.
*
* Usage:
* $dbw->deadlockLoop( callback, ... );
*
* Extra arguments are passed through to the specified callback function.
*
* Returns whatever the callback function returned on its successful,
* iteration, or false on error, for example if the retry limit was
* reached.
*/
function deadlockLoop() {
$myFname = 'mwDatabase::deadlockLoop';
$this->begin();
$args = func_get_args();
$function = array_shift( $args );
$oldIgnore = $this->ignoreErrors( true );
$tries = DEADLOCK_TRIES;
if ( is_array( $function ) ) {
$fname = $function[0];
} else {
$fname = $function;
}
do {
$retVal = call_user_func_array( $function, $args );
$error = $this->lastError();
$errno = $this->lastErrno();
$sql = $this->lastQuery();
if ( $errno ) {
if ( $this->wasDeadlock() ) {
# Retry
usleep( mt_rand( DEADLOCK_DELAY_MIN, DEADLOCK_DELAY_MAX ) );
} else {
$this->reportQueryError( $error, $errno, $sql, $fname );
}
}
} while( $this->wasDeadlock() && --$tries > 0 );
$this->ignoreErrors( $oldIgnore );
if ( $tries <= 0 ) {
$this->query( 'ROLLBACK', $myFname );
$this->reportQueryError( $error, $errno, $sql, $fname );
return false;
} else {
$this->query( 'COMMIT', $myFname );
return $retVal;
}
}
/**
* Do a SELECT MASTER_POS_WAIT()
*
* @param string $file the binlog file
* @param string $pos the binlog position
* @param integer $timeout the maximum number of seconds to wait for synchronisation
*/
function masterPosWait( $file, $pos, $timeout ) {
$fname = 'mwDatabase::masterPosWait';
wfProfileIn( $fname );
# Commit any open transactions
$this->immediateCommit();
# Call doQuery() directly, to avoid opening a transaction if DBO_TRX is set
$encFile = $this->strencode( $file );
$sql = "SELECT MASTER_POS_WAIT('$encFile', $pos, $timeout)";
$res = $this->doQuery( $sql );
if ( $res && $row = $this->fetchRow( $res ) ) {
$this->freeResult( $res );
wfProfileOut( $fname );
return $row[0];
} else {
wfProfileOut( $fname );
return false;
}
}
/**
* Get the position of the master from SHOW SLAVE STATUS
*/
function getSlavePos() {
$res = $this->query( 'SHOW SLAVE STATUS', 'mwDatabase::getSlavePos' );
$row = $this->fetchObject( $res );
if ( $row ) {
return array( $row->Master_Log_File, $row->Read_Master_Log_Pos );
} else {
return array( false, false );
}
}
/**
* Get the position of the master from SHOW MASTER STATUS
*/
function getMasterPos() {
$res = $this->query( 'SHOW MASTER STATUS', 'mwDatabase::getMasterPos' );
$row = $this->fetchObject( $res );
if ( $row ) {
return array( $row->File, $row->Position );
} else {
return array( false, false );
}
}
/**
* Begin a transaction, committing any previously open transaction
*/
function begin( $fname = 'mwDatabase::begin' ) {
$this->query( 'BEGIN', $fname );
$this->mTrxLevel = 1;
}
/**
* End a transaction
*/
function commit( $fname = 'mwDatabase::commit' ) {
$this->query( 'COMMIT', $fname );
$this->mTrxLevel = 0;
}
/**
* Rollback a transaction
*/
function rollback( $fname = 'mwDatabase::rollback' ) {
$this->query( 'ROLLBACK', $fname );
$this->mTrxLevel = 0;
}
/**
* Begin a transaction, committing any previously open transaction
* @deprecated use begin()
*/
function immediateBegin( $fname = 'mwDatabase::immediateBegin' ) {
$this->begin();
}
/**
* Commit transaction, if one is open
* @deprecated use commit()
*/
function immediateCommit( $fname = 'mwDatabase::immediateCommit' ) {
$this->commit();
}
/**
* Return MW-style timestamp used for MySQL schema
*/
function timestamp( $ts=0 ) {
return wfTimestamp(TS_MW,$ts);
}
/**
* Local database timestamp format or null
*/
function timestampOrNull( $ts = null ) {
if( is_null( $ts ) ) {
return null;
} else {
return $this->timestamp( $ts );
}
}
/**
* @todo document
*/
function resultObject( $result ) {
if( empty( $result ) ) {
return NULL;
} else {
return new ResultWrapper( $this, $result );
}
}
/**
* Return aggregated value alias
*/
function aggregateValue ($valuedata,$valuename='value') {
return $valuename;
}
/**
* @return string wikitext of a link to the server software's web site
*/
function getSoftwareLink() {
return "[http://www.mysql.com/ MySQL]";
}
/**
* @return string Version information from the database
*/
function getServerVersion() {
return mysql_get_server_info();
}
/**
* Ping the server and try to reconnect if it there is no connection
*/
function ping() {
if( function_exists( 'mysql_ping' ) ) {
return mysql_ping( $this->mConn );
} else {
wfDebug( "Tried to call mysql_ping but this is ancient PHP version. Faking it!\n" );
return true;
}
}
/**
* Get slave lag.
* At the moment, this will only work if the DB user has the PROCESS privilege
*/
function getLag() {
$res = $this->query( 'SHOW PROCESSLIST' );
# Find slave SQL thread. Assumed to be the second one running, which is a bit
# dubious, but unfortunately there's no easy rigorous way
$slaveThreads = 0;
while ( $row = $this->fetchObject( $res ) ) {
/* This should work for most situations - when default db
* for thread is not specified, it had no events executed,
* and therefore it doesn't know yet how lagged it is.
*
* Relay log I/O thread does not select databases.
*/
if ( $row->User == 'system user' &&
$row->State != 'Waiting for master to send event' &&
$row->State != 'Connecting to master' &&
$row->State != 'Queueing master event to the relay log' &&
$row->State != 'Waiting for master update' &&
$row->State != 'Requesting binlog dump'
) {
# This is it, return the time (except -ve)
if ( $row->Time > 0x7fffffff ) {
return false;
} else {
return $row->Time;
}
}
}
return false;
}
/**
* Get status information from SHOW STATUS in an associative array
*/
function getStatus($which="%") {
$res = $this->query( "SHOW STATUS LIKE '{$which}'" );
$status = array();
while ( $row = $this->fetchObject( $res ) ) {
$status[$row->Variable_name] = $row->Value;
}
return $status;
}
/**
* Return the maximum number of items allowed in a list, or 0 for unlimited.
*/
function maxListLen() {
return 0;
}
function encodeBlob($b) {
return $b;
}
function decodeBlob($b) {
return $b;
}
/**
* Read and execute SQL commands from a file.
* Returns true on success, error string on failure
*/
function sourceFile( $filename ) {
$fp = fopen( $filename, 'r' );
if ( false === $fp ) {
return "Could not open \"{$fname}\".\n";
}
$cmd = "";
$done = false;
$dollarquote = false;
while ( ! feof( $fp ) ) {
$line = trim( fgets( $fp, 1024 ) );
$sl = strlen( $line ) - 1;
if ( $sl < 0 ) { continue; }
if ( '-' == $line{0} && '-' == $line{1} ) { continue; }
## Allow dollar quoting for function declarations
if (substr($line,0,4) == '$mw$') {
if ($dollarquote) {
$dollarquote = false;
$done = true;
}
else {
$dollarquote = true;
}
}
else if (!$dollarquote) {
if ( ';' == $line{$sl} && ($sl < 2 || ';' != $line{$sl - 1})) {
$done = true;
$line = substr( $line, 0, $sl );
}
}
if ( '' != $cmd ) { $cmd .= ' '; }
$cmd .= "$line\n";
if ( $done ) {
$cmd = str_replace(';;', ";", $cmd);
$cmd = $this->replaceVars( $cmd );
$res = $this->query( $cmd, 'dbsource', true );
if ( false === $res ) {
$err = $this->lastError();
return "Query \"{$cmd}\" failed with error code \"$err\".\n";
}
$cmd = '';
$done = false;
}
}
fclose( $fp );
return true;
}
/**
* Replace variables in sourced SQL
*/
protected function replaceVars( $ins ) {
$varnames = array(
'wgDBserver', 'wgDBname', 'wgDBintlname', 'wgDBuser',
'wgDBpassword', 'wgDBsqluser', 'wgDBsqlpassword',
'wgDBadminuser', 'wgDBadminpassword',
);
// 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 );
}
}
// Table prefixes
$ins = preg_replace_callback( '/\/\*(?:\$wgDBprefix|_)\*\/([a-z_]*)/',
array( &$this, 'tableNameCallback' ), $ins );
return $ins;
}
/**
* Table name callback
* @private
*/
protected function tableNameCallback( $matches ) {
return $this->tableName( $matches[1] );
}
}
/**
* Database abstraction object for mySQL
* Inherit all methods and properties of Database::Database()
*
* @package MediaWiki
* @see Database
*/
class DatabaseMysql extends mwDatabase {
# Inherit all
}
/**
* Result wrapper for grabbing data queried by someone else
*
* @package MediaWiki
*/
class ResultWrapper {
var $db, $result;
/**
* @todo document
*/
function ResultWrapper( &$database, $result ) {
$this->db =& $database;
$this->result =& $result;
}
/**
* @todo document
*/
function numRows() {
return $this->db->numRows( $this->result );
}
/**
* @todo document
*/
function fetchObject() {
return $this->db->fetchObject( $this->result );
}
/**
* @todo document
*/
function fetchRow() {
return $this->db->fetchRow( $this->result );
}
/**
* @todo document
*/
function free() {
$this->db->freeResult( $this->result );
unset( $this->result );
unset( $this->db );
}
function seek( $row ) {
$this->db->dataSeek( $this->result, $row );
}
}
endif;
?>
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?