📄 mysql.php
字号:
'major' => isset($tmp[0]) ? $tmp[0] : null,
'minor' => isset($tmp[1]) ? $tmp[1] : null,
'patch' => $tmp2[0],
'extra' => $tmp2[1],
'native' => $server_info,
);
}
return $server_info;
}
// }}}
// {{{ _getServerCapabilities()
/**
* Fetch some information about the server capabilities
* (transactions, subselects, prepared statements, etc).
*
* @access private
*/
function _getServerCapabilities()
{
if (!$this->server_capabilities_checked) {
$this->server_capabilities_checked = true;
//set defaults
$this->supported['sub_selects'] = 'emulated';
$this->supported['prepared_statements'] = 'emulated';
$this->start_transaction = false;
$this->varchar_max_length = 255;
$server_info = $this->getServerVersion();
if (is_array($server_info)) {
if (!version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '4.1.0', '<')) {
$this->supported['sub_selects'] = true;
$this->supported['prepared_statements'] = true;
}
if (!version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '4.0.14', '<')
|| !version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '4.1.1', '<')
) {
$this->supported['savepoints'] = true;
}
if (!version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '4.0.11', '<')) {
$this->start_transaction = true;
}
if (!version_compare($server_info['major'].'.'.$server_info['minor'].'.'.$server_info['patch'], '5.0.3', '<')) {
$this->varchar_max_length = 65532;
}
}
}
}
// }}}
// {{{ function _skipUserDefinedVariable($query, $position)
/**
* Utility method, used by prepare() to avoid misinterpreting MySQL user
* defined variables (SELECT @x:=5) for placeholders.
* Check if the placeholder is a false positive, i.e. if it is an user defined
* variable instead. If so, skip it and advance the position, otherwise
* return the current position, which is valid
*
* @param string $query
* @param integer $position current string cursor position
* @return integer $new_position
* @access protected
*/
function _skipUserDefinedVariable($query, $position)
{
$found = strpos(strrev(substr($query, 0, $position)), '@');
if ($found === false) {
return $position;
}
$pos = strlen($query) - strlen(substr($query, $position)) - $found - 1;
$substring = substr($query, $pos, $position - $pos + 2);
if (preg_match('/^@\w+\s*:=$/', $substring)) {
return $position + 1; //found an user defined variable: skip it
}
return $position;
}
// }}}
// {{{ prepare()
/**
* Prepares a query for multiple execution with execute().
* With some database backends, this is emulated.
* prepare() requires a generic query as string like
* 'INSERT INTO numbers VALUES(?,?)' or
* 'INSERT INTO numbers VALUES(:foo,:bar)'.
* The ? and :name and are placeholders which can be set using
* bindParam() and the query can be sent off using the execute() method.
* The allowed format for :name can be set with the 'bindname_format' option.
*
* @param string $query the query to prepare
* @param mixed $types array that contains the types of the placeholders
* @param mixed $result_types array that contains the types of the columns in
* the result set or MDB2_PREPARE_RESULT, if set to
* MDB2_PREPARE_MANIP the query is handled as a manipulation query
* @param mixed $lobs key (field) value (parameter) pair for all lob placeholders
* @return mixed resource handle for the prepared query on success, a MDB2
* error on failure
* @access public
* @see bindParam, execute
*/
function &prepare($query, $types = null, $result_types = null, $lobs = array())
{
if ($this->options['emulate_prepared']
|| $this->supported['prepared_statements'] !== true
) {
$obj =& parent::prepare($query, $types, $result_types, $lobs);
return $obj;
}
$is_manip = ($result_types === MDB2_PREPARE_MANIP);
$offset = $this->offset;
$limit = $this->limit;
$this->offset = $this->limit = 0;
$query = $this->_modifyQuery($query, $is_manip, $limit, $offset);
$result = $this->debug($query, __FUNCTION__, array('is_manip' => $is_manip, 'when' => 'pre'));
if ($result) {
if (PEAR::isError($result)) {
return $result;
}
$query = $result;
}
$placeholder_type_guess = $placeholder_type = null;
$question = '?';
$colon = ':';
$positions = array();
$position = 0;
while ($position < strlen($query)) {
$q_position = strpos($query, $question, $position);
$c_position = strpos($query, $colon, $position);
if ($q_position && $c_position) {
$p_position = min($q_position, $c_position);
} elseif ($q_position) {
$p_position = $q_position;
} elseif ($c_position) {
$p_position = $c_position;
} else {
break;
}
if (is_null($placeholder_type)) {
$placeholder_type_guess = $query[$p_position];
}
$new_pos = $this->_skipDelimitedStrings($query, $position, $p_position);
if (PEAR::isError($new_pos)) {
return $new_pos;
}
if ($new_pos != $position) {
$position = $new_pos;
continue; //evaluate again starting from the new position
}
//make sure this is not part of an user defined variable
$new_pos = $this->_skipUserDefinedVariable($query, $position);
if ($new_pos != $position) {
$position = $new_pos;
continue; //evaluate again starting from the new position
}
if ($query[$position] == $placeholder_type_guess) {
if (is_null($placeholder_type)) {
$placeholder_type = $query[$p_position];
$question = $colon = $placeholder_type;
}
if ($placeholder_type == ':') {
$regexp = '/^.{'.($position+1).'}('.$this->options['bindname_format'].').*$/s';
$parameter = preg_replace($regexp, '\\1', $query);
if ($parameter === '') {
$err =& $this->raiseError(MDB2_ERROR_SYNTAX, null, null,
'named parameter name must match "bindname_format" option', __FUNCTION__);
return $err;
}
$positions[$p_position] = $parameter;
$query = substr_replace($query, '?', $position, strlen($parameter)+1);
} else {
$positions[$p_position] = count($positions);
}
$position = $p_position + 1;
} else {
$position = $p_position;
}
}
$connection = $this->getConnection();
if (PEAR::isError($connection)) {
return $connection;
}
static $prep_statement_counter = 1;
$statement_name = sprintf($this->options['statement_format'], $this->phptype, sha1(microtime() + mt_rand())) . $prep_statement_counter++;
$query = "PREPARE $statement_name FROM ".$this->quote($query, 'text');
$statement =& $this->_doQuery($query, true, $connection);
if (PEAR::isError($statement)) {
return $statement;
}
$class_name = 'MDB2_Statement_'.$this->phptype;
$obj = new $class_name($this, $statement_name, $positions, $query, $types, $result_types, $is_manip, $limit, $offset);
$this->debug($query, __FUNCTION__, array('is_manip' => $is_manip, 'when' => 'post', 'result' => $obj));
return $obj;
}
// }}}
// {{{ replace()
/**
* Execute a SQL REPLACE query. A REPLACE query is identical to a INSERT
* query, except that if there is already a row in the table with the same
* key field values, the REPLACE query just updates its values instead of
* inserting a new row.
*
* The REPLACE type of query does not make part of the SQL standards. Since
* practically only MySQL implements it natively, this type of query is
* emulated through this method for other DBMS using standard types of
* queries inside a transaction to assure the atomicity of the operation.
*
* @access public
*
* @param string $table name of the table on which the REPLACE query will
* be executed.
* @param array $fields associative array that describes the fields and the
* values that will be inserted or updated in the specified table. The
* indexes of the array are the names of all the fields of the table. The
* values of the array are also associative arrays that describe the
* values and other properties of the table fields.
*
* Here follows a list of field properties that need to be specified:
*
* value:
* Value to be assigned to the specified field. This value may be
* of specified in database independent type format as this
* function can perform the necessary datatype conversions.
*
* Default:
* this property is required unless the Null property
* is set to 1.
*
* type
* Name of the type of the field. Currently, all types Metabase
* are supported except for clob and blob.
*
* Default: no type conversion
*
* null
* Boolean property that indicates that the value for this field
* should be set to null.
*
* The default value for fields missing in INSERT queries may be
* specified the definition of a table. Often, the default value
* is already null, but since the REPLACE may be emulated using
* an UPDATE query, make sure that all fields of the table are
* listed in this function argument array.
*
* Default: 0
*
* key
* Boolean property that indicates that this field should be
* handled as a primary key or at least as part of the compound
* unique index of the table that will determine the row that will
* updated if it exists or inserted a new row otherwise.
*
* This function will fail if no key field is specified or if the
* value of a key field is set to null because fields that are
* part of unique index they may not be null.
*
* Default: 0
*
* @return mixed MDB2_OK on success, a MDB2 error on failure
*/
function replace($table, $fields)
{
$count = count($fields);
$query = $values = '';
$keys = $colnum = 0;
for (reset($fields); $colnum < $count; next($fields), $colnum++) {
$name = key($fields);
if ($colnum > 0) {
$query .= ',';
$values.= ',';
}
$query.= $name;
if (isset($fields[$name]['null']) && $fields[$name]['null']) {
$value = 'NULL';
} else {
$type = isset($fields[$name]['type']) ? $fields[$name]['type'] : null;
$value = $this->quote($fields[$name]['value'], $type);
if (PEAR::isError($value)) {
return $value;
}
}
$values.= $value;
if (isset($fields[$name]['key']) && $fields[$name]['key']) {
if ($value === 'NULL') {
return $this->raiseError(MDB2_ERROR_CANNOT_REPLACE, null, null,
'key value '.$name.' may not be NULL', __FUNCTION__);
}
$keys++;
}
}
if ($keys == 0) {
return $this->raiseError(MDB2_ERROR_CANNOT_REPLACE, null, null,
'not specified which fields are keys', __FUNCTION__);
}
$connection = $this->getConnection();
if (PEAR::isError($connection)) {
return $connection;
}
$query = "REPLACE INTO $table ($query) VALUES ($values)";
$result =& $this->_doQuery($query, true, $connection);
if (PEAR::isError($result)) {
return $result;
}
return $this->_affectedRows($connection, $result);
}
// }}}
// {{{ nextID()
/**
* Returns the next free id of a sequence
*
* @param string $seq_name name of the sequence
* @param boolean $ondemand when true the sequence is
* automatic created, if it
* not exists
*
* @return mixed MDB2 Error Object or id
* @access public
*/
function nextID($seq_name, $ondemand = true)
{
$sequence_name = $this->quoteIdentifier($this->getSequenceName($seq_name), true);
$seqcol_name = $this->quoteIdentifier($this->options['seqcol_name'], true);
$query = "INSERT INTO $sequence_name ($seqcol_name) VALUES (NULL)";
$this->expectError(MDB2_ERROR_NOSUCHTABLE);
$result =& $this->_doQuery($query, true);
$this->popExpect();
if (PEAR::isError($result)) {
if ($ondemand && $result->getCode() == MDB2_ERROR_NOSUCHTABLE) {
$this->loadModule('Manager', null, true);
$result = $this->manager->createSequence($seq_name);
if (PEAR::isError($result)) {
return $this->raiseError($result, null, null,
'on demand sequence '.$seq_name.' could not be created', __FUNCTION__);
} else {
return $this->nextID($seq_name, false);
}
}
return $result;
}
$value = $this->lastInsertID();
if (is_numeric($value)) {
$query = "DELETE FROM $sequence_name WHERE $seqcol_name < $value";
$result =& $this->_doQuery($query, true);
if (PEAR::isError($result)) {
$this->warnings[] = 'nextID: could not delete previous sequence table values from '.$seq_name;
}
}
return $value;
}
// }}}
// {{{ lastInsertID()
/**
* Returns the autoincrement ID if supported or $id or fetches the current
* ID in a sequence called: $table.(empty($field) ? '' : '_'.$field)
*
* @param string $table name of the table into which a new row was inserted
* @param string $field name of the field into which a new row was inserted
* @return mixed MDB2 Error Object or id
* @access public
*/
function lastInsertID($table = null, $field = null)
{
// not using mysql_insert_id() due to http://pear.php.net/bugs/bug.php?id=8051
return $this->queryOne('SELECT LAST_INSERT_ID()', 'integer');
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -