mirror of
https://github.com/yiisoft/yii2.git
synced 2025-08-26 14:26:54 +08:00
WIP
This commit is contained in:
@ -68,10 +68,14 @@ class Command extends \yii\base\Component
|
||||
public $fetchMode = \PDO::FETCH_ASSOC;
|
||||
/**
|
||||
* @var array the parameters (name => value) that are bound to the current PDO statement.
|
||||
* This property is maintained by methods such as [[bindValue()]].
|
||||
* Do not modify it directly.
|
||||
* This property is maintained by methods such as [[bindValue()]]. It is mainly provided for logging purpose
|
||||
* and is used to generated [[rawSql]]. Do not modify it directly.
|
||||
*/
|
||||
public $params = [];
|
||||
/**
|
||||
* @var array pending parameters to be bound to the current PDO statement.
|
||||
*/
|
||||
private $_pendingParams = [];
|
||||
/**
|
||||
* @var string the SQL statement that this command represents
|
||||
*/
|
||||
@ -97,6 +101,7 @@ class Command extends \yii\base\Component
|
||||
if ($sql !== $this->_sql) {
|
||||
$this->cancel();
|
||||
$this->_sql = $this->db->quoteSql($sql);
|
||||
$this->_pendingParams = [];
|
||||
$this->params = [];
|
||||
}
|
||||
|
||||
@ -143,21 +148,32 @@ class Command extends \yii\base\Component
|
||||
* this may improve performance.
|
||||
* For SQL statement with binding parameters, this method is invoked
|
||||
* automatically.
|
||||
* @param boolean $forRead whether this method is called for a read query. If null, it means
|
||||
* the SQL statement should be used to determine whether it is for read or write.
|
||||
* @throws Exception if there is any DB error
|
||||
*/
|
||||
public function prepare()
|
||||
public function prepare($forRead = null)
|
||||
{
|
||||
if ($this->pdoStatement == null) {
|
||||
if ($this->pdoStatement) {
|
||||
return;
|
||||
}
|
||||
|
||||
$sql = $this->getSql();
|
||||
|
||||
if ($forRead || $forRead === null && $this->db->getSchema()->isReadQuery($sql)) {
|
||||
$pdo = $this->db->getReadPdo();
|
||||
} else {
|
||||
$pdo = $this->db->getWritePdo();
|
||||
}
|
||||
|
||||
try {
|
||||
$this->pdoStatement = $this->db->pdo->prepare($sql);
|
||||
$this->pdoStatement = $pdo->prepare($sql);
|
||||
} catch (\Exception $e) {
|
||||
$message = $e->getMessage() . "\nFailed to prepare SQL: $sql";
|
||||
$errorInfo = $e instanceof \PDOException ? $e->errorInfo : null;
|
||||
throw new Exception($message, $errorInfo, (int) $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels the execution of the SQL statement.
|
||||
@ -184,6 +200,9 @@ class Command extends \yii\base\Component
|
||||
public function bindParam($name, &$value, $dataType = null, $length = null, $driverOptions = null)
|
||||
{
|
||||
$this->prepare();
|
||||
|
||||
$this->bindPendingParams();
|
||||
|
||||
if ($dataType === null) {
|
||||
$dataType = $this->db->getSchema()->getPdoType($value);
|
||||
}
|
||||
@ -199,6 +218,18 @@ class Command extends \yii\base\Component
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds pending parameters that were registered via [[bindValue()]] and [[bindValues()]].
|
||||
* Note that this method requires an active [[pdoStatement]].
|
||||
*/
|
||||
protected function bindPendingParams()
|
||||
{
|
||||
foreach ($this->_pendingParams as $name => $value) {
|
||||
$this->pdoStatement->bindValue($name, $value[0], $value[1]);
|
||||
}
|
||||
$this->_pendingParams = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds a value to a parameter.
|
||||
* @param string|integer $name Parameter identifier. For a prepared statement
|
||||
@ -212,11 +243,10 @@ class Command extends \yii\base\Component
|
||||
*/
|
||||
public function bindValue($name, $value, $dataType = null)
|
||||
{
|
||||
$this->prepare();
|
||||
if ($dataType === null) {
|
||||
$dataType = $this->db->getSchema()->getPdoType($value);
|
||||
}
|
||||
$this->pdoStatement->bindValue($name, $value, $dataType);
|
||||
$this->_pendingParams[$name] = [$value, $dataType];
|
||||
$this->params[$name] = $value;
|
||||
|
||||
return $this;
|
||||
@ -235,19 +265,19 @@ class Command extends \yii\base\Component
|
||||
*/
|
||||
public function bindValues($values)
|
||||
{
|
||||
if (!empty($values)) {
|
||||
$this->prepare();
|
||||
if (empty($values)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
foreach ($values as $name => $value) {
|
||||
if (is_array($value)) {
|
||||
$type = $value[1];
|
||||
$value = $value[0];
|
||||
$this->_pendingParams[$name] = $value;
|
||||
} else {
|
||||
$type = $this->db->getSchema()->getPdoType($value);
|
||||
$this->_pendingParams[$name] = [$value, $type];
|
||||
}
|
||||
$this->pdoStatement->bindValue($name, $value, $type);
|
||||
$this->params[$name] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
@ -271,11 +301,13 @@ class Command extends \yii\base\Component
|
||||
return 0;
|
||||
}
|
||||
|
||||
$this->prepare(false);
|
||||
$this->bindPendingParams();
|
||||
|
||||
$token = $rawSql;
|
||||
try {
|
||||
Yii::beginProfile($token, __METHOD__);
|
||||
|
||||
$this->prepare();
|
||||
$this->pdoStatement->execute();
|
||||
$n = $this->pdoStatement->rowCount();
|
||||
|
||||
@ -390,11 +422,13 @@ class Command extends \yii\base\Component
|
||||
}
|
||||
}
|
||||
|
||||
$this->prepare(true);
|
||||
$this->bindPendingParams();
|
||||
|
||||
$token = $rawSql;
|
||||
try {
|
||||
Yii::beginProfile($token, 'yii\db\Command::query');
|
||||
|
||||
$this->prepare();
|
||||
$this->pdoStatement->execute();
|
||||
|
||||
if ($method === '') {
|
||||
|
@ -456,7 +456,6 @@ class Connection extends Component
|
||||
*/
|
||||
public function createCommand($sql = null, $params = [])
|
||||
{
|
||||
$this->open();
|
||||
$command = new Command([
|
||||
'db' => $this,
|
||||
'sql' => $sql,
|
||||
@ -660,6 +659,29 @@ class Connection extends Component
|
||||
$this->_driverName = strtolower($driverName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the PDO instance for read queries.
|
||||
* When [[enableSlave]] is true, one of the slaves will be used for read queries, and its PDO instance
|
||||
* will be returned by this method. If no slave is available, the [[writePdo]] will be returned.
|
||||
* @return PDO the PDO instance for read queries.
|
||||
*/
|
||||
public function getReadPdo()
|
||||
{
|
||||
$db = $this->getSlave();
|
||||
return $db ? $db->pdo : $this->getWritePdo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the PDO instance for write queries.
|
||||
* This method will open the master DB connection and then return [[pdo]].
|
||||
* @return PDO the PDO instance for write queries.
|
||||
*/
|
||||
public function getWritePdo()
|
||||
{
|
||||
$this->open();
|
||||
return $this->pdo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently active slave.
|
||||
* If this method is called the first time, it will try to open a slave connection when [[enableSlave]] is true.
|
||||
@ -710,9 +732,11 @@ class Connection extends Component
|
||||
}
|
||||
/* @var $slave Connection */
|
||||
$slave = Yii::createObject($config);
|
||||
|
||||
if (!isset($slave->attributes[PDO::ATTR_TIMEOUT])) {
|
||||
$slave->attributes[PDO::ATTR_TIMEOUT] = $this->slaveTimeout;
|
||||
}
|
||||
|
||||
try {
|
||||
$slave->open();
|
||||
return $slave;
|
||||
|
@ -369,11 +369,12 @@ abstract class Schema extends Object
|
||||
return $str;
|
||||
}
|
||||
|
||||
$this->db->open();
|
||||
if (($value = $this->db->pdo->quote($str)) !== false) {
|
||||
return $value;
|
||||
} else { // the driver doesn't support quote (e.g. oci)
|
||||
$pdo = $this->db->getReadPdo();
|
||||
|
||||
if (($value = $pdo->quote($str)) !== false) {
|
||||
return $value;
|
||||
} else {
|
||||
// the driver doesn't support quote (e.g. oci)
|
||||
return "'" . addcslashes(str_replace("'", "''", $str), "\000\n\r\\\032") . "'";
|
||||
}
|
||||
}
|
||||
@ -520,4 +521,10 @@ abstract class Schema extends Object
|
||||
throw new $exceptionClass($message, $errorInfo, (int) $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
public function isReadQuery($sql)
|
||||
{
|
||||
$pattern = '/^\s*(SELECT|SHOW|DESCRIBE)\b/i';
|
||||
return preg_match($pattern, $sql);
|
||||
}
|
||||
}
|
||||
|
@ -116,13 +116,14 @@ class Schema extends \yii\db\Schema
|
||||
return $str;
|
||||
}
|
||||
|
||||
$this->db->open();
|
||||
$pdo = $this->db->getReadPdo();
|
||||
|
||||
// workaround for broken PDO::quote() implementation in CUBRID 9.1.0 http://jira.cubrid.org/browse/APIS-658
|
||||
$version = $this->db->pdo->getAttribute(\PDO::ATTR_CLIENT_VERSION);
|
||||
$version = $pdo->getAttribute(\PDO::ATTR_CLIENT_VERSION);
|
||||
if (version_compare($version, '8.4.4.0002', '<') || $version[0] == '9' && version_compare($version, '9.2.0.0002', '<=')) {
|
||||
return "'" . addcslashes(str_replace("'", "''", $str), "\000\n\r\\\032") . "'";
|
||||
} else {
|
||||
return $this->db->pdo->quote($str);
|
||||
return $pdo->quote($str);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user