Command.php 26.1 KB
Newer Older
w  
Qiang Xue committed
1 2
<?php
/**
Qiang Xue committed
3
 * Command class file.
w  
Qiang Xue committed
4 5
 *
 * @link http://www.yiiframework.com/
Qiang Xue committed
6
 * @copyright Copyright &copy; 2008 Yii Software LLC
w  
Qiang Xue committed
7 8 9
 * @license http://www.yiiframework.com/license/
 */

Qiang Xue committed
10
namespace yii\db;
w  
Qiang Xue committed
11

w  
Qiang Xue committed
12 13
use yii\db\Exception;

w  
Qiang Xue committed
14
/**
w  
Qiang Xue committed
15
 * Command represents a SQL statement to be executed against a database.
w  
Qiang Xue committed
16
 *
Qiang Xue committed
17
 * A command object is usually created by calling [[Connection::createCommand()]].
Qiang Xue committed
18
 * The SQL statement it represents can be set via the [[sql]] property.
w  
Qiang Xue committed
19
 *
Qiang Xue committed
20
 * To execute a non-query SQL (such as INSERT, DELETE, UPDATE), call [[execute()]].
Qiang Xue committed
21
 * To execute a SQL statement that returns result data set (such as SELECT),
Qiang Xue committed
22
 * use [[queryAll()]], [[queryRow()]], [[queryColumn()]], [[queryScalar()]], or [[query()]].
Qiang Xue committed
23 24 25
 * For example,
 *
 * ~~~
Qiang Xue committed
26
 * $users = \Yii::$application->db->createCommand('SELECT * FROM tbl_user')->queryAll();
Qiang Xue committed
27
 * ~~~
w  
Qiang Xue committed
28
 *
Qiang Xue committed
29
 * Command supports SQL statement preparation and parameter binding.
Qiang Xue committed
30 31
 * Call [[bindValue()]] to bind a value to a SQL parameter;
 * Call [[bindParam()]] to bind a PHP variable to a SQL parameter.
w  
Qiang Xue committed
32
 * When binding a parameter, the SQL statement is automatically prepared.
Qiang Xue committed
33
 * You may also call [[prepare()]] explicitly to prepare a SQL statement.
w  
Qiang Xue committed
34
 *
Qiang Xue committed
35 36
 * @property string $sql the SQL statement to be executed
 *
w  
Qiang Xue committed
37
 * @author Qiang Xue <qiang.xue@gmail.com>
w  
Qiang Xue committed
38
 * @since 2.0
w  
Qiang Xue committed
39
 */
w  
Qiang Xue committed
40
class Command extends \yii\base\Component
w  
Qiang Xue committed
41
{
Qiang Xue committed
42 43 44
	/**
	 * @var Connection the DB connection that this command is associated with
	 */
w  
Qiang Xue committed
45
	public $connection;
Qiang Xue committed
46 47 48
	/**
	 * @var \PDOStatement the PDOStatement object that this command contains
	 */
w  
Qiang Xue committed
49 50
	public $pdoStatement;
	/**
Qiang Xue committed
51
	 * @var mixed the default fetch mode for this command.
w  
Qiang Xue committed
52 53 54
	 * @see http://www.php.net/manual/en/function.PDOStatement-setFetchMode.php
	 */
	public $fetchMode = \PDO::FETCH_ASSOC;
Qiang Xue committed
55 56 57 58 59
	/**
	 * @var string the SQL statement that this command represents
	 */
	private $_sql;
	/**
Qiang Xue committed
60
	 * @var array the parameter log information (name=>value)
Qiang Xue committed
61
	 */
Qiang Xue committed
62
	private $_params = array();
Qiang Xue committed
63

w  
Qiang Xue committed
64
	/**
Qiang Xue committed
65
	 * Returns the SQL statement for this command.
w  
Qiang Xue committed
66 67
	 * @return string the SQL statement to be executed
	 */
Qiang Xue committed
68
	public function getSql()
w  
Qiang Xue committed
69
	{
w  
Qiang Xue committed
70
		return $this->_sql;
w  
Qiang Xue committed
71 72 73 74
	}

	/**
	 * Specifies the SQL statement to be executed.
Qiang Xue committed
75
	 * Any previous execution will be terminated or cancelled.
76
	 * @param string $sql the SQL statement to be set.
w  
Qiang Xue committed
77
	 * @return Command this command instance
w  
Qiang Xue committed
78
	 */
79
	public function setSql($sql)
w  
Qiang Xue committed
80
	{
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
		if ($sql !== $this->_sql) {
			if ($this->connection->enableAutoQuoting && $sql != '') {
				$sql = 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);
			}
			$this->_sql = $sql;
			$this->_params = array();
			$this->cancel();
		}
w  
Qiang Xue committed
96 97 98 99 100 101 102 103 104
		return $this;
	}

	/**
	 * Prepares the SQL statement to be executed.
	 * For complex SQL statement that is to be executed multiple times,
	 * this may improve performance.
	 * For SQL statement with binding parameters, this method is invoked
	 * automatically.
Qiang Xue committed
105
	 * @throws Exception if there is any DB error
w  
Qiang Xue committed
106 107 108
	 */
	public function prepare()
	{
w  
Qiang Xue committed
109
		if ($this->pdoStatement == null) {
110
			$sql = $this->getSql();
w  
Qiang Xue committed
111
			try {
Qiang Xue committed
112
				$this->pdoStatement = $this->connection->pdo->prepare($sql);
Qiang Xue committed
113
			} catch (\Exception $e) {
Qiang Xue committed
114
				\Yii::error($e->getMessage() . "\nFailed to prepare SQL: $sql", __CLASS__);
Qiang Xue committed
115
				$errorInfo = $e instanceof \PDOException ? $e->errorInfo : null;
Qiang Xue committed
116
				throw new Exception($e->getMessage(), (int)$e->getCode(), $errorInfo);
w  
Qiang Xue committed
117 118 119 120 121 122
			}
		}
	}

	/**
	 * Cancels the execution of the SQL statement.
Qiang Xue committed
123
	 * This method mainly sets [[pdoStatement]] to be null.
w  
Qiang Xue committed
124 125 126
	 */
	public function cancel()
	{
w  
Qiang Xue committed
127
		$this->pdoStatement = null;
w  
Qiang Xue committed
128 129 130 131
	}

	/**
	 * Binds a parameter to the SQL statement to be executed.
Qiang Xue committed
132
	 * @param string|integer $name parameter identifier. For a prepared statement
w  
Qiang Xue committed
133
	 * using named placeholders, this will be a parameter name of
Qiang Xue committed
134
	 * the form `:name`. For a prepared statement using question mark
w  
Qiang Xue committed
135 136 137 138
	 * placeholders, this will be the 1-indexed position of the parameter.
	 * @param mixed $value Name of the PHP variable to bind to the SQL statement parameter
	 * @param integer $dataType SQL data type of the parameter. If null, the type is determined by the PHP type of the value.
	 * @param integer $length length of the data type
Qiang Xue committed
139 140
	 * @param mixed $driverOptions the driver-specific options
	 * @return Command the current command being executed
w  
Qiang Xue committed
141 142 143 144 145
	 * @see http://www.php.net/manual/en/function.PDOStatement-bindParam.php
	 */
	public function bindParam($name, &$value, $dataType = null, $length = null, $driverOptions = null)
	{
		$this->prepare();
Qiang Xue committed
146
		if ($dataType === null) {
w  
Qiang Xue committed
147
			$this->pdoStatement->bindParam($name, $value, $this->connection->getPdoType(gettype($value)));
Qiang Xue committed
148
		} elseif ($length === null) {
w  
Qiang Xue committed
149
			$this->pdoStatement->bindParam($name, $value, $dataType);
Qiang Xue committed
150
		} elseif ($driverOptions === null) {
w  
Qiang Xue committed
151
			$this->pdoStatement->bindParam($name, $value, $dataType, $length);
Qiang Xue committed
152
		} else {
w  
Qiang Xue committed
153
			$this->pdoStatement->bindParam($name, $value, $dataType, $length, $driverOptions);
Qiang Xue committed
154
		}
Qiang Xue committed
155
		$this->_params[$name] =& $value;
w  
Qiang Xue committed
156 157 158 159 160
		return $this;
	}

	/**
	 * Binds a value to a parameter.
Qiang Xue committed
161
	 * @param string|integer $name Parameter identifier. For a prepared statement
w  
Qiang Xue committed
162
	 * using named placeholders, this will be a parameter name of
Qiang Xue committed
163
	 * the form `:name`. For a prepared statement using question mark
w  
Qiang Xue committed
164 165 166
	 * placeholders, this will be the 1-indexed position of the parameter.
	 * @param mixed $value The value to bind to the parameter
	 * @param integer $dataType SQL data type of the parameter. If null, the type is determined by the PHP type of the value.
Qiang Xue committed
167
	 * @return Command the current command being executed
w  
Qiang Xue committed
168 169 170 171 172
	 * @see http://www.php.net/manual/en/function.PDOStatement-bindValue.php
	 */
	public function bindValue($name, $value, $dataType = null)
	{
		$this->prepare();
Qiang Xue committed
173
		if ($dataType === null) {
w  
Qiang Xue committed
174
			$this->pdoStatement->bindValue($name, $value, $this->connection->getPdoType(gettype($value)));
Qiang Xue committed
175
		} else {
w  
Qiang Xue committed
176
			$this->pdoStatement->bindValue($name, $value, $dataType);
Qiang Xue committed
177
		}
Qiang Xue committed
178
		$this->_params[$name] = $value;
w  
Qiang Xue committed
179 180 181 182 183
		return $this;
	}

	/**
	 * Binds a list of values to the corresponding parameters.
Qiang Xue committed
184
	 * This is similar to [[bindValue()]] except that it binds multiple values at a time.
w  
Qiang Xue committed
185 186
	 * Note that the SQL data type of each value is determined by its PHP type.
	 * @param array $values the values to be bound. This must be given in terms of an associative
Qiang Xue committed
187
	 * array with array keys being the parameter names, and array values the corresponding parameter values,
188 189 190
	 * e.g. `array(':name'=>'John', ':age'=>25)`. By default, the PDO type of each value is determined
	 * by its PHP type. You may explicitly specify the PDO type by using an array: `array(value, type)`,
	 * e.g. `array(':name'=>'John', ':profile'=>array($profile, \PDO::PARAM_LOB))`.
w  
Qiang Xue committed
191
	 * @return Command the current command being executed
w  
Qiang Xue committed
192 193 194
	 */
	public function bindValues($values)
	{
Qiang Xue committed
195
		if (!empty($values)) {
Qiang Xue committed
196 197
			$this->prepare();
			foreach ($values as $name => $value) {
198 199 200 201 202 203 204
				if (is_array($value)) {
					$type = $value[1];
					$value = $value[0];
				} else {
					$type = $this->connection->getPdoType(gettype($value));
				}
				$this->pdoStatement->bindValue($name, $value, $type);
Qiang Xue committed
205 206 207
				$this->_params[$name] = $value;
			}
		}
w  
Qiang Xue committed
208 209 210 211 212
		return $this;
	}

	/**
	 * Executes the SQL statement.
Qiang Xue committed
213
	 * This method should only be used for executing non-query SQL statement, such as `INSERT`, `DELETE`, `UPDATE` SQLs.
w  
Qiang Xue committed
214 215
	 * No result set will be returned.
	 * @param array $params input parameters (name=>value) for the SQL execution. This is an alternative
Qiang Xue committed
216 217
	 * to [[bindValues()]]. Note that if you pass parameters in this way, any previous call to [[bindParam()]]
	 * or [[bindValue()]] will be ignored.
w  
Qiang Xue committed
218
	 * @return integer number of rows affected by the execution.
Qiang Xue committed
219
	 * @throws Exception execution failed
w  
Qiang Xue committed
220 221 222
	 */
	public function execute($params = array())
	{
223
		$sql = $this->getSql();
Qiang Xue committed
224 225 226
		$this->_params = array_merge($this->_params, $params);
		if ($this->_params === array()) {
			$paramLog = '';
Qiang Xue committed
227
		} else {
Qiang Xue committed
228
			$paramLog = "\nParameters: " . var_export($this->_params, true);
w  
Qiang Xue committed
229
		}
Qiang Xue committed
230 231

		\Yii::trace("Executing SQL: {$sql}{$paramLog}", __CLASS__);
Qiang Xue committed
232

Qiang Xue committed
233 234 235 236
		try {
			if ($this->connection->enableProfiling) {
				\Yii::beginProfile(__METHOD__ . "($sql)", __CLASS__);
			}
w  
Qiang Xue committed
237 238

			$this->prepare();
Qiang Xue committed
239
			if ($params === array()) {
w  
Qiang Xue committed
240
				$this->pdoStatement->execute();
Qiang Xue committed
241
			} else {
w  
Qiang Xue committed
242
				$this->pdoStatement->execute($params);
Qiang Xue committed
243
			}
w  
Qiang Xue committed
244
			$n = $this->pdoStatement->rowCount();
w  
Qiang Xue committed
245

Qiang Xue committed
246 247 248
			if ($this->connection->enableProfiling) {
				\Yii::endProfile(__METHOD__ . "($sql)", __CLASS__);
			}
w  
Qiang Xue committed
249
			return $n;
Qiang Xue committed
250
		} catch (\Exception $e) {
Qiang Xue committed
251 252 253 254 255 256 257
			if ($this->connection->enableProfiling) {
				\Yii::endProfile(__METHOD__ . "($sql)", __CLASS__);
			}
			$message = $e->getMessage();
			\Yii::error("$message\nFailed to execute SQL: {$sql}{$paramLog}", __CLASS__);
			$errorInfo = $e instanceof \PDOException ? $e->errorInfo : null;
			throw new Exception($message, (int)$e->getCode(), $errorInfo);
w  
Qiang Xue committed
258 259 260 261 262
		}
	}

	/**
	 * Executes the SQL statement and returns query result.
Qiang Xue committed
263
	 * This method is for executing a SQL query that returns result set, such as `SELECT`.
w  
Qiang Xue committed
264
	 * @param array $params input parameters (name=>value) for the SQL execution. This is an alternative
Qiang Xue committed
265 266
	 * to [[bindValues()]]. Note that if you pass parameters in this way, any previous call to [[bindParam()]]
	 * or [[bindValue()]] will be ignored.
Qiang Xue committed
267 268
	 * @return DataReader the reader object for fetching the query result
	 * @throws Exception execution failed
w  
Qiang Xue committed
269 270 271
	 */
	public function query($params = array())
	{
w  
Qiang Xue committed
272
		return $this->queryInternal('', $params);
w  
Qiang Xue committed
273 274 275
	}

	/**
Qiang Xue committed
276
	 * Executes the SQL statement and returns ALL rows at once.
Qiang Xue committed
277
	 * @param array $params input parameters (name=>value) for the SQL execution. This is an alternative
Qiang Xue committed
278 279
	 * to [[bindValues()]]. Note that if you pass parameters in this way, any previous call to [[bindParam()]]
	 * or [[bindValue()]] will be ignored.
Qiang Xue committed
280 281 282
	 * @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.
	 * @return array all rows of the query result. Each array element is an array representing a row of data.
w  
Qiang Xue committed
283
	 * An empty array is returned if the query results in nothing.
Qiang Xue committed
284
	 * @throws Exception execution failed
w  
Qiang Xue committed
285
	 */
w  
Qiang Xue committed
286
	public function queryAll($params = array(), $fetchMode = null)
w  
Qiang Xue committed
287
	{
w  
Qiang Xue committed
288
		return $this->queryInternal('fetchAll', $params, $fetchMode);
w  
Qiang Xue committed
289 290 291 292
	}

	/**
	 * Executes the SQL statement and returns the first row of the result.
Qiang Xue committed
293
	 * This method is best used when only the first row of result is needed for a query.
Qiang Xue committed
294
	 * @param array $params input parameters (name=>value) for the SQL execution. This is an alternative
Qiang Xue committed
295 296
	 * to [[bindValues()]]. Note that if you pass parameters in this way, any previous call to [[bindParam()]]
	 * or [[bindValue()]] will be ignored.
Qiang Xue committed
297 298 299 300
	 * @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.
	 * @return array|boolean the first row (in terms of an array) of the query result. False is returned if the query
	 * results in nothing.
Qiang Xue committed
301
	 * @throws Exception execution failed
w  
Qiang Xue committed
302
	 */
w  
Qiang Xue committed
303
	public function queryRow($params = array(), $fetchMode = null)
w  
Qiang Xue committed
304
	{
w  
Qiang Xue committed
305
		return $this->queryInternal('fetch', $params, $fetchMode);
w  
Qiang Xue committed
306 307 308 309
	}

	/**
	 * Executes the SQL statement and returns the value of the first column in the first row of data.
Qiang Xue committed
310
	 * This method is best used when only a single value is needed for a query.
w  
Qiang Xue committed
311
	 * @param array $params input parameters (name=>value) for the SQL execution. This is an alternative
Qiang Xue committed
312 313 314
	 * to [[bindValues()]]. Note that if you pass parameters in this way, any previous call to [[bindParam()]]
	 * or [[bindValue()]] will be ignored.
	 * @return string|boolean the value of the first column in the first row of the query result.
Qiang Xue committed
315
	 * False is returned if there is no value.
Qiang Xue committed
316
	 * @throws Exception execution failed
w  
Qiang Xue committed
317 318 319
	 */
	public function queryScalar($params = array())
	{
Qiang Xue committed
320
		$result = $this->queryInternal('fetchColumn', $params, 0);
w  
Qiang Xue committed
321
		if (is_resource($result) && get_resource_type($result) === 'stream') {
w  
Qiang Xue committed
322
			return stream_get_contents($result);
Qiang Xue committed
323
		} else {
w  
Qiang Xue committed
324
			return $result;
w  
Qiang Xue committed
325
		}
w  
Qiang Xue committed
326 327 328 329
	}

	/**
	 * Executes the SQL statement and returns the first column of the result.
Qiang Xue committed
330 331
	 * This method is best used when only the first column of result (i.e. the first element in each row)
	 * is needed for a query.
w  
Qiang Xue committed
332
	 * @param array $params input parameters (name=>value) for the SQL execution. This is an alternative
Qiang Xue committed
333 334
	 * to [[bindValues()]]. Note that if you pass parameters in this way, any previous call to [[bindParam()]]
	 * or [[bindValue()]] will be ignored.
Qiang Xue committed
335
	 * @return array the first column of the query result. Empty array is returned if the query results in nothing.
Qiang Xue committed
336
	 * @throws Exception execution failed
w  
Qiang Xue committed
337 338 339
	 */
	public function queryColumn($params = array())
	{
w  
Qiang Xue committed
340
		return $this->queryInternal('fetchAll', $params, \PDO::FETCH_COLUMN);
w  
Qiang Xue committed
341 342 343
	}

	/**
Qiang Xue committed
344
	 * Performs the actual DB query of a SQL statement.
w  
Qiang Xue committed
345 346
	 * @param string $method method of PDOStatement to be called
	 * @param array $params input parameters (name=>value) for the SQL execution. This is an alternative
Qiang Xue committed
347 348
	 * to [[bindValues()]]. Note that if you pass parameters in this way, any previous call to [[bindParam()]]
	 * or [[bindValue()]] will be ignored.
Qiang Xue committed
349 350
	 * @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.
w  
Qiang Xue committed
351 352
	 * @return mixed the method execution result
	 */
w  
Qiang Xue committed
353
	private function queryInternal($method, $params, $fetchMode = null)
w  
Qiang Xue committed
354
	{
Qiang Xue committed
355
		$db = $this->connection;
356
		$sql = $this->getSql();
Qiang Xue committed
357 358 359
		$this->_params = array_merge($this->_params, $params);
		if ($this->_params === array()) {
			$paramLog = '';
Qiang Xue committed
360
		} else {
Qiang Xue committed
361
			$paramLog = "\nParameters: " . var_export($this->_params, true);
w  
Qiang Xue committed
362
		}
Qiang Xue committed
363 364

		\Yii::trace("Querying SQL: {$sql}{$paramLog}", __CLASS__);
365

Qiang Xue committed
366
		/** @var $cache \yii\caching\Cache */
367
		if ($db->enableQueryCache && $method !== '') {
Qiang Xue committed
368
			$cache = \Yii::$application->getComponent($db->queryCacheID);
Qiang Xue committed
369 370 371 372
		}

		if (isset($cache)) {
			$cacheKey = __CLASS__ . "/{$db->dsn}/{$db->username}/$sql/$paramLog";
Qiang Xue committed
373
			if (($result = $cache->get($cacheKey)) !== false) {
Qiang Xue committed
374
				\Yii::trace('Query result found in cache', __CLASS__);
w  
Qiang Xue committed
375 376 377 378
				return $result;
			}
		}

Qiang Xue committed
379 380 381 382
		try {
			if ($db->enableProfiling) {
				\Yii::beginProfile(__METHOD__ . "($sql)", __CLASS__);
			}
w  
Qiang Xue committed
383 384

			$this->prepare();
Qiang Xue committed
385
			if ($params === array()) {
w  
Qiang Xue committed
386
				$this->pdoStatement->execute();
Qiang Xue committed
387
			} else {
w  
Qiang Xue committed
388
				$this->pdoStatement->execute($params);
Qiang Xue committed
389
			}
w  
Qiang Xue committed
390

Qiang Xue committed
391
			if ($method === '') {
w  
Qiang Xue committed
392
				$result = new DataReader($this);
Qiang Xue committed
393
			} else {
Qiang Xue committed
394 395 396
				if ($fetchMode === null) {
					$fetchMode = $this->fetchMode;
				}
w  
Qiang Xue committed
397 398
				$result = call_user_func_array(array($this->pdoStatement, $method), (array)$fetchMode);
				$this->pdoStatement->closeCursor();
w  
Qiang Xue committed
399 400
			}

Qiang Xue committed
401 402 403
			if ($db->enableProfiling) {
				\Yii::endProfile(__METHOD__ . "($sql)", __CLASS__);
			}
w  
Qiang Xue committed
404

Qiang Xue committed
405
			if (isset($cache, $cacheKey)) {
406
				$cache->set($cacheKey, $result, $db->queryCacheDuration, $db->queryCacheDependency);
Qiang Xue committed
407
				\Yii::trace('Saved query result in cache', __CLASS__);
Qiang Xue committed
408
			}
w  
Qiang Xue committed
409 410

			return $result;
Qiang Xue committed
411
		} catch (\Exception $e) {
Qiang Xue committed
412 413 414 415
			if ($db->enableProfiling) {
				\Yii::endProfile(__METHOD__ . "($sql)", __CLASS__);
			}
			$message = $e->getMessage();
Qiang Xue committed
416 417 418
			\Yii::error("$message\nCommand::$method() failed: {$sql}{$paramLog}", __CLASS__);
			$errorInfo = $e instanceof \PDOException ? $e->errorInfo : null;
			throw new Exception($message, (int)$e->getCode(), $errorInfo);
w  
Qiang Xue committed
419 420
		}
	}
Qiang Xue committed
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668

	/**
	 * Creates an INSERT command.
	 * For example,
	 *
	 * ~~~
	 * $db->createCommand()->insert('tbl_user', array(
	 *	 'name' => 'Sam',
	 *	 'age' => 30,
	 * ))->execute();
	 * ~~~
	 *
	 * The method will properly escape the column names, and bind the values to be inserted.
	 *
	 * Note that the created command is not executed until [[execute()]] is called.
	 *
	 * @param string $table the table that new rows will be inserted into.
	 * @param array $columns the column data (name=>value) to be inserted into the table.
	 * @param array $params the parameters to be bound to the command
	 * @return Command the command object itself
	 */
	public function insert($table, $columns, $params = array())
	{
		$sql = $this->connection->getQueryBuilder()->insert($table, $columns, $params);
		return $this->setSql($sql)->bindValues($params);
	}

	/**
	 * Creates an UPDATE command.
	 * For example,
	 *
	 * ~~~
	 * $db->createCommand()->update('tbl_user', array(
	 *	 'status' => 1,
	 * ), 'age > 30')->execute();
	 * ~~~
	 *
	 * The method will properly escape the column names and bind the values to be updated.
	 *
	 * Note that the created command is not executed until [[execute()]] is called.
	 *
	 * @param string $table the table to be updated.
	 * @param array $columns the column data (name=>value) to be updated.
	 * @param mixed $condition the condition that will be put in the WHERE part. Please
	 * refer to [[Query::where()]] on how to specify condition.
	 * @param array $params the parameters to be bound to the command
	 * @return Command the command object itself
	 */
	public function update($table, $columns, $condition = '', $params = array())
	{
		$sql = $this->connection->getQueryBuilder()->update($table, $columns, $condition, $params);
		return $this->setSql($sql)->bindValues($params);
	}

	/**
	 * Creates a DELETE command.
	 * For example,
	 *
	 * ~~~
	 * $db->createCommand()->delete('tbl_user', 'status = 0')->execute();
	 * ~~~
	 *
	 * The method will properly escape the table and column names.
	 *
	 * Note that the created command is not executed until [[execute()]] is called.
	 *
	 * @param string $table the table where the data will be deleted from.
	 * @param mixed $condition the condition that will be put in the WHERE part. Please
	 * refer to [[Query::where()]] on how to specify condition.
	 * @param array $params the parameters to be bound to the command
	 * @return Command the command object itself
	 */
	public function delete($table, $condition = '', $params = array())
	{
		$sql = $this->connection->getQueryBuilder()->delete($table, $condition);
		return $this->setSql($sql)->bindValues($params);
	}


	/**
	 * Creates a SQL command for creating a new DB table.
	 *
	 * The columns in the new table should be specified as name-definition pairs (e.g. 'name'=>'string'),
	 * where name stands for a column name which will be properly quoted by the method, and definition
	 * stands for the column type which can contain an abstract DB type.
	 * The method [[\yii\db\QueryBuilder::getColumnType()]] will be called
	 * to convert the abstract column types to physical ones. For example, `string` will be converted
	 * as `varchar(255)`, and `string not null` becomes `varchar(255) not null`.
	 *
	 * If a column is specified with definition only (e.g. 'PRIMARY KEY (name, type)'), it will be directly
	 * inserted into the generated SQL.
	 *
	 * @param string $table the name of the table to be created. The name will be properly quoted by the method.
	 * @param array $columns the columns (name=>definition) in the new table.
	 * @param string $options additional SQL fragment that will be appended to the generated SQL.
	 * @return Command the command object itself
	 */
	public function createTable($table, $columns, $options = null)
	{
		$sql = $this->connection->getQueryBuilder()->createTable($table, $columns, $options);
		return $this->setSql($sql);
	}

	/**
	 * Creates a SQL command for renaming a DB table.
	 * @param string $table the table to be renamed. The name will be properly quoted by the method.
	 * @param string $newName the new table name. The name will be properly quoted by the method.
	 * @return Command the command object itself
	 */
	public function renameTable($table, $newName)
	{
		$sql = $this->connection->getQueryBuilder()->renameTable($table, $newName);
		return $this->setSql($sql);
	}

	/**
	 * Creates a SQL command for dropping a DB table.
	 * @param string $table the table to be dropped. The name will be properly quoted by the method.
	 * @return Command the command object itself
	 */
	public function dropTable($table)
	{
		$sql = $this->connection->getQueryBuilder()->dropTable($table);
		return $this->setSql($sql);
	}

	/**
	 * Creates a SQL command for truncating a DB table.
	 * @param string $table the table to be truncated. The name will be properly quoted by the method.
	 * @return Command the command object itself
	 */
	public function truncateTable($table)
	{
		$sql = $this->connection->getQueryBuilder()->truncateTable($table);
		return $this->setSql($sql);
	}

	/**
	 * Creates a SQL command for adding a new DB column.
	 * @param string $table the table that the new column will be added to. The table name will be properly quoted by the method.
	 * @param string $column the name of the new column. The name will be properly quoted by the method.
	 * @param string $type the column type. [[\yii\db\QueryBuilder::getColumnType()]] will be called
	 * to convert the give column type to the physical one. For example, `string` will be converted
	 * as `varchar(255)`, and `string not null` becomes `varchar(255) not null`.
	 * @return Command the command object itself
	 */
	public function addColumn($table, $column, $type)
	{
		$sql = $this->connection->getQueryBuilder()->addColumn($table, $column, $type);
		return $this->setSql($sql);
	}

	/**
	 * Creates a SQL command for dropping a DB column.
	 * @param string $table the table whose column is to be dropped. The name will be properly quoted by the method.
	 * @param string $column the name of the column to be dropped. The name will be properly quoted by the method.
	 * @return Command the command object itself
	 */
	public function dropColumn($table, $column)
	{
		$sql = $this->connection->getQueryBuilder()->dropColumn($table, $column);
		return $this->setSql($sql);
	}

	/**
	 * Creates a SQL command for renaming a column.
	 * @param string $table the table whose column is to be renamed. The name will be properly quoted by the method.
	 * @param string $oldName the old name of the column. The name will be properly quoted by the method.
	 * @param string $newName the new name of the column. The name will be properly quoted by the method.
	 * @return Command the command object itself
	 */
	public function renameColumn($table, $oldName, $newName)
	{
		$sql = $this->connection->getQueryBuilder()->renameColumn($table, $oldName, $newName);
		return $this->setSql($sql);
	}

	/**
	 * Creates a SQL command for changing the definition of a column.
	 * @param string $table the table whose column is to be changed. The table name will be properly quoted by the method.
	 * @param string $column the name of the column to be changed. The name will be properly quoted by the method.
	 * @param string $type the column type. [[\yii\db\QueryBuilder::getColumnType()]] will be called
	 * to convert the give column type to the physical one. For example, `string` will be converted
	 * as `varchar(255)`, and `string not null` becomes `varchar(255) not null`.
	 * @return Command the command object itself
	 */
	public function alterColumn($table, $column, $type)
	{
		$sql = $this->connection->getQueryBuilder()->alterColumn($table, $column, $type);
		return $this->setSql($sql);
	}

	/**
	 * Creates a SQL command for adding a foreign key constraint to an existing table.
	 * The method will properly quote the table and column names.
	 * @param string $name the name of the foreign key constraint.
	 * @param string $table the table that the foreign key constraint will be added to.
	 * @param string $columns the name of the column to that the constraint will be added on. If there are multiple columns, separate them with commas.
	 * @param string $refTable the table that the foreign key references to.
	 * @param string $refColumns the name of the column that the foreign key references to. If there are multiple columns, separate them with commas.
	 * @param string $delete the ON DELETE option. Most DBMS support these options: RESTRICT, CASCADE, NO ACTION, SET DEFAULT, SET NULL
	 * @param string $update the ON UPDATE option. Most DBMS support these options: RESTRICT, CASCADE, NO ACTION, SET DEFAULT, SET NULL
	 * @return Command the command object itself
	 */
	public function addForeignKey($name, $table, $columns, $refTable, $refColumns, $delete = null, $update = null)
	{
		$sql = $this->connection->getQueryBuilder()->addForeignKey($name, $table, $columns, $refTable, $refColumns, $delete, $update);
		return $this->setSql($sql);
	}

	/**
	 * Creates a SQL command for dropping a foreign key constraint.
	 * @param string $name the name of the foreign key constraint to be dropped. The name will be properly quoted by the method.
	 * @param string $table the table whose foreign is to be dropped. The name will be properly quoted by the method.
	 * @return Command the command object itself
	 */
	public function dropForeignKey($name, $table)
	{
		$sql = $this->connection->getQueryBuilder()->dropForeignKey($name, $table);
		return $this->setSql($sql);
	}

	/**
	 * Creates a SQL command for creating a new index.
	 * @param string $name the name of the index. The name will be properly quoted by the method.
	 * @param string $table the table that the new index will be created for. The table name will be properly quoted by the method.
	 * @param string $columns the column(s) that should be included in the index. If there are multiple columns, please separate them
	 * by commas. The column names will be properly quoted by the method.
	 * @param boolean $unique whether to add UNIQUE constraint on the created index.
	 * @return Command the command object itself
	 */
	public function createIndex($name, $table, $columns, $unique = false)
	{
		$sql = $this->connection->getQueryBuilder()->createIndex($name, $table, $columns, $unique);
		return $this->setSql($sql);
	}

	/**
	 * Creates a SQL command for dropping an index.
	 * @param string $name the name of the index to be dropped. The name will be properly quoted by the method.
	 * @param string $table the table whose index is to be dropped. The name will be properly quoted by the method.
	 * @return Command the command object itself
	 */
	public function dropIndex($name, $table)
	{
		$sql = $this->connection->getQueryBuilder()->dropIndex($name, $table);
		return $this->setSql($sql);
	}
w  
Qiang Xue committed
669
}