Commit 9b62fb67 by Qiang Xue

DB cleanup.

parent 1cbfcb19
<?php
/**
* BadCallException class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\base;
/**
* BadCallException represents an exception caused by calling a method in a wrong way.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class BadCallException extends \Exception
{
}
...@@ -45,7 +45,7 @@ use yii\util\StringHelper; ...@@ -45,7 +45,7 @@ use yii\util\StringHelper;
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */
abstract class ActiveRecord extends Model class ActiveRecord extends Model
{ {
/** /**
* @var array attribute values indexed by attribute names * @var array attribute values indexed by attribute names
......
...@@ -21,7 +21,7 @@ namespace yii\db; ...@@ -21,7 +21,7 @@ namespace yii\db;
* For example, * For example,
* *
* ~~~ * ~~~
* $users = \Yii::$application->db->createCommand('SELECT * FROM tbl_user')->queryAll(); * $users = $connection->createCommand('SELECT * FROM tbl_user')->queryAll();
* ~~~ * ~~~
* *
* Command supports SQL statement preparation and parameter binding. * Command supports SQL statement preparation and parameter binding.
...@@ -30,6 +30,18 @@ namespace yii\db; ...@@ -30,6 +30,18 @@ namespace yii\db;
* When binding a parameter, the SQL statement is automatically prepared. * When binding a parameter, the SQL statement is automatically prepared.
* You may also call [[prepare()]] explicitly to prepare a SQL statement. * You may also call [[prepare()]] explicitly to prepare a SQL statement.
* *
* Command also supports building SQL statements by providing methods such as [[insert()]],
* [[update()]], etc. For example,
*
* ~~~
* $connection->createCommand()->insert('tbl_user', array(
* 'name' => 'Sam',
* 'age' => 30,
* ))->execute();
* ~~~
*
* To build SELECT SQL statements, please use [[QueryBuilder]] instead.
*
* @property string $sql the SQL statement to be executed * @property string $sql the SQL statement to be executed
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
...@@ -42,7 +54,7 @@ class Command extends \yii\base\Component ...@@ -42,7 +54,7 @@ class Command extends \yii\base\Component
*/ */
public $connection; public $connection;
/** /**
* @var \PDOStatement the PDOStatement object that this command contains * @var \PDOStatement the PDOStatement object that this command is associated with
*/ */
public $pdoStatement; public $pdoStatement;
/** /**
...@@ -78,23 +90,33 @@ class Command extends \yii\base\Component ...@@ -78,23 +90,33 @@ class Command extends \yii\base\Component
{ {
if ($sql !== $this->_sql) { if ($sql !== $this->_sql) {
if ($this->connection->enableAutoQuoting && $sql != '') { if ($this->connection->enableAutoQuoting && $sql != '') {
$sql = preg_replace_callback('/(\\{\\{(.*?)\\}\\}|\\[\\[(.*?)\\]\\])/', function($matches) { $sql = $this->expandSql($sql);
if (isset($matches[3])) {
return $this->connection->quoteColumnName($matches[3]);
} else {
$name = str_replace('%', $this->connection->tablePrefix, $matches[2]);
return $this->connection->quoteTableName($name);
}
}, $sql);
} }
$this->cancel();
$this->_sql = $sql; $this->_sql = $sql;
$this->_params = array(); $this->_params = array();
$this->cancel();
} }
return $this; return $this;
} }
/** /**
* Expands a SQL statement by quoting table and column names and replacing table prefixes.
* @param string $sql the SQL to be expanded
* @return string the expanded SQL
*/
protected function expandSql($sql)
{
return preg_replace_callback('/(\\{\\{(.*?)\\}\\}|\\[\\[(.*?)\\]\\])/', function($matches) {
if (isset($matches[3])) {
return $this->connection->quoteColumnName($matches[3]);
} else {
$name = str_replace('%', $this->connection->tablePrefix, $matches[2]);
return $this->connection->quoteTableName($name);
}
}, $sql);
}
/**
* Prepares the SQL statement to be executed. * Prepares the SQL statement to be executed.
* For complex SQL statement that is to be executed multiple times, * For complex SQL statement that is to be executed multiple times,
* this may improve performance. * this may improve performance.
...@@ -142,7 +164,7 @@ class Command extends \yii\base\Component ...@@ -142,7 +164,7 @@ class Command extends \yii\base\Component
{ {
$this->prepare(); $this->prepare();
if ($dataType === null) { if ($dataType === null) {
$this->pdoStatement->bindParam($name, $value, $this->getPdoType(gettype($value))); $this->pdoStatement->bindParam($name, $value, $this->getPdoType($value));
} elseif ($length === null) { } elseif ($length === null) {
$this->pdoStatement->bindParam($name, $value, $dataType); $this->pdoStatement->bindParam($name, $value, $dataType);
} elseif ($driverOptions === null) { } elseif ($driverOptions === null) {
...@@ -169,7 +191,7 @@ class Command extends \yii\base\Component ...@@ -169,7 +191,7 @@ class Command extends \yii\base\Component
{ {
$this->prepare(); $this->prepare();
if ($dataType === null) { if ($dataType === null) {
$this->pdoStatement->bindValue($name, $value, $this->getPdoType(gettype($value))); $this->pdoStatement->bindValue($name, $value, $this->getPdoType($value));
} else { } else {
$this->pdoStatement->bindValue($name, $value, $dataType); $this->pdoStatement->bindValue($name, $value, $dataType);
} }
...@@ -197,7 +219,7 @@ class Command extends \yii\base\Component ...@@ -197,7 +219,7 @@ class Command extends \yii\base\Component
$type = $value[1]; $type = $value[1];
$value = $value[0]; $value = $value[0];
} else { } else {
$type = $this->getPdoType(gettype($value)); $type = $this->getPdoType($value);
} }
$this->pdoStatement->bindValue($name, $value, $type); $this->pdoStatement->bindValue($name, $value, $type);
$this->_params[$name] = $value; $this->_params[$name] = $value;
...@@ -207,12 +229,12 @@ class Command extends \yii\base\Component ...@@ -207,12 +229,12 @@ class Command extends \yii\base\Component
} }
/** /**
* Determines the PDO type for the give PHP data type. * Determines the PDO type for the give PHP data value.
* @param string $type The PHP type (obtained by `gettype()` call). * @param mixed $data the data whose PDO type is to be determined
* @return integer the corresponding PDO type * @return integer the PDO type
* @see http://www.php.net/manual/en/pdo.constants.php * @see http://www.php.net/manual/en/pdo.constants.php
*/ */
private function getPdoType($type) private function getPdoType($data)
{ {
static $typeMap = array( static $typeMap = array(
'boolean' => \PDO::PARAM_BOOL, 'boolean' => \PDO::PARAM_BOOL,
...@@ -220,6 +242,7 @@ class Command extends \yii\base\Component ...@@ -220,6 +242,7 @@ class Command extends \yii\base\Component
'string' => \PDO::PARAM_STR, 'string' => \PDO::PARAM_STR,
'NULL' => \PDO::PARAM_NULL, 'NULL' => \PDO::PARAM_NULL,
); );
$type = gettype($data);
return isset($typeMap[$type]) ? $typeMap[$type] : \PDO::PARAM_STR; return isset($typeMap[$type]) ? $typeMap[$type] : \PDO::PARAM_STR;
} }
...@@ -267,7 +290,9 @@ class Command extends \yii\base\Component ...@@ -267,7 +290,9 @@ class Command extends \yii\base\Component
\Yii::endProfile(__METHOD__ . "($sql)", __CLASS__); \Yii::endProfile(__METHOD__ . "($sql)", __CLASS__);
} }
$message = $e->getMessage(); $message = $e->getMessage();
\Yii::error("$message\nFailed to execute SQL: {$sql}{$paramLog}", __CLASS__); \Yii::error("$message\nFailed to execute SQL: {$sql}{$paramLog}", __CLASS__);
$errorInfo = $e instanceof \PDOException ? $e->errorInfo : null; $errorInfo = $e instanceof \PDOException ? $e->errorInfo : null;
throw new Exception($message, (int)$e->getCode(), $errorInfo); throw new Exception($message, (int)$e->getCode(), $errorInfo);
} }
...@@ -364,6 +389,7 @@ class Command extends \yii\base\Component ...@@ -364,6 +389,7 @@ class Command extends \yii\base\Component
* @param mixed $fetchMode the result fetch mode. Please refer to [PHP manual](http://www.php.net/manual/en/function.PDOStatement-setFetchMode.php) * @param mixed $fetchMode the result fetch mode. Please refer to [PHP manual](http://www.php.net/manual/en/function.PDOStatement-setFetchMode.php)
* for valid fetch modes. If this parameter is null, the value set in [[fetchMode]] will be used. * for valid fetch modes. If this parameter is null, the value set in [[fetchMode]] will be used.
* @return mixed the method execution result * @return mixed the method execution result
* @throws Exception if the query causes any problem
*/ */
private function queryInternal($method, $params, $fetchMode = null) private function queryInternal($method, $params, $fetchMode = null)
{ {
...@@ -439,9 +465,9 @@ class Command extends \yii\base\Component ...@@ -439,9 +465,9 @@ class Command extends \yii\base\Component
* For example, * For example,
* *
* ~~~ * ~~~
* $db->createCommand()->insert('tbl_user', array( * $connection->createCommand()->insert('tbl_user', array(
* 'name' => 'Sam', * 'name' => 'Sam',
* 'age' => 30, * 'age' => 30,
* ))->execute(); * ))->execute();
* ~~~ * ~~~
* *
...@@ -465,8 +491,8 @@ class Command extends \yii\base\Component ...@@ -465,8 +491,8 @@ class Command extends \yii\base\Component
* For example, * For example,
* *
* ~~~ * ~~~
* $db->createCommand()->update('tbl_user', array( * $connection->createCommand()->update('tbl_user', array(
* 'status' => 1, * 'status' => 1,
* ), 'age > 30')->execute(); * ), 'age > 30')->execute();
* ~~~ * ~~~
* *
...@@ -492,7 +518,7 @@ class Command extends \yii\base\Component ...@@ -492,7 +518,7 @@ class Command extends \yii\base\Component
* For example, * For example,
* *
* ~~~ * ~~~
* $db->createCommand()->delete('tbl_user', 'status = 0')->execute(); * $connection->createCommand()->delete('tbl_user', 'status = 0')->execute();
* ~~~ * ~~~
* *
* The method will properly escape the table and column names. * The method will properly escape the table and column names.
......
...@@ -92,8 +92,7 @@ use yii\base\BadConfigException; ...@@ -92,8 +92,7 @@ use yii\base\BadConfigException;
* @property QueryBuilder $queryBuilder The query builder. * @property QueryBuilder $queryBuilder The query builder.
* @property string $lastInsertID The row ID of the last row inserted, or the last value retrieved from the sequence object. * @property string $lastInsertID The row ID of the last row inserted, or the last value retrieved from the sequence object.
* @property string $driverName Name of the DB driver currently being used. * @property string $driverName Name of the DB driver currently being used.
* @property string $clientVersion The version information of the DB driver. * @property array $querySummary The statistical results of SQL queries.
* @property array $stats The statistical results of SQL executions.
* *
* @event Event afterOpen this event is triggered after a DB connection is established * @event Event afterOpen this event is triggered after a DB connection is established
* *
...@@ -118,7 +117,7 @@ class Connection extends \yii\base\ApplicationComponent ...@@ -118,7 +117,7 @@ class Connection extends \yii\base\ApplicationComponent
*/ */
public $password = ''; public $password = '';
/** /**
* @var array PDO attributes (name=>value) that should be set when calling [[open]] * @var array PDO attributes (name=>value) that should be set when calling [[open()]]
* to establish a DB connection. Please refer to the * to establish a DB connection. Please refer to the
* [PHP manual](http://www.php.net/manual/en/function.PDO-setAttribute.php) for * [PHP manual](http://www.php.net/manual/en/function.PDO-setAttribute.php) for
* details about available attributes. * details about available attributes.
...@@ -275,16 +274,6 @@ class Connection extends \yii\base\ApplicationComponent ...@@ -275,16 +274,6 @@ class Connection extends \yii\base\ApplicationComponent
} }
/** /**
* Returns a list of available PDO drivers.
* @return array list of available PDO drivers
* @see http://www.php.net/manual/en/function.PDO-getAvailableDrivers.php
*/
public static function getAvailableDrivers()
{
return \PDO::getAvailableDrivers();
}
/**
* Returns a value indicating whether the DB connection is established. * Returns a value indicating whether the DB connection is established.
* @return boolean whether the DB connection is established * @return boolean whether the DB connection is established
*/ */
...@@ -533,36 +522,12 @@ class Connection extends \yii\base\ApplicationComponent ...@@ -533,36 +522,12 @@ class Connection extends \yii\base\ApplicationComponent
if (($pos = strpos($this->dsn, ':')) !== false) { if (($pos = strpos($this->dsn, ':')) !== false) {
return strtolower(substr($this->dsn, 0, $pos)); return strtolower(substr($this->dsn, 0, $pos));
} else { } else {
return strtolower($this->getAttribute(\PDO::ATTR_DRIVER_NAME)); return strtolower($this->pdo->getAttribute(\PDO::ATTR_DRIVER_NAME));
} }
} }
/** /**
* Obtains a specific DB connection attribute information. * Returns the statistical results of SQL queries.
* @param integer $name the attribute to be queried
* @return mixed the corresponding attribute information
* @see http://www.php.net/manual/en/function.PDO-getAttribute.php
*/
public function getAttribute($name)
{
$this->open();
return $this->pdo->getAttribute($name);
}
/**
* Sets an attribute on the database connection.
* @param integer $name the attribute to be set
* @param mixed $value the attribute value
* @see http://www.php.net/manual/en/function.PDO-setAttribute.php
*/
public function setAttribute($name, $value)
{
$this->open();
$this->pdo->setAttribute($name, $value);
}
/**
* Returns the statistical results of SQL executions.
* The results returned include the number of SQL statements executed and * The results returned include the number of SQL statements executed and
* the total time spent. * the total time spent.
* In order to use this method, [[enableProfiling]] has to be set true. * In order to use this method, [[enableProfiling]] has to be set true.
...@@ -570,7 +535,7 @@ class Connection extends \yii\base\ApplicationComponent ...@@ -570,7 +535,7 @@ class Connection extends \yii\base\ApplicationComponent
* and the second element the total time spent in SQL execution. * and the second element the total time spent in SQL execution.
* @see \yii\logging\Logger::getProfiling() * @see \yii\logging\Logger::getProfiling()
*/ */
public function getExecutionSummary() public function getQuerySummary()
{ {
$logger = \Yii::getLogger(); $logger = \Yii::getLogger();
$timings = $logger->getProfiling(array('yii\db\Command::query', 'yii\db\Command::execute')); $timings = $logger->getProfiling(array('yii\db\Command::query', 'yii\db\Command::execute'));
......
...@@ -9,23 +9,33 @@ ...@@ -9,23 +9,33 @@
namespace yii\db; namespace yii\db;
use yii\db\Exception; use yii\base\BadCallException;
/** /**
* DataReader represents a forward-only stream of rows from a query result set. * DataReader represents a forward-only stream of rows from a query result set.
* *
* To read the current row of data, call [[read]]. The method [[readAll]] * To read the current row of data, call [[read()]]. The method [[readAll()]]
* returns all the rows in a single array. * returns all the rows in a single array. Rows of data can also be read by
* * iterating through the reader. For example,
* One can also retrieve the rows of data in DataReader by using `foreach`:
* *
* ~~~ * ~~~
* $reader = $command->query('SELECT * FROM tbl_post');
*
* while ($row = $reader->read()) {
* $rows[] = $row;
* }
*
* // equivalent to:
* foreach($reader as $row) { * foreach($reader as $row) {
* // $row represents a row of data * $rows[] = $row;
* } * }
*
* // equivalent to:
* $rows = $reader->readAll();
* ~~~ * ~~~
* *
* Since DataReader is a forward-only stream, you can only traverse it once. * Note that since DataReader is a forward-only stream, you can only traverse it once.
* Doing it the second time will throw an exception.
* *
* It is possible to use a specific mode of data fetching by setting * It is possible to use a specific mode of data fetching by setting
* [[fetchMode]]. See the [PHP manual](http://www.php.net/manual/en/function.PDOStatement-setFetchMode.php) * [[fetchMode]]. See the [PHP manual](http://www.php.net/manual/en/function.PDOStatement-setFetchMode.php)
...@@ -202,7 +212,7 @@ class DataReader extends \yii\base\Object implements \Iterator, \Countable ...@@ -202,7 +212,7 @@ class DataReader extends \yii\base\Object implements \Iterator, \Countable
/** /**
* Resets the iterator to the initial state. * Resets the iterator to the initial state.
* This method is required by the interface Iterator. * This method is required by the interface Iterator.
* @throws Exception if this method is invoked twice * @throws BadCallException if this method is invoked twice
*/ */
public function rewind() public function rewind()
{ {
...@@ -210,7 +220,7 @@ class DataReader extends \yii\base\Object implements \Iterator, \Countable ...@@ -210,7 +220,7 @@ class DataReader extends \yii\base\Object implements \Iterator, \Countable
$this->_row = $this->_statement->fetch(); $this->_row = $this->_statement->fetch();
$this->_index = 0; $this->_index = 0;
} else { } else {
throw new Exception('DataReader cannot rewind. It is a forward-only reader.'); throw new BadCallException('DataReader cannot rewind. It is a forward-only reader.');
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment