No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

848 líneas
33KB

  1. <?php
  2. /**
  3. * @link http://www.yiiframework.com/
  4. * @copyright Copyright (c) 2008 Yii Software LLC
  5. * @license http://www.yiiframework.com/license/
  6. */
  7. namespace yii\db;
  8. use Yii;
  9. use yii\base\Component;
  10. use yii\base\NotSupportedException;
  11. /**
  12. * Command represents a SQL statement to be executed against a database.
  13. *
  14. * A command object is usually created by calling [[Connection::createCommand()]].
  15. * The SQL statement it represents can be set via the [[sql]] property.
  16. *
  17. * To execute a non-query SQL (such as INSERT, DELETE, UPDATE), call [[execute()]].
  18. * To execute a SQL statement that returns result data set (such as SELECT),
  19. * use [[queryAll()]], [[queryOne()]], [[queryColumn()]], [[queryScalar()]], or [[query()]].
  20. * For example,
  21. *
  22. * ~~~
  23. * $users = $connection->createCommand('SELECT * FROM user')->queryAll();
  24. * ~~~
  25. *
  26. * Command supports SQL statement preparation and parameter binding.
  27. * Call [[bindValue()]] to bind a value to a SQL parameter;
  28. * Call [[bindParam()]] to bind a PHP variable to a SQL parameter.
  29. * When binding a parameter, the SQL statement is automatically prepared.
  30. * You may also call [[prepare()]] explicitly to prepare a SQL statement.
  31. *
  32. * Command also supports building SQL statements by providing methods such as [[insert()]],
  33. * [[update()]], etc. For example,
  34. *
  35. * ~~~
  36. * $connection->createCommand()->insert('user', [
  37. * 'name' => 'Sam',
  38. * 'age' => 30,
  39. * ])->execute();
  40. * ~~~
  41. *
  42. * To build SELECT SQL statements, please use [[QueryBuilder]] instead.
  43. *
  44. * @property string $rawSql The raw SQL with parameter values inserted into the corresponding placeholders in
  45. * [[sql]]. This property is read-only.
  46. * @property string $sql The SQL statement to be executed.
  47. *
  48. * @author Qiang Xue <qiang.xue@gmail.com>
  49. * @since 2.0
  50. */
  51. class Command extends Component
  52. {
  53. /**
  54. * @var Connection the DB connection that this command is associated with
  55. */
  56. public $db;
  57. /**
  58. * @var \PDOStatement the PDOStatement object that this command is associated with
  59. */
  60. public $pdoStatement;
  61. /**
  62. * @var integer the default fetch mode for this command.
  63. * @see http://www.php.net/manual/en/function.PDOStatement-setFetchMode.php
  64. */
  65. public $fetchMode = \PDO::FETCH_ASSOC;
  66. /**
  67. * @var array the parameters (name => value) that are bound to the current PDO statement.
  68. * This property is maintained by methods such as [[bindValue()]]. It is mainly provided for logging purpose
  69. * and is used to generate [[rawSql]]. Do not modify it directly.
  70. */
  71. public $params = [];
  72. /**
  73. * @var integer the default number of seconds that query results can remain valid in cache.
  74. * Use 0 to indicate that the cached data will never expire. And use a negative number to indicate
  75. * query cache should not be used.
  76. * @see cache()
  77. */
  78. public $queryCacheDuration;
  79. /**
  80. * @var \yii\caching\Dependency the dependency to be associated with the cached query result for this command
  81. * @see cache()
  82. */
  83. public $queryCacheDependency;
  84. /**
  85. * @var array pending parameters to be bound to the current PDO statement.
  86. */
  87. private $_pendingParams = [];
  88. /**
  89. * @var string the SQL statement that this command represents
  90. */
  91. private $_sql;
  92. /**
  93. * Enables query cache for this command.
  94. * @param integer $duration the number of seconds that query result of this command can remain valid in the cache.
  95. * If this is not set, the value of [[Connection::queryCacheDuration]] will be used instead.
  96. * Use 0 to indicate that the cached data will never expire.
  97. * @param \yii\caching\Dependency $dependency the cache dependency associated with the cached query result.
  98. * @return static the command object itself
  99. */
  100. public function cache($duration = null, $dependency = null)
  101. {
  102. $this->queryCacheDuration = $duration === null ? $this->db->queryCacheDuration : $duration;
  103. $this->queryCacheDependency = $dependency;
  104. return $this;
  105. }
  106. /**
  107. * Disables query cache for this command.
  108. * @return static the command object itself
  109. */
  110. public function noCache()
  111. {
  112. $this->queryCacheDuration = -1;
  113. return $this;
  114. }
  115. /**
  116. * Returns the SQL statement for this command.
  117. * @return string the SQL statement to be executed
  118. */
  119. public function getSql()
  120. {
  121. return $this->_sql;
  122. }
  123. /**
  124. * Specifies the SQL statement to be executed.
  125. * The previous SQL execution (if any) will be cancelled, and [[params]] will be cleared as well.
  126. * @param string $sql the SQL statement to be set.
  127. * @return static this command instance
  128. */
  129. public function setSql($sql)
  130. {
  131. if ($sql !== $this->_sql) {
  132. $this->cancel();
  133. $this->_sql = $this->db->quoteSql($sql);
  134. $this->_pendingParams = [];
  135. $this->params = [];
  136. }
  137. return $this;
  138. }
  139. /**
  140. * Returns the raw SQL by inserting parameter values into the corresponding placeholders in [[sql]].
  141. * Note that the return value of this method should mainly be used for logging purpose.
  142. * It is likely that this method returns an invalid SQL due to improper replacement of parameter placeholders.
  143. * @return string the raw SQL with parameter values inserted into the corresponding placeholders in [[sql]].
  144. */
  145. public function getRawSql()
  146. {
  147. if (empty($this->params)) {
  148. return $this->_sql;
  149. } else {
  150. $params = [];
  151. foreach ($this->params as $name => $value) {
  152. if (is_string($value)) {
  153. $params[$name] = $this->db->quoteValue($value);
  154. } elseif ($value === null) {
  155. $params[$name] = 'NULL';
  156. } else {
  157. $params[$name] = $value;
  158. }
  159. }
  160. if (isset($params[1])) {
  161. $sql = '';
  162. foreach (explode('?', $this->_sql) as $i => $part) {
  163. $sql .= (isset($params[$i]) ? $params[$i] : '') . $part;
  164. }
  165. return $sql;
  166. } else {
  167. return strtr($this->_sql, $params);
  168. }
  169. }
  170. }
  171. /**
  172. * Prepares the SQL statement to be executed.
  173. * For complex SQL statement that is to be executed multiple times,
  174. * this may improve performance.
  175. * For SQL statement with binding parameters, this method is invoked
  176. * automatically.
  177. * @param boolean $forRead whether this method is called for a read query. If null, it means
  178. * the SQL statement should be used to determine whether it is for read or write.
  179. * @throws Exception if there is any DB error
  180. */
  181. public function prepare($forRead = null)
  182. {
  183. if ($this->pdoStatement) {
  184. $this->bindPendingParams();
  185. return;
  186. }
  187. $sql = $this->getSql();
  188. if ($this->db->getTransaction()) {
  189. // master is in a transaction. use the same connection.
  190. $forRead = false;
  191. }
  192. if ($forRead || $forRead === null && $this->db->getSchema()->isReadQuery($sql)) {
  193. $pdo = $this->db->getSlavePdo();
  194. } else {
  195. $pdo = $this->db->getMasterPdo();
  196. }
  197. try {
  198. $this->pdoStatement = $pdo->prepare($sql);
  199. $this->bindPendingParams();
  200. } catch (\Exception $e) {
  201. $message = $e->getMessage() . "\nFailed to prepare SQL: $sql";
  202. $errorInfo = $e instanceof \PDOException ? $e->errorInfo : null;
  203. throw new Exception($message, $errorInfo, (int) $e->getCode(), $e);
  204. }
  205. }
  206. /**
  207. * Cancels the execution of the SQL statement.
  208. * This method mainly sets [[pdoStatement]] to be null.
  209. */
  210. public function cancel()
  211. {
  212. $this->pdoStatement = null;
  213. }
  214. /**
  215. * Binds a parameter to the SQL statement to be executed.
  216. * @param string|integer $name parameter identifier. For a prepared statement
  217. * using named placeholders, this will be a parameter name of
  218. * the form `:name`. For a prepared statement using question mark
  219. * placeholders, this will be the 1-indexed position of the parameter.
  220. * @param mixed $value Name of the PHP variable to bind to the SQL statement parameter
  221. * @param integer $dataType SQL data type of the parameter. If null, the type is determined by the PHP type of the value.
  222. * @param integer $length length of the data type
  223. * @param mixed $driverOptions the driver-specific options
  224. * @return static the current command being executed
  225. * @see http://www.php.net/manual/en/function.PDOStatement-bindParam.php
  226. */
  227. public function bindParam($name, &$value, $dataType = null, $length = null, $driverOptions = null)
  228. {
  229. $this->prepare();
  230. if ($dataType === null) {
  231. $dataType = $this->db->getSchema()->getPdoType($value);
  232. }
  233. if ($length === null) {
  234. $this->pdoStatement->bindParam($name, $value, $dataType);
  235. } elseif ($driverOptions === null) {
  236. $this->pdoStatement->bindParam($name, $value, $dataType, $length);
  237. } else {
  238. $this->pdoStatement->bindParam($name, $value, $dataType, $length, $driverOptions);
  239. }
  240. $this->params[$name] =& $value;
  241. return $this;
  242. }
  243. /**
  244. * Binds pending parameters that were registered via [[bindValue()]] and [[bindValues()]].
  245. * Note that this method requires an active [[pdoStatement]].
  246. */
  247. protected function bindPendingParams()
  248. {
  249. foreach ($this->_pendingParams as $name => $value) {
  250. $this->pdoStatement->bindValue($name, $value[0], $value[1]);
  251. }
  252. $this->_pendingParams = [];
  253. }
  254. /**
  255. * Binds a value to a parameter.
  256. * @param string|integer $name Parameter identifier. For a prepared statement
  257. * using named placeholders, this will be a parameter name of
  258. * the form `:name`. For a prepared statement using question mark
  259. * placeholders, this will be the 1-indexed position of the parameter.
  260. * @param mixed $value The value to bind to the parameter
  261. * @param integer $dataType SQL data type of the parameter. If null, the type is determined by the PHP type of the value.
  262. * @return static the current command being executed
  263. * @see http://www.php.net/manual/en/function.PDOStatement-bindValue.php
  264. */
  265. public function bindValue($name, $value, $dataType = null)
  266. {
  267. if ($dataType === null) {
  268. $dataType = $this->db->getSchema()->getPdoType($value);
  269. }
  270. $this->_pendingParams[$name] = [$value, $dataType];
  271. $this->params[$name] = $value;
  272. return $this;
  273. }
  274. /**
  275. * Binds a list of values to the corresponding parameters.
  276. * This is similar to [[bindValue()]] except that it binds multiple values at a time.
  277. * Note that the SQL data type of each value is determined by its PHP type.
  278. * @param array $values the values to be bound. This must be given in terms of an associative
  279. * array with array keys being the parameter names, and array values the corresponding parameter values,
  280. * e.g. `[':name' => 'John', ':age' => 25]`. By default, the PDO type of each value is determined
  281. * by its PHP type. You may explicitly specify the PDO type by using an array: `[value, type]`,
  282. * e.g. `[':name' => 'John', ':profile' => [$profile, \PDO::PARAM_LOB]]`.
  283. * @return static the current command being executed
  284. */
  285. public function bindValues($values)
  286. {
  287. if (empty($values)) {
  288. return $this;
  289. }
  290. foreach ($values as $name => $value) {
  291. if (is_array($value)) {
  292. $this->_pendingParams[$name] = $value;
  293. $this->params[$name] = $value[0];
  294. } else {
  295. $type = $this->db->getSchema()->getPdoType($value);
  296. $this->_pendingParams[$name] = [$value, $type];
  297. $this->params[$name] = $value;
  298. }
  299. }
  300. return $this;
  301. }
  302. /**
  303. * Executes the SQL statement and returns query result.
  304. * This method is for executing a SQL query that returns result set, such as `SELECT`.
  305. * @return DataReader the reader object for fetching the query result
  306. * @throws Exception execution failed
  307. */
  308. public function query()
  309. {
  310. return $this->queryInternal('');
  311. }
  312. /**
  313. * Executes the SQL statement and returns ALL rows at once.
  314. * @param integer $fetchMode the result fetch mode. Please refer to [PHP manual](http://www.php.net/manual/en/function.PDOStatement-setFetchMode.php)
  315. * for valid fetch modes. If this parameter is null, the value set in [[fetchMode]] will be used.
  316. * @return array all rows of the query result. Each array element is an array representing a row of data.
  317. * An empty array is returned if the query results in nothing.
  318. * @throws Exception execution failed
  319. */
  320. public function queryAll($fetchMode = null)
  321. {
  322. return $this->queryInternal('fetchAll', $fetchMode);
  323. }
  324. /**
  325. * Executes the SQL statement and returns the first row of the result.
  326. * This method is best used when only the first row of result is needed for a query.
  327. * @param integer $fetchMode the result fetch mode. Please refer to [PHP manual](http://www.php.net/manual/en/function.PDOStatement-setFetchMode.php)
  328. * for valid fetch modes. If this parameter is null, the value set in [[fetchMode]] will be used.
  329. * @return array|boolean the first row (in terms of an array) of the query result. False is returned if the query
  330. * results in nothing.
  331. * @throws Exception execution failed
  332. */
  333. public function queryOne($fetchMode = null)
  334. {
  335. return $this->queryInternal('fetch', $fetchMode);
  336. }
  337. /**
  338. * Executes the SQL statement and returns the value of the first column in the first row of data.
  339. * This method is best used when only a single value is needed for a query.
  340. * @return string|null|boolean the value of the first column in the first row of the query result.
  341. * False is returned if there is no value.
  342. * @throws Exception execution failed
  343. */
  344. public function queryScalar()
  345. {
  346. $result = $this->queryInternal('fetchColumn', 0);
  347. if (is_resource($result) && get_resource_type($result) === 'stream') {
  348. return stream_get_contents($result);
  349. } else {
  350. return $result;
  351. }
  352. }
  353. /**
  354. * Executes the SQL statement and returns the first column of the result.
  355. * This method is best used when only the first column of result (i.e. the first element in each row)
  356. * is needed for a query.
  357. * @return array the first column of the query result. Empty array is returned if the query results in nothing.
  358. * @throws Exception execution failed
  359. */
  360. public function queryColumn()
  361. {
  362. return $this->queryInternal('fetchAll', \PDO::FETCH_COLUMN);
  363. }
  364. /**
  365. * Creates an INSERT command.
  366. * For example,
  367. *
  368. * ~~~
  369. * $connection->createCommand()->insert('user', [
  370. * 'name' => 'Sam',
  371. * 'age' => 30,
  372. * ])->execute();
  373. * ~~~
  374. *
  375. * The method will properly escape the column names, and bind the values to be inserted.
  376. *
  377. * Note that the created command is not executed until [[execute()]] is called.
  378. *
  379. * @param string $table the table that new rows will be inserted into.
  380. * @param array $columns the column data (name => value) to be inserted into the table.
  381. * @return Command the command object itself
  382. */
  383. public function insert($table, $columns)
  384. {
  385. $params = [];
  386. $sql = $this->db->getQueryBuilder()->insert($table, $columns, $params);
  387. return $this->setSql($sql)->bindValues($params);
  388. }
  389. /**
  390. * Creates a batch INSERT command.
  391. * For example,
  392. *
  393. * ~~~
  394. * $connection->createCommand()->batchInsert('user', ['name', 'age'], [
  395. * ['Tom', 30],
  396. * ['Jane', 20],
  397. * ['Linda', 25],
  398. * ])->execute();
  399. * ~~~
  400. *
  401. * Note that the values in each row must match the corresponding column names.
  402. *
  403. * @param string $table the table that new rows will be inserted into.
  404. * @param array $columns the column names
  405. * @param array $rows the rows to be batch inserted into the table
  406. * @return Command the command object itself
  407. */
  408. public function batchInsert($table, $columns, $rows)
  409. {
  410. $sql = $this->db->getQueryBuilder()->batchInsert($table, $columns, $rows);
  411. return $this->setSql($sql);
  412. }
  413. /**
  414. * Creates an UPDATE command.
  415. * For example,
  416. *
  417. * ~~~
  418. * $connection->createCommand()->update('user', ['status' => 1], 'age > 30')->execute();
  419. * ~~~
  420. *
  421. * The method will properly escape the column names and bind the values to be updated.
  422. *
  423. * Note that the created command is not executed until [[execute()]] is called.
  424. *
  425. * @param string $table the table to be updated.
  426. * @param array $columns the column data (name => value) to be updated.
  427. * @param string|array $condition the condition that will be put in the WHERE part. Please
  428. * refer to [[Query::where()]] on how to specify condition.
  429. * @param array $params the parameters to be bound to the command
  430. * @return Command the command object itself
  431. */
  432. public function update($table, $columns, $condition = '', $params = [])
  433. {
  434. $sql = $this->db->getQueryBuilder()->update($table, $columns, $condition, $params);
  435. return $this->setSql($sql)->bindValues($params);
  436. }
  437. /**
  438. * Creates a DELETE command.
  439. * For example,
  440. *
  441. * ~~~
  442. * $connection->createCommand()->delete('user', 'status = 0')->execute();
  443. * ~~~
  444. *
  445. * The method will properly escape the table and column names.
  446. *
  447. * Note that the created command is not executed until [[execute()]] is called.
  448. *
  449. * @param string $table the table where the data will be deleted from.
  450. * @param string|array $condition the condition that will be put in the WHERE part. Please
  451. * refer to [[Query::where()]] on how to specify condition.
  452. * @param array $params the parameters to be bound to the command
  453. * @return Command the command object itself
  454. */
  455. public function delete($table, $condition = '', $params = [])
  456. {
  457. $sql = $this->db->getQueryBuilder()->delete($table, $condition, $params);
  458. return $this->setSql($sql)->bindValues($params);
  459. }
  460. /**
  461. * Creates a SQL command for creating a new DB table.
  462. *
  463. * The columns in the new table should be specified as name-definition pairs (e.g. 'name' => 'string'),
  464. * where name stands for a column name which will be properly quoted by the method, and definition
  465. * stands for the column type which can contain an abstract DB type.
  466. * The method [[QueryBuilder::getColumnType()]] will be called
  467. * to convert the abstract column types to physical ones. For example, `string` will be converted
  468. * as `varchar(255)`, and `string not null` becomes `varchar(255) not null`.
  469. *
  470. * If a column is specified with definition only (e.g. 'PRIMARY KEY (name, type)'), it will be directly
  471. * inserted into the generated SQL.
  472. *
  473. * @param string $table the name of the table to be created. The name will be properly quoted by the method.
  474. * @param array $columns the columns (name => definition) in the new table.
  475. * @param string $options additional SQL fragment that will be appended to the generated SQL.
  476. * @return Command the command object itself
  477. */
  478. public function createTable($table, $columns, $options = null)
  479. {
  480. $sql = $this->db->getQueryBuilder()->createTable($table, $columns, $options);
  481. return $this->setSql($sql);
  482. }
  483. /**
  484. * Creates a SQL command for renaming a DB table.
  485. * @param string $table the table to be renamed. The name will be properly quoted by the method.
  486. * @param string $newName the new table name. The name will be properly quoted by the method.
  487. * @return Command the command object itself
  488. */
  489. public function renameTable($table, $newName)
  490. {
  491. $sql = $this->db->getQueryBuilder()->renameTable($table, $newName);
  492. return $this->setSql($sql);
  493. }
  494. /**
  495. * Creates a SQL command for dropping a DB table.
  496. * @param string $table the table to be dropped. The name will be properly quoted by the method.
  497. * @return Command the command object itself
  498. */
  499. public function dropTable($table)
  500. {
  501. $sql = $this->db->getQueryBuilder()->dropTable($table);
  502. return $this->setSql($sql);
  503. }
  504. /**
  505. * Creates a SQL command for truncating a DB table.
  506. * @param string $table the table to be truncated. The name will be properly quoted by the method.
  507. * @return Command the command object itself
  508. */
  509. public function truncateTable($table)
  510. {
  511. $sql = $this->db->getQueryBuilder()->truncateTable($table);
  512. return $this->setSql($sql);
  513. }
  514. /**
  515. * Creates a SQL command for adding a new DB column.
  516. * @param string $table the table that the new column will be added to. The table name will be properly quoted by the method.
  517. * @param string $column the name of the new column. The name will be properly quoted by the method.
  518. * @param string $type the column type. [[\yii\db\QueryBuilder::getColumnType()]] will be called
  519. * to convert the give column type to the physical one. For example, `string` will be converted
  520. * as `varchar(255)`, and `string not null` becomes `varchar(255) not null`.
  521. * @return Command the command object itself
  522. */
  523. public function addColumn($table, $column, $type)
  524. {
  525. $sql = $this->db->getQueryBuilder()->addColumn($table, $column, $type);
  526. return $this->setSql($sql);
  527. }
  528. /**
  529. * Creates a SQL command for dropping a DB column.
  530. * @param string $table the table whose column is to be dropped. The name will be properly quoted by the method.
  531. * @param string $column the name of the column to be dropped. The name will be properly quoted by the method.
  532. * @return Command the command object itself
  533. */
  534. public function dropColumn($table, $column)
  535. {
  536. $sql = $this->db->getQueryBuilder()->dropColumn($table, $column);
  537. return $this->setSql($sql);
  538. }
  539. /**
  540. * Creates a SQL command for renaming a column.
  541. * @param string $table the table whose column is to be renamed. The name will be properly quoted by the method.
  542. * @param string $oldName the old name of the column. The name will be properly quoted by the method.
  543. * @param string $newName the new name of the column. The name will be properly quoted by the method.
  544. * @return Command the command object itself
  545. */
  546. public function renameColumn($table, $oldName, $newName)
  547. {
  548. $sql = $this->db->getQueryBuilder()->renameColumn($table, $oldName, $newName);
  549. return $this->setSql($sql);
  550. }
  551. /**
  552. * Creates a SQL command for changing the definition of a column.
  553. * @param string $table the table whose column is to be changed. The table name will be properly quoted by the method.
  554. * @param string $column the name of the column to be changed. The name will be properly quoted by the method.
  555. * @param string $type the column type. [[\yii\db\QueryBuilder::getColumnType()]] will be called
  556. * to convert the give column type to the physical one. For example, `string` will be converted
  557. * as `varchar(255)`, and `string not null` becomes `varchar(255) not null`.
  558. * @return Command the command object itself
  559. */
  560. public function alterColumn($table, $column, $type)
  561. {
  562. $sql = $this->db->getQueryBuilder()->alterColumn($table, $column, $type);
  563. return $this->setSql($sql);
  564. }
  565. /**
  566. * Creates a SQL command for adding a primary key constraint to an existing table.
  567. * The method will properly quote the table and column names.
  568. * @param string $name the name of the primary key constraint.
  569. * @param string $table the table that the primary key constraint will be added to.
  570. * @param string|array $columns comma separated string or array of columns that the primary key will consist of.
  571. * @return Command the command object itself.
  572. */
  573. public function addPrimaryKey($name, $table, $columns)
  574. {
  575. $sql = $this->db->getQueryBuilder()->addPrimaryKey($name, $table, $columns);
  576. return $this->setSql($sql);
  577. }
  578. /**
  579. * Creates a SQL command for removing a primary key constraint to an existing table.
  580. * @param string $name the name of the primary key constraint to be removed.
  581. * @param string $table the table that the primary key constraint will be removed from.
  582. * @return Command the command object itself
  583. */
  584. public function dropPrimaryKey($name, $table)
  585. {
  586. $sql = $this->db->getQueryBuilder()->dropPrimaryKey($name, $table);
  587. return $this->setSql($sql);
  588. }
  589. /**
  590. * Creates a SQL command for adding a foreign key constraint to an existing table.
  591. * The method will properly quote the table and column names.
  592. * @param string $name the name of the foreign key constraint.
  593. * @param string $table the table that the foreign key constraint will be added to.
  594. * @param string|array $columns the name of the column to that the constraint will be added on. If there are multiple columns, separate them with commas.
  595. * @param string $refTable the table that the foreign key references to.
  596. * @param string|array $refColumns the name of the column that the foreign key references to. If there are multiple columns, separate them with commas.
  597. * @param string $delete the ON DELETE option. Most DBMS support these options: RESTRICT, CASCADE, NO ACTION, SET DEFAULT, SET NULL
  598. * @param string $update the ON UPDATE option. Most DBMS support these options: RESTRICT, CASCADE, NO ACTION, SET DEFAULT, SET NULL
  599. * @return Command the command object itself
  600. */
  601. public function addForeignKey($name, $table, $columns, $refTable, $refColumns, $delete = null, $update = null)
  602. {
  603. $sql = $this->db->getQueryBuilder()->addForeignKey($name, $table, $columns, $refTable, $refColumns, $delete, $update);
  604. return $this->setSql($sql);
  605. }
  606. /**
  607. * Creates a SQL command for dropping a foreign key constraint.
  608. * @param string $name the name of the foreign key constraint to be dropped. The name will be properly quoted by the method.
  609. * @param string $table the table whose foreign is to be dropped. The name will be properly quoted by the method.
  610. * @return Command the command object itself
  611. */
  612. public function dropForeignKey($name, $table)
  613. {
  614. $sql = $this->db->getQueryBuilder()->dropForeignKey($name, $table);
  615. return $this->setSql($sql);
  616. }
  617. /**
  618. * Creates a SQL command for creating a new index.
  619. * @param string $name the name of the index. The name will be properly quoted by the method.
  620. * @param string $table the table that the new index will be created for. The table name will be properly quoted by the method.
  621. * @param string|array $columns the column(s) that should be included in the index. If there are multiple columns, please separate them
  622. * by commas. The column names will be properly quoted by the method.
  623. * @param boolean $unique whether to add UNIQUE constraint on the created index.
  624. * @return Command the command object itself
  625. */
  626. public function createIndex($name, $table, $columns, $unique = false)
  627. {
  628. $sql = $this->db->getQueryBuilder()->createIndex($name, $table, $columns, $unique);
  629. return $this->setSql($sql);
  630. }
  631. /**
  632. * Creates a SQL command for dropping an index.
  633. * @param string $name the name of the index to be dropped. The name will be properly quoted by the method.
  634. * @param string $table the table whose index is to be dropped. The name will be properly quoted by the method.
  635. * @return Command the command object itself
  636. */
  637. public function dropIndex($name, $table)
  638. {
  639. $sql = $this->db->getQueryBuilder()->dropIndex($name, $table);
  640. return $this->setSql($sql);
  641. }
  642. /**
  643. * Creates a SQL command for resetting the sequence value of a table's primary key.
  644. * The sequence will be reset such that the primary key of the next new row inserted
  645. * will have the specified value or 1.
  646. * @param string $table the name of the table whose primary key sequence will be reset
  647. * @param mixed $value the value for the primary key of the next new row inserted. If this is not set,
  648. * the next new row's primary key will have a value 1.
  649. * @return Command the command object itself
  650. * @throws NotSupportedException if this is not supported by the underlying DBMS
  651. */
  652. public function resetSequence($table, $value = null)
  653. {
  654. $sql = $this->db->getQueryBuilder()->resetSequence($table, $value);
  655. return $this->setSql($sql);
  656. }
  657. /**
  658. * Builds a SQL command for enabling or disabling integrity check.
  659. * @param boolean $check whether to turn on or off the integrity check.
  660. * @param string $schema the schema name of the tables. Defaults to empty string, meaning the current
  661. * or default schema.
  662. * @param string $table the table name.
  663. * @return Command the command object itself
  664. * @throws NotSupportedException if this is not supported by the underlying DBMS
  665. */
  666. public function checkIntegrity($check = true, $schema = '', $table = '')
  667. {
  668. $sql = $this->db->getQueryBuilder()->checkIntegrity($check, $schema, $table);
  669. return $this->setSql($sql);
  670. }
  671. /**
  672. * Executes the SQL statement.
  673. * This method should only be used for executing non-query SQL statement, such as `INSERT`, `DELETE`, `UPDATE` SQLs.
  674. * No result set will be returned.
  675. * @return integer number of rows affected by the execution.
  676. * @throws Exception execution failed
  677. */
  678. public function execute()
  679. {
  680. $sql = $this->getSql();
  681. $rawSql = $this->getRawSql();
  682. Yii::info($rawSql, __METHOD__);
  683. if ($sql == '') {
  684. return 0;
  685. }
  686. $this->prepare(false);
  687. $token = $rawSql;
  688. try {
  689. Yii::beginProfile($token, __METHOD__);
  690. $this->pdoStatement->execute();
  691. $n = $this->pdoStatement->rowCount();
  692. Yii::endProfile($token, __METHOD__);
  693. return $n;
  694. } catch (\Exception $e) {
  695. Yii::endProfile($token, __METHOD__);
  696. throw $this->db->getSchema()->convertException($e, $rawSql);
  697. }
  698. }
  699. /**
  700. * Performs the actual DB query of a SQL statement.
  701. * @param string $method method of PDOStatement to be called
  702. * @param integer $fetchMode the result fetch mode. Please refer to [PHP manual](http://www.php.net/manual/en/function.PDOStatement-setFetchMode.php)
  703. * for valid fetch modes. If this parameter is null, the value set in [[fetchMode]] will be used.
  704. * @return mixed the method execution result
  705. * @throws Exception if the query causes any problem
  706. * @since 2.0.1 this method is protected (was private before).
  707. */
  708. protected function queryInternal($method, $fetchMode = null)
  709. {
  710. $rawSql = $this->getRawSql();
  711. Yii::info($rawSql, 'yii\db\Command::query');
  712. if ($method !== '') {
  713. $info = $this->db->getQueryCacheInfo($this->queryCacheDuration, $this->queryCacheDependency);
  714. if (is_array($info)) {
  715. /* @var $cache \yii\caching\Cache */
  716. $cache = $info[0];
  717. $cacheKey = [
  718. __CLASS__,
  719. $method,
  720. $fetchMode,
  721. $this->db->dsn,
  722. $this->db->username,
  723. $rawSql,
  724. ];
  725. $result = $cache->get($cacheKey);
  726. if (is_array($result) && isset($result[0])) {
  727. Yii::trace('Query result served from cache', 'yii\db\Command::query');
  728. return $result[0];
  729. }
  730. }
  731. }
  732. $this->prepare(true);
  733. $token = $rawSql;
  734. try {
  735. Yii::beginProfile($token, 'yii\db\Command::query');
  736. $this->pdoStatement->execute();
  737. if ($method === '') {
  738. $result = new DataReader($this);
  739. } else {
  740. if ($fetchMode === null) {
  741. $fetchMode = $this->fetchMode;
  742. }
  743. $result = call_user_func_array([$this->pdoStatement, $method], (array) $fetchMode);
  744. $this->pdoStatement->closeCursor();
  745. }
  746. Yii::endProfile($token, 'yii\db\Command::query');
  747. } catch (\Exception $e) {
  748. Yii::endProfile($token, 'yii\db\Command::query');
  749. throw $this->db->getSchema()->convertException($e, $rawSql);
  750. }
  751. if (isset($cache, $cacheKey, $info)) {
  752. $cache->set($cacheKey, [$result], $info[1], $info[2]);
  753. Yii::trace('Saved query result in cache', 'yii\db\Command::query');
  754. }
  755. return $result;
  756. }
  757. }