GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( ecd2dc...aafa57 )
by Robert
18:49
created

Command::execute()   B

Complexity

Conditions 3
Paths 7

Size

Total Lines 31
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 3

Importance

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