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 ( a81d72...271609 )
by Robert
14:15
created

Schema::getTableSchema()   D

Complexity

Conditions 10
Paths 7

Size

Total Lines 31
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 10.0751

Importance

Changes 0
Metric Value
dl 0
loc 31
rs 4.8196
c 0
b 0
f 0
ccs 20
cts 22
cp 0.9091
cc 10
eloc 18
nc 7
nop 2
crap 10.0751

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