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 ( c73de3...97c43c )
by Robert
13:22
created

Schema::getTableSchema()   D

Complexity

Conditions 10
Paths 7

Size

Total Lines 31
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 10.0862

Importance

Changes 0
Metric Value
dl 0
loc 31
rs 4.8196
c 0
b 0
f 0
ccs 19
cts 21
cp 0.9048
cc 10
eloc 18
nc 7
nop 2
crap 10.0862

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\Object;
12
use yii\base\NotSupportedException;
13
use yii\base\InvalidCallException;
14
use yii\caching\Cache;
15
use yii\caching\TagDependency;
16
17
/**
18
 * Schema is the base class for concrete DBMS-specific schema classes.
19
 *
20
 * Schema represents the database schema information that is DBMS specific.
21
 *
22
 * @property string $lastInsertID The row ID of the last row inserted, or the last value retrieved from the
23
 * sequence object. This property is read-only.
24
 * @property QueryBuilder $queryBuilder The query builder for this connection. This property is read-only.
25
 * @property string[] $schemaNames All schema names in the database, except system schemas. This property is
26
 * read-only.
27
 * @property string[] $tableNames All table names in the database. This property is read-only.
28
 * @property TableSchema[] $tableSchemas The metadata for all tables in the database. Each array element is an
29
 * instance of [[TableSchema]] or its child class. This property is read-only.
30
 * @property string $transactionIsolationLevel The transaction isolation level to use for this transaction.
31
 * This can be one of [[Transaction::READ_UNCOMMITTED]], [[Transaction::READ_COMMITTED]],
32
 * [[Transaction::REPEATABLE_READ]] and [[Transaction::SERIALIZABLE]] but also a string containing DBMS specific
33
 * syntax to be used after `SET TRANSACTION ISOLATION LEVEL`. This property is write-only.
34
 *
35
 * @author Qiang Xue <[email protected]>
36
 * @since 2.0
37
 */
38
abstract class Schema extends Object
39
{
40
    // The following are the supported abstract column data types.
41
    const TYPE_PK = 'pk';
42
    const TYPE_UPK = 'upk';
43
    const TYPE_BIGPK = 'bigpk';
44
    const TYPE_UBIGPK = 'ubigpk';
45
    const TYPE_CHAR = 'char';
46
    const TYPE_STRING = 'string';
47
    const TYPE_TEXT = 'text';
48
    const TYPE_SMALLINT = 'smallint';
49
    const TYPE_INTEGER = 'integer';
50
    const TYPE_BIGINT = 'bigint';
51
    const TYPE_FLOAT = 'float';
52
    const TYPE_DOUBLE = 'double';
53
    const TYPE_DECIMAL = 'decimal';
54
    const TYPE_DATETIME = 'datetime';
55
    const TYPE_TIMESTAMP = 'timestamp';
56
    const TYPE_TIME = 'time';
57
    const TYPE_DATE = 'date';
58
    const TYPE_BINARY = 'binary';
59
    const TYPE_BOOLEAN = 'boolean';
60
    const TYPE_MONEY = 'money';
61
62
    /**
63
     * @var Connection the database connection
64
     */
65
    public $db;
66
    /**
67
     * @var string the default schema name used for the current session.
68
     */
69
    public $defaultSchema;
70
    /**
71
     * @var array map of DB errors and corresponding exceptions
72
     * If left part is found in DB error message exception class from the right part is used.
73
     */
74
    public $exceptionMap = [
75
        'SQLSTATE[23' => 'yii\db\IntegrityException',
76
    ];
77
    /**
78
     * @var string column schema class
79
     * @since 2.0.11
80
     */
81
    public $columnSchemaClass = 'yii\db\ColumnSchema';
82
83
    /**
84
     * @var array list of ALL schema names in the database, except system schemas
85
     */
86
    private $_schemaNames;
87
    /**
88
     * @var array list of ALL table names in the database
89
     */
90
    private $_tableNames = [];
91
    /**
92
     * @var array list of loaded table metadata (table name => TableSchema)
93
     */
94
    private $_tables = [];
95
    /**
96
     * @var QueryBuilder the query builder for this database
97
     */
98
    private $_builder;
99
100
101
    /**
102
     * @return \yii\db\ColumnSchema
103
     * @throws \yii\base\InvalidConfigException
104
     */
105 468
    protected function createColumnSchema()
106
    {
107 468
        return Yii::createObject($this->columnSchemaClass);
108
    }
109
110
    /**
111
     * Loads the metadata for the specified table.
112
     * @param string $name table name
113
     * @return null|TableSchema DBMS-dependent table metadata, null if the table does not exist.
114
     */
115
    abstract protected function loadTableSchema($name);
116
117
    /**
118
     * Obtains the metadata for the named table.
119
     * @param string $name table name. The table name may contain schema name if any. Do not quote the table name.
120
     * @param bool $refresh whether to reload the table schema even if it is found in the cache.
121
     * @return null|TableSchema table metadata. Null if the named table does not exist.
122
     */
123 560
    public function getTableSchema($name, $refresh = false)
124
    {
125 560
        if (array_key_exists($name, $this->_tables) && !$refresh) {
126 465
            return $this->_tables[$name];
127
        }
128
129 488
        $db = $this->db;
130 488
        $realName = $this->getRawTableName($name);
131
132 488
        if ($db->enableSchemaCache && !in_array($name, $db->schemaCacheExclude, true)) {
133
            /* @var $cache Cache */
134 7
            $cache = is_string($db->schemaCache) ? Yii::$app->get($db->schemaCache, false) : $db->schemaCache;
135 7
            if ($cache instanceof Cache) {
136 7
                $key = $this->getCacheKey($name);
137 7
                if ($refresh || ($table = $cache->get($key)) === false) {
138 7
                    $this->_tables[$name] = $table = $this->loadTableSchema($realName);
139 7
                    if ($table !== null) {
140 7
                        $cache->set($key, $table, $db->schemaCacheDuration, new TagDependency([
141 7
                            'tags' => $this->getCacheTag(),
142 7
                        ]));
143 7
                    }
144 7
                } else {
145
                    $this->_tables[$name] = $table;
146
                }
147
148 7
                return $this->_tables[$name];
149
            }
150
        }
151
152 481
        return $this->_tables[$name] = $this->loadTableSchema($realName);
153
    }
154
155
    /**
156
     * Returns the cache key for the specified table name.
157
     * @param string $name the table name
158
     * @return mixed the cache key
159
     */
160 7
    protected function getCacheKey($name)
161
    {
162
        return [
163 7
            __CLASS__,
164 7
            $this->db->dsn,
165 7
            $this->db->username,
166 7
            $name,
167 7
        ];
168
    }
169
170
    /**
171
     * Returns the cache tag name.
172
     * This allows [[refresh()]] to invalidate all cached table schemas.
173
     * @return string the cache tag name
174
     */
175 7
    protected function getCacheTag()
176
    {
177 7
        return md5(serialize([
178 7
            __CLASS__,
179 7
            $this->db->dsn,
180 7
            $this->db->username,
181 7
        ]));
182
    }
183
184
    /**
185
     * Returns the metadata for all tables in the database.
186
     * @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema name.
187
     * @param bool $refresh whether to fetch the latest available table schemas. If this is false,
188
     * cached data may be returned if available.
189
     * @return TableSchema[] the metadata for all tables in the database.
190
     * Each array element is an instance of [[TableSchema]] or its child class.
191
     */
192 10
    public function getTableSchemas($schema = '', $refresh = false)
193
    {
194 10
        $tables = [];
195 10
        foreach ($this->getTableNames($schema, $refresh) as $name) {
196 10
            if ($schema !== '') {
197
                $name = $schema . '.' . $name;
198
            }
199 10
            if (($table = $this->getTableSchema($name, $refresh)) !== null) {
200 10
                $tables[] = $table;
201 10
            }
202 10
        }
203
204 10
        return $tables;
205
    }
206
207
    /**
208
     * Returns all schema names in the database, except system schemas.
209
     * @param bool $refresh whether to fetch the latest available schema names. If this is false,
210
     * schema names fetched previously (if available) will be returned.
211
     * @return string[] all schema names in the database, except system schemas.
212
     * @since 2.0.4
213
     */
214 1
    public function getSchemaNames($refresh = false)
215
    {
216 1
        if ($this->_schemaNames === null || $refresh) {
217 1
            $this->_schemaNames = $this->findSchemaNames();
218 1
        }
219
220 1
        return $this->_schemaNames;
221
    }
222
223
    /**
224
     * Returns all table names in the database.
225
     * @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema name.
226
     * If not empty, the returned table names will be prefixed with the schema name.
227
     * @param bool $refresh whether to fetch the latest available table names. If this is false,
228
     * table names fetched previously (if available) will be returned.
229
     * @return string[] all table names in the database.
230
     */
231 18
    public function getTableNames($schema = '', $refresh = false)
232
    {
233 18
        if (!isset($this->_tableNames[$schema]) || $refresh) {
234 18
            $this->_tableNames[$schema] = $this->findTableNames($schema);
235 18
        }
236
237 18
        return $this->_tableNames[$schema];
238
    }
239
240
    /**
241
     * @return QueryBuilder the query builder for this connection.
242
     */
243 599
    public function getQueryBuilder()
244
    {
245 599
        if ($this->_builder === null) {
246 498
            $this->_builder = $this->createQueryBuilder();
247 498
        }
248
249 599
        return $this->_builder;
250
    }
251
252
    /**
253
     * Determines the PDO type for the given PHP data value.
254
     * @param mixed $data the data whose PDO type is to be determined
255
     * @return int the PDO type
256
     * @see http://www.php.net/manual/en/pdo.constants.php
257
     */
258 560
    public function getPdoType($data)
259
    {
260
        static $typeMap = [
261
            // php type => PDO type
262
            'boolean' => \PDO::PARAM_BOOL,
263
            'integer' => \PDO::PARAM_INT,
264
            'string' => \PDO::PARAM_STR,
265
            'resource' => \PDO::PARAM_LOB,
266
            'NULL' => \PDO::PARAM_NULL,
267 560
        ];
268 560
        $type = gettype($data);
269
270 560
        return isset($typeMap[$type]) ? $typeMap[$type] : \PDO::PARAM_STR;
271
    }
272
273
    /**
274
     * Refreshes the schema.
275
     * This method cleans up all cached table schemas so that they can be re-created later
276
     * to reflect the database schema change.
277
     */
278 14
    public function refresh()
279
    {
280
        /* @var $cache Cache */
281 14
        $cache = is_string($this->db->schemaCache) ? Yii::$app->get($this->db->schemaCache, false) : $this->db->schemaCache;
282 14
        if ($this->db->enableSchemaCache && $cache instanceof Cache) {
283 1
            TagDependency::invalidate($cache, $this->getCacheTag());
284 1
        }
285 14
        $this->_tableNames = [];
286 14
        $this->_tables = [];
287 14
    }
288
289
    /**
290
     * Refreshes the particular table schema.
291
     * This method cleans up cached table schema so that it can be re-created later
292
     * to reflect the database schema change.
293
     * @param string $name table name.
294
     * @since 2.0.6
295
     */
296 20
    public function refreshTableSchema($name)
297
    {
298 20
        unset($this->_tables[$name]);
299 20
        $this->_tableNames = [];
300
        /* @var $cache Cache */
301 20
        $cache = is_string($this->db->schemaCache) ? Yii::$app->get($this->db->schemaCache, false) : $this->db->schemaCache;
302 20
        if ($this->db->enableSchemaCache && $cache instanceof Cache) {
303 4
            $cache->delete($this->getCacheKey($name));
304 4
        }
305 20
    }
306
307
    /**
308
     * Creates a query builder for the database.
309
     * This method may be overridden by child classes to create a DBMS-specific query builder.
310
     * @return QueryBuilder query builder instance
311
     */
312
    public function createQueryBuilder()
313
    {
314
        return new QueryBuilder($this->db);
315
    }
316
317
    /**
318
     * Create a column schema builder instance giving the type and value precision.
319
     *
320
     * This method may be overridden by child classes to create a DBMS-specific column schema builder.
321
     *
322
     * @param string $type type of the column. See [[ColumnSchemaBuilder::$type]].
323
     * @param int|string|array $length length or precision of the column. See [[ColumnSchemaBuilder::$length]].
324
     * @return ColumnSchemaBuilder column schema builder instance
325
     * @since 2.0.6
326
     */
327 2
    public function createColumnSchemaBuilder($type, $length = null)
328
    {
329 2
        return new ColumnSchemaBuilder($type, $length);
330
    }
331
332
    /**
333
     * Returns all schema names in the database, including the default one but not system schemas.
334
     * This method should be overridden by child classes in order to support this feature
335
     * because the default implementation simply throws an exception.
336
     * @return array all schema names in the database, except system schemas
337
     * @throws NotSupportedException if this method is called
338
     * @since 2.0.4
339
     */
340
    protected function findSchemaNames()
341
    {
342
        throw new NotSupportedException(get_class($this) . ' does not support fetching all schema names.');
343
    }
344
345
    /**
346
     * Returns all table names in the database.
347
     * This method should be overridden by child classes in order to support this feature
348
     * because the default implementation simply throws an exception.
349
     * @param string $schema the schema of the tables. Defaults to empty string, meaning the current or default schema.
350
     * @return array all table names in the database. The names have NO schema name prefix.
351
     * @throws NotSupportedException if this method is called
352
     */
353
    protected function findTableNames($schema = '')
354
    {
355
        throw new NotSupportedException(get_class($this) . ' does not support fetching all table names.');
356
    }
357
358
    /**
359
     * Returns all unique indexes for the given table.
360
     * Each array element is of the following structure:
361
     *
362
     * ```php
363
     * [
364
     *  'IndexName1' => ['col1' [, ...]],
365
     *  'IndexName2' => ['col2' [, ...]],
366
     * ]
367
     * ```
368
     *
369
     * This method should be overridden by child classes in order to support this feature
370
     * because the default implementation simply throws an exception
371
     * @param TableSchema $table the table metadata
372
     * @return array all unique indexes for the given table.
373
     * @throws NotSupportedException if this method is called
374
     */
375
    public function findUniqueIndexes($table)
376
    {
377
        throw new NotSupportedException(get_class($this) . ' does not support getting unique indexes information.');
378
    }
379
380
    /**
381
     * Returns the ID of the last inserted row or sequence value.
382
     * @param string $sequenceName name of the sequence object (required by some DBMS)
383
     * @return string the row ID of the last row inserted, or the last value retrieved from the sequence object
384
     * @throws InvalidCallException if the DB connection is not active
385
     * @see http://www.php.net/manual/en/function.PDO-lastInsertId.php
386
     */
387 54
    public function getLastInsertID($sequenceName = '')
388
    {
389 54
        if ($this->db->isActive) {
390 54
            return $this->db->pdo->lastInsertId($sequenceName === '' ? null : $this->quoteTableName($sequenceName));
391
        } else {
392
            throw new InvalidCallException('DB Connection is not active.');
393
        }
394
    }
395
396
    /**
397
     * @return bool whether this DBMS supports [savepoint](http://en.wikipedia.org/wiki/Savepoint).
398
     */
399 3
    public function supportsSavepoint()
400
    {
401 3
        return $this->db->enableSavepoint;
402
    }
403
404
    /**
405
     * Creates a new savepoint.
406
     * @param string $name the savepoint name
407
     */
408 3
    public function createSavepoint($name)
409
    {
410 3
        $this->db->createCommand("SAVEPOINT $name")->execute();
411 3
    }
412
413
    /**
414
     * Releases an existing savepoint.
415
     * @param string $name the savepoint name
416
     */
417
    public function releaseSavepoint($name)
418
    {
419
        $this->db->createCommand("RELEASE SAVEPOINT $name")->execute();
420
    }
421
422
    /**
423
     * Rolls back to a previously created savepoint.
424
     * @param string $name the savepoint name
425
     */
426 3
    public function rollBackSavepoint($name)
427
    {
428 3
        $this->db->createCommand("ROLLBACK TO SAVEPOINT $name")->execute();
429 3
    }
430
431
    /**
432
     * Sets the isolation level of the current transaction.
433
     * @param string $level The transaction isolation level to use for this transaction.
434
     * This can be one of [[Transaction::READ_UNCOMMITTED]], [[Transaction::READ_COMMITTED]], [[Transaction::REPEATABLE_READ]]
435
     * and [[Transaction::SERIALIZABLE]] but also a string containing DBMS specific syntax to be used
436
     * after `SET TRANSACTION ISOLATION LEVEL`.
437
     * @see http://en.wikipedia.org/wiki/Isolation_%28database_systems%29#Isolation_levels
438
     */
439 4
    public function setTransactionIsolationLevel($level)
440
    {
441 4
        $this->db->createCommand("SET TRANSACTION ISOLATION LEVEL $level;")->execute();
442 4
    }
443
444
    /**
445
     * Executes the INSERT command, returning primary key values.
446
     * @param string $table the table that new rows will be inserted into.
447
     * @param array $columns the column data (name => value) to be inserted into the table.
448
     * @return array|false primary key values or false if the command fails
449
     * @since 2.0.4
450
     */
451 58
    public function insert($table, $columns)
452
    {
453 58
        $command = $this->db->createCommand()->insert($table, $columns);
454 58
        if (!$command->execute()) {
455
            return false;
456
        }
457 58
        $tableSchema = $this->getTableSchema($table);
458 58
        $result = [];
459 58
        foreach ($tableSchema->primaryKey as $name) {
460 55
            if ($tableSchema->columns[$name]->autoIncrement) {
461 51
                $result[$name] = $this->getLastInsertID($tableSchema->sequenceName);
462 51
                break;
463
            } else {
464 6
                $result[$name] = isset($columns[$name]) ? $columns[$name] : $tableSchema->columns[$name]->defaultValue;
465
            }
466 58
        }
467 58
        return $result;
468
    }
469
470
    /**
471
     * Quotes a string value for use in a query.
472
     * Note that if the parameter is not a string, it will be returned without change.
473
     * @param string $str string to be quoted
474
     * @return string the properly quoted string
475
     * @see http://www.php.net/manual/en/function.PDO-quote.php
476
     */
477 493
    public function quoteValue($str)
478
    {
479 493
        if (!is_string($str)) {
480 3
            return $str;
481
        }
482
483 493
        if (($value = $this->db->getSlavePdo()->quote($str)) !== false) {
484 493
            return $value;
485
        } else {
486
            // the driver doesn't support quote (e.g. oci)
487
            return "'" . addcslashes(str_replace("'", "''", $str), "\000\n\r\\\032") . "'";
488
        }
489
    }
490
491
    /**
492
     * Quotes a table name for use in a query.
493
     * If the table name contains schema prefix, the prefix will also be properly quoted.
494
     * If the table name is already quoted or contains '(' or '{{',
495
     * then this method will do nothing.
496
     * @param string $name table name
497
     * @return string the properly quoted table name
498
     * @see quoteSimpleTableName()
499
     */
500 728
    public function quoteTableName($name)
501
    {
502 728
        if (strpos($name, '(') !== false || strpos($name, '{{') !== false) {
503 194
            return $name;
504
        }
505 724
        if (strpos($name, '.') === false) {
506 724
            return $this->quoteSimpleTableName($name);
507
        }
508 4
        $parts = explode('.', $name);
509 4
        foreach ($parts as $i => $part) {
510 4
            $parts[$i] = $this->quoteSimpleTableName($part);
511 4
        }
512
513 4
        return implode('.', $parts);
514
515
    }
516
517
    /**
518
     * Quotes a column name for use in a query.
519
     * If the column name contains prefix, the prefix will also be properly quoted.
520
     * If the column name is already quoted or contains '(', '[[' or '{{',
521
     * then this method will do nothing.
522
     * @param string $name column name
523
     * @return string the properly quoted column name
524
     * @see quoteSimpleColumnName()
525
     */
526 797
    public function quoteColumnName($name)
527
    {
528 797
        if (strpos($name, '(') !== false || strpos($name, '[[') !== false) {
529 38
            return $name;
530
        }
531 791
        if (($pos = strrpos($name, '.')) !== false) {
532 113
            $prefix = $this->quoteTableName(substr($name, 0, $pos)) . '.';
533 113
            $name = substr($name, $pos + 1);
534 113
        } else {
535 791
            $prefix = '';
536
        }
537 791
        if (strpos($name, '{{') !== false) {
538 3
            return $name;
539
        }
540 791
        return $prefix . $this->quoteSimpleColumnName($name);
541
    }
542
543
    /**
544
     * Quotes a simple table name for use in a query.
545
     * A simple table name should contain the table name only without any schema prefix.
546
     * If the table name is already quoted, this method will do nothing.
547
     * @param string $name table name
548
     * @return string the properly quoted table name
549
     */
550
    public function quoteSimpleTableName($name)
551
    {
552
        return strpos($name, "'") !== false ? $name : "'" . $name . "'";
553
    }
554
555
    /**
556
     * Quotes a simple column name for use in a query.
557
     * A simple column name should contain the column name only without any prefix.
558
     * If the column name is already quoted or is the asterisk character '*', this method will do nothing.
559
     * @param string $name column name
560
     * @return string the properly quoted column name
561
     */
562 226
    public function quoteSimpleColumnName($name)
563
    {
564 226
        return strpos($name, '"') !== false || $name === '*' ? $name : '"' . $name . '"';
565
    }
566
567
    /**
568
     * Returns the actual name of a given table name.
569
     * This method will strip off curly brackets from the given table name
570
     * and replace the percentage character '%' with [[Connection::tablePrefix]].
571
     * @param string $name the table name to be converted
572
     * @return string the real name of the given table name
573
     */
574 488
    public function getRawTableName($name)
575
    {
576 488
        if (strpos($name, '{{') !== false) {
577 101
            $name = preg_replace('/\\{\\{(.*?)\\}\\}/', '\1', $name);
578
579 101
            return str_replace('%', $this->db->tablePrefix, $name);
580
        } else {
581 391
            return $name;
582
        }
583
    }
584
585
    /**
586
     * Extracts the PHP type from abstract DB type.
587
     * @param ColumnSchema $column the column schema information
588
     * @return string PHP type name
589
     */
590 468
    protected function getColumnPhpType($column)
591
    {
592
        static $typeMap = [
593
            // abstract type => php type
594
            'smallint' => 'integer',
595
            'integer' => 'integer',
596
            'bigint' => 'integer',
597
            'boolean' => 'boolean',
598
            'float' => 'double',
599
            'double' => 'double',
600
            'binary' => 'resource',
601 468
        ];
602 468
        if (isset($typeMap[$column->type])) {
603 461
            if ($column->type === 'bigint') {
604 27
                return PHP_INT_SIZE === 8 && !$column->unsigned ? 'integer' : 'string';
605 461
            } elseif ($column->type === 'integer') {
606 461
                return PHP_INT_SIZE === 4 && $column->unsigned ? 'string' : 'integer';
607
            } else {
608 137
                return $typeMap[$column->type];
609
            }
610
        } else {
611 452
            return 'string';
612
        }
613
    }
614
615
    /**
616
     * Converts a DB exception to a more concrete one if possible.
617
     *
618
     * @param \Exception $e
619
     * @param string $rawSql SQL that produced exception
620
     * @return Exception
621
     */
622 21
    public function convertException(\Exception $e, $rawSql)
623
    {
624 21
        if ($e instanceof Exception) {
625
            return $e;
626
        }
627
628 21
        $exceptionClass = '\yii\db\Exception';
629 21
        foreach ($this->exceptionMap as $error => $class) {
630 21
            if (strpos($e->getMessage(), $error) !== false) {
631 6
                $exceptionClass = $class;
632 6
            }
633 21
        }
634 21
        $message = $e->getMessage()  . "\nThe SQL being executed was: $rawSql";
635 21
        $errorInfo = $e instanceof \PDOException ? $e->errorInfo : null;
636 21
        return new $exceptionClass($message, $errorInfo, (int) $e->getCode(), $e);
637
    }
638
639
    /**
640
     * Returns a value indicating whether a SQL statement is for read purpose.
641
     * @param string $sql the SQL statement
642
     * @return bool whether a SQL statement is for read purpose.
643
     */
644 9
    public function isReadQuery($sql)
645
    {
646 9
        $pattern = '/^\s*(SELECT|SHOW|DESCRIBE)\b/i';
647 9
        return preg_match($pattern, $sql) > 0;
648
    }
649
}
650