databaseb1.php

来自「php 开发的内容管理系统」· PHP 代码 · 共 2,038 行 · 第 1/4 页

PHP
2,038
字号
		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 );
	}

}

?>

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?