📄 mysql.php
字号:
if ($this->_changed_db) {
if (!@mysql_select_db($this->_changed_db, $this->connection)) {
return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED);
}
}
$result = @mysql_query('COMMIT', $this->connection);
$result = @mysql_query('SET AUTOCOMMIT=1', $this->connection);
$this->transaction_opcount = 0;
if (!$result) {
return $this->mysqlRaiseError();
}
}
return DB_OK;
}
// }}}
// {{{ rollback()
/**
* Roll back (undo) the current transaction.
*/
function rollback()
{
if ($this->transaction_opcount > 0) {
if ($this->_changed_db) {
if (!@mysql_select_db($this->_changed_db, $this->connection)) {
return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED);
}
}
$result = @mysql_query('ROLLBACK', $this->connection);
$result = @mysql_query('SET AUTOCOMMIT=1', $this->connection);
$this->transaction_opcount = 0;
if (!$result) {
return $this->mysqlRaiseError();
}
}
return DB_OK;
}
// }}}
// {{{ affectedRows()
/**
* Gets the number of rows affected by the data manipulation
* query. For other queries, this function returns 0.
*
* @return number of rows affected by the last query
*/
function affectedRows()
{
if (DB::isManip($this->last_query)) {
$result = @mysql_affected_rows($this->connection);
} else {
$result = 0;
}
return $result;
}
// }}}
// {{{ errorNative()
/**
* Get the native error code of the last error (if any) that
* occured on the current connection.
*
* @access public
*
* @return int native MySQL error code
*/
function errorNative()
{
return mysql_errno($this->connection);
}
// }}}
// {{{ nextId()
/**
* Get the next value in a sequence. We emulate sequences
* for MySQL. Will create the sequence if it does not exist.
*
* @access public
*
* @param $seq_name the name of the sequence
*
* @param $ondemand whether to create the sequence table on demand
* (default is true)
*
* @return a sequence integer, or a DB error
*/
function nextId($seq_name, $ondemand = true)
{
$sqn = preg_replace('/[^a-z0-9_]/i', '_', $seq_name);
$repeat = 0;
do {
// XXX HACK: temporarily force error mode to "return"
$tmp = $this->_default_error_mode;
$this->_default_error_mode = PEAR_ERROR_RETURN;
$result = $this->query("UPDATE ${sqn}_seq ".
'SET id=LAST_INSERT_ID(id+1)');
$this->_default_error_mode = $tmp;
if ($ondemand && DB::isError($result) &&
$result->getCode() == DB_ERROR_NOSUCHTABLE) {
$repeat = 1;
$result = $this->createSequence($seq_name);
// Since createSequence initializes the ID to be 1,
// we do not need to retrieve the ID again (or we will get 2)
if (DB::isError($result)) {
return $result;
} else {
// First ID of a newly created sequence is 1
return 1;
}
} elseif (DB::isError($result) &&
$result->getCode() == DB_ERROR_ALREADY_EXISTS) {
// Must be using old sequence emulation implementation,
// we need to clean up the dupes.
// Obtain a user-level lock... this will release any previous
// application locks, but unlike LOCK TABLES, it does not abort
// the current transaction and is much less frequently used.
$result = $this->getOne("SELECT GET_LOCK('${sqn}_seq_lock',10)");
if (DB::isError($result)) {
return $result;
}
if ($result == 0) {
// Failed to get the lock, can't do the conversion, bail
// with a DB_ERROR_NOT_LOCKED error
return $this->mysqlRaiseError(1100);
}
$highest_id = $this->getOne("SELECT MAX(id) FROM ${sqn}_seq");
if (DB::isError($highest_id)) {
return $highest_id;
}
// We should probably do something if $highest_id isn't
// numeric, but I'm at a loss as how to handle that...
$result = $this->query("DELETE FROM ${sqn}_seq ".
"WHERE id <> $highest_id");
if (DB::isError($result)) {
return $result;
}
// If another thread has been waiting for this lock,
// it will go thru the above procedure, but will have no
// real effect
$result = $this->getOne("SELECT RELEASE_LOCK('${sqn}_seq_lock')");
if (DB::isError($result)) {
return $result;
}
// This should kill all rows except the highest, now we
// can try again
$repeat = 1;
} else {
$repeat = 0;
}
} while ($repeat);
if (DB::isError($result)) {
return $result;
}
return mysql_insert_id($this->connection);
}
// }}}
// {{{ createSequence()
function createSequence($seq_name)
{
$sqn = preg_replace('/[^a-z0-9_]/i', '_', $seq_name);
$res = $this->query("CREATE TABLE ${sqn}_seq ".
'(id INTEGER UNSIGNED AUTO_INCREMENT NOT NULL,'.
' PRIMARY KEY(id))');
if (DB::isError($res)) {
return $res;
}
// insert yields value 1, nextId call will generate ID 2
return $this->query("INSERT INTO ${sqn}_seq VALUES(0)");
}
// }}}
// {{{ dropSequence()
function dropSequence($seq_name)
{
$sqn = preg_replace('/[^a-z0-9_]/i', '_', $seq_name);
return $this->query("DROP TABLE ${sqn}_seq");
}
// }}}
// {{{ quote()
/**
* Quote the given string so it can be safely used within string delimiters
* in a query.
* @param $string mixed Data to be quoted
* @return mixed "NULL" string, quoted string or original data
*/
function quote($str = null)
{
switch (strtolower(gettype($str))) {
case 'null':
return 'NULL';
case 'integer':
return $str;
case 'string':
default:
return "'".mysql_escape_string($str)."'";
}
}
// }}}
// {{{ modifyQuery()
function modifyQuery($query, $subject = null)
{
if ($this->options['optimize'] == 'portability') {
// "DELETE FROM table" gives 0 affected rows in MySQL.
// This little hack lets you know how many rows were deleted.
if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $query)) {
$query = preg_replace('/^\s*DELETE\s+FROM\s+(\S+)\s*$/',
'DELETE FROM \1 WHERE 1=1', $query);
}
}
return $query;
}
// }}}
// {{{ modifyLimitQuery()
function modifyLimitQuery($query, $from, $count)
{
$query = $query . " LIMIT $from, $count";
return $query;
}
// }}}
// {{{ mysqlRaiseError()
function mysqlRaiseError($errno = null)
{
if ($errno === null) {
$errno = $this->errorCode(mysql_errno($this->connection));
}
return $this->raiseError($errno, null, null, null,
@mysql_error($this->connection));
}
// }}}
// {{{ tableInfo()
function tableInfo($result, $mode = null) {
$count = 0;
$id = 0;
$res = array();
/*
* depending on $mode, metadata returns the following values:
*
* - mode is false (default):
* $result[]:
* [0]["table"] table name
* [0]["name"] field name
* [0]["type"] field type
* [0]["len"] field length
* [0]["flags"] field flags
*
* - mode is DB_TABLEINFO_ORDER
* $result[]:
* ["num_fields"] number of metadata records
* [0]["table"] table name
* [0]["name"] field name
* [0]["type"] field type
* [0]["len"] field length
* [0]["flags"] field flags
* ["order"][field name] index of field named "field name"
* The last one is used, if you have a field name, but no index.
* Test: if (isset($result['meta']['myfield'])) { ...
*
* - mode is DB_TABLEINFO_ORDERTABLE
* the same as above. but additionally
* ["ordertable"][table name][field name] index of field
* named "field name"
*
* this is, because if you have fields from different
* tables with the same field name * they override each
* other with DB_TABLEINFO_ORDER
*
* you can combine DB_TABLEINFO_ORDER and
* DB_TABLEINFO_ORDERTABLE with DB_TABLEINFO_ORDER |
* DB_TABLEINFO_ORDERTABLE * or with DB_TABLEINFO_FULL
*/
// if $result is a string, then we want information about a
// table without a resultset
if (is_string($result)) {
$id = @mysql_list_fields($this->dsn['database'],
$result, $this->connection);
if (empty($id)) {
return $this->mysqlRaiseError();
}
} else { // else we want information about a resultset
$id = $result;
if (empty($id)) {
return $this->mysqlRaiseError();
}
}
$count = @mysql_num_fields($id);
// made this IF due to performance (one if is faster than $count if's)
if (empty($mode)) {
for ($i=0; $i<$count; $i++) {
$res[$i]['table'] = @mysql_field_table ($id, $i);
$res[$i]['name'] = @mysql_field_name ($id, $i);
$res[$i]['type'] = @mysql_field_type ($id, $i);
$res[$i]['len'] = @mysql_field_len ($id, $i);
$res[$i]['flags'] = @mysql_field_flags ($id, $i);
}
} else { // full
$res['num_fields']= $count;
for ($i=0; $i<$count; $i++) {
$res[$i]['table'] = @mysql_field_table ($id, $i);
$res[$i]['name'] = @mysql_field_name ($id, $i);
$res[$i]['type'] = @mysql_field_type ($id, $i);
$res[$i]['len'] = @mysql_field_len ($id, $i);
$res[$i]['flags'] = @mysql_field_flags ($id, $i);
if ($mode & DB_TABLEINFO_ORDER) {
$res['order'][$res[$i]['name']] = $i;
}
if ($mode & DB_TABLEINFO_ORDERTABLE) {
$res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
}
}
}
// free the result only if we were called on a table
if (is_string($result)) {
@mysql_free_result($id);
}
return $res;
}
// }}}
// {{{ getTablesQuery()
/**
* Returns the query needed to get some backend info
* @param string $type What kind of info you want to retrieve
* @return string The SQL query string
*/
function getSpecialQuery($type)
{
switch ($type) {
case 'tables':
$sql = "SHOW TABLES";
break;
case 'views':
return DB_ERROR_NOT_CAPABLE;
case 'users':
$sql = "select distinct User from user";
if($this->dsn['database'] != 'mysql') {
$dsn = $this->dsn;
$dsn['database'] = 'mysql';
if (DB::isError($db = DB::connect($dsn))) {
return $db;
}
$sql = $db->getCol($sql);
$db->disconnect();
// XXX Fixme the mysql driver should take care of this
if (!@mysql_select_db($this->dsn['database'], $this->connection)) {
return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED);
}
}
return $sql;
break;
case 'databases':
$sql = "SHOW DATABASES";
break;
default:
return null;
}
return $sql;
}
// }}}
// TODO/wishlist:
// longReadlen
// binmode
}
?>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -