This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | /** |
||
4 | * @link http://www.yiiframework.com/ |
||
5 | * @copyright Copyright (c) 2008 Yii Software LLC |
||
6 | * @license http://www.yiiframework.com/license/ |
||
7 | */ |
||
8 | |||
9 | namespace edgardmessias\db\firebird; |
||
10 | |||
11 | use yii\base\InvalidCallException; |
||
12 | use yii\db\CheckConstraint; |
||
13 | use yii\db\Constraint; |
||
14 | use yii\db\ConstraintFinderInterface; |
||
15 | use yii\db\ConstraintFinderTrait; |
||
16 | use yii\db\Exception; |
||
17 | use yii\db\Expression; |
||
18 | use yii\db\ForeignKeyConstraint; |
||
19 | use yii\db\IndexConstraint; |
||
20 | use yii\db\Schema as BaseSchema; |
||
21 | use yii\db\TableSchema; |
||
22 | use yii\db\Transaction; |
||
0 ignored issues
–
show
|
|||
23 | use yii\db\ViewFinderTrait; |
||
24 | use yii\helpers\ArrayHelper; |
||
25 | |||
26 | /** |
||
27 | * Schema represents the Firebird schema information. |
||
28 | * |
||
29 | * @property string[] $indexNames All index names in the Firebird. This property is read-only. |
||
30 | * @property IndexSchema[] $indexSchemas The metadata for all indexes in the Firebird. Each array element is an |
||
31 | * instance of [[IndexSchema]] or its child class. This property is read-only. |
||
32 | * @property array $indexTypes All index types in the Firebird in format: index name => index type. This |
||
33 | * property is read-only. |
||
34 | * @property QueryBuilder $queryBuilder The query builder for this connection. This property is read-only. |
||
35 | * |
||
36 | * @author Edgard Lorraine Messias <[email protected]> |
||
37 | * @since 2.0 |
||
38 | */ |
||
39 | class Schema extends BaseSchema implements ConstraintFinderInterface |
||
40 | { |
||
41 | use ViewFinderTrait; |
||
42 | use ConstraintFinderTrait; |
||
43 | |||
44 | private $_lastInsertID = null; |
||
45 | |||
46 | /** |
||
47 | * @var array map of DB errors and corresponding exceptions |
||
48 | * If left part is found in DB error message exception class from the right part is used. |
||
49 | */ |
||
50 | public $exceptionMap = [ |
||
51 | 'SQLSTATE[23' => 'yii\db\IntegrityException', |
||
52 | 'SQLSTATE[HY000]: General error: -803 violation of PRIMARY' => 'yii\db\IntegrityException', |
||
53 | ]; |
||
54 | public $reservedWords = [ |
||
55 | 'ADD', |
||
56 | 'ADMIN', |
||
57 | 'ALL', |
||
58 | 'ALTER', |
||
59 | 'AND', |
||
60 | 'ANY', |
||
61 | 'AS', |
||
62 | 'AT', |
||
63 | 'AVG', |
||
64 | 'BEGIN', |
||
65 | 'BETWEEN', |
||
66 | 'BIGINT', |
||
67 | 'BIT_LENGTH', |
||
68 | 'BLOB', |
||
69 | 'BOTH', |
||
70 | 'BOOLEAN', |
||
71 | 99 | 'BY', |
|
72 | 'CASE', |
||
73 | 99 | 'CAST', |
|
74 | 'CHAR', |
||
75 | 'CHAR_LENGTH', |
||
76 | 'CHARACTER', |
||
77 | 'CHARACTER_LENGTH', |
||
78 | 'CHECK', |
||
79 | 2 | 'CLOSE', |
|
80 | 'COLLATE', |
||
81 | 2 | 'COLUMN', |
|
82 | 'COMMIT', |
||
83 | 'CONNECT', |
||
84 | 157 | 'CONSTRAINT', |
|
85 | 'CORR', |
||
86 | 157 | 'COUNT', |
|
87 | 'COVAR_POP', |
||
88 | 'CREATE', |
||
89 | 'CROSS', |
||
90 | 157 | 'CURRENT', |
|
91 | 157 | 'CURRENT_CONNECTION', |
|
92 | 43 | 'CURRENT_DATE', |
|
93 | 'CURRENT_ROLE', |
||
94 | 'CURRENT_TIME', |
||
95 | 156 | 'CURRENT_TIMESTAMP', |
|
96 | 'CURRENT_TRANSACTION', |
||
97 | 'CURRENT_USER', |
||
98 | 173 | 'CURSOR', |
|
99 | 'DATE', |
||
100 | 173 | 'DAY', |
|
101 | 6 | 'DEC', |
|
102 | 'DECIMAL', |
||
103 | 173 | 'DECLARE', |
|
104 | 'DEFAULT', |
||
105 | 'DELETE', |
||
106 | 106 | 'DELETING', |
|
107 | 'DETERMINISTIC', |
||
108 | 106 | 'DISCONNECT', |
|
109 | 106 | 'DISTINCT', |
|
110 | 106 | 'DOUBLE', |
|
111 | 104 | 'DROP', |
|
112 | 104 | 'ELSE', |
|
113 | 'END', |
||
114 | 7 | 'ESCAPE', |
|
115 | 'EXECUTE', |
||
116 | 'EXISTS', |
||
117 | 93 | 'EXTERNAL', |
|
118 | 'EXRACT', |
||
119 | 93 | 'FALSE', |
|
120 | 'FETCH', |
||
121 | 'FILTER', |
||
122 | 'FLOAT', |
||
123 | 'FOR', |
||
124 | 'FOREIGN', |
||
125 | 'FROM', |
||
126 | 'FULL', |
||
127 | 93 | 'FUNCTION', |
|
128 | 'GDSCODE', |
||
129 | 93 | 'GLOBAL', |
|
130 | 'GRANT', |
||
131 | 'GROUP', |
||
132 | 'HAVING', |
||
133 | 'HOUR', |
||
134 | 'IN', |
||
135 | 'INDEX', |
||
136 | 'INNER', |
||
137 | 106 | 'INSENSITIVE', |
|
138 | 'INSERT', |
||
139 | 106 | 'INSERTING', |
|
140 | 106 | 'INT', |
|
141 | 'INTEGER', |
||
142 | 'INTO', |
||
143 | 'IS', |
||
144 | 'JOIN', |
||
145 | 106 | 'LEADING', |
|
146 | 106 | 'LEFT', |
|
147 | 'LIKE', |
||
148 | 106 | 'LONG', |
|
149 | 'LOWER', |
||
150 | 'MAX', |
||
151 | 'MAXIMUM_SEGMENT', |
||
152 | 'MERGE', |
||
153 | 'MIN', |
||
154 | 'MINUTE', |
||
155 | 'MONTH', |
||
156 | 106 | 'NATIONAL', |
|
157 | 'NATURAL', |
||
158 | 'NCHAR', |
||
159 | 'NO', |
||
160 | 'NOT', |
||
161 | 'NULL', |
||
162 | 'NUMERIC', |
||
163 | 'OCTET_LENGTH', |
||
164 | 'OF', |
||
165 | 'OFFSET', |
||
166 | 'ON', |
||
167 | 'OPEN', |
||
168 | 'OR', |
||
169 | 'ORDER', |
||
170 | 'OUTER', |
||
171 | 'OVER', |
||
172 | 'PARAMETER', |
||
173 | 'PASSWORD', |
||
174 | 106 | 'PLAN', |
|
175 | 'POSITION', |
||
176 | 'POST_EVENT', |
||
177 | 'PRECISION', |
||
178 | 'PRIMARY', |
||
179 | 'PROCEDURE', |
||
180 | 'RDB$DB_KEY', |
||
181 | 'RDB$RECORD_VERSION', |
||
182 | 'REAL', |
||
183 | 'RECORD_VERSION', |
||
184 | 106 | 'RECREATE', |
|
185 | 'RECURSIVE', |
||
186 | 106 | 'REFERENCES', |
|
187 | 'REGR_AVGX', |
||
188 | 106 | 'REGR_AVGY', |
|
189 | 106 | 'REGR_COUNT', |
|
190 | 106 | 'REGR_INTERCEPT', |
|
191 | 'REGR_R2', |
||
192 | 'REGR_SLOPE', |
||
193 | 'REGR_SXX', |
||
194 | 'REGR_SXY', |
||
195 | 'REGR_SYY', |
||
196 | 'RELEASE', |
||
197 | 'RETURN', |
||
198 | 'RETURNING_VALUES', |
||
199 | 'RETURNS', |
||
200 | 'REVOKE', |
||
201 | 104 | 'RIGHT', |
|
202 | 'ROLLBACK', |
||
203 | 104 | 'ROW', |
|
204 | 'ROWS', |
||
205 | 'ROW_COUNT', |
||
206 | 'SAVEPOINT', |
||
207 | 104 | 'SCROLL', |
|
208 | 104 | 'SECOND', |
|
209 | 104 | 'SELECT', |
|
210 | 104 | 'SENSITIVE', |
|
211 | 104 | 'SET', |
|
212 | 'SIMILAR', |
||
213 | 104 | 'SOME', |
|
214 | 104 | 'SQLCODE', |
|
215 | 104 | 'SQLSTATE', |
|
216 | 87 | 'START', |
|
217 | 87 | 'STDDEV_POP', |
|
218 | 79 | 'STDDEV_SAMP', |
|
219 | 13 | 'SUM', |
|
220 | 13 | 'TABLE', |
|
221 | 'THEN', |
||
222 | 'TIME', |
||
223 | 104 | 'TIMESTAMP', |
|
224 | 104 | 'TO', |
|
225 | 104 | 'TRAILING', |
|
226 | 'TRIGGER', |
||
227 | 'TRIM', |
||
228 | 104 | 'TRUE', |
|
229 | 'UNION', |
||
230 | 'UNIQUE', |
||
231 | 'UNKNOWN', |
||
232 | 'UPDATE', |
||
233 | 'UPDATING', |
||
234 | 'UPPER', |
||
235 | 104 | 'USER', |
|
236 | 'USING', |
||
237 | 104 | 'VALUE', |
|
238 | 'VALUES', |
||
239 | 'VARCHAR', |
||
240 | 'VARIABLE', |
||
241 | 'VARYING', |
||
242 | 'VAR_POP', |
||
243 | 'VAR_SAMP', |
||
244 | 'VIEW', |
||
245 | 'WHEN', |
||
246 | 104 | 'WHERE', |
|
247 | 'WHILE', |
||
248 | 104 | 'WITH', |
|
249 | 104 | 'YEAR', |
|
250 | 104 | ]; |
|
251 | 104 | ||
252 | 104 | /** |
|
253 | 104 | * @var array mapping from physical column types (keys) to abstract column types (values) |
|
254 | */ |
||
255 | 104 | public $typeMap = [ |
|
256 | 'bigint' => self::TYPE_BIGINT, |
||
257 | 104 | 'char' => self::TYPE_CHAR, |
|
258 | 104 | 'varchar' => self::TYPE_STRING, |
|
259 | 'timestamp' => self::TYPE_TIMESTAMP, |
||
260 | 63 | 'decimal' => self::TYPE_DECIMAL, |
|
261 | 63 | 'float' => self::TYPE_FLOAT, |
|
262 | 'blob' => self::TYPE_BINARY, |
||
263 | 'integer' => self::TYPE_INTEGER, |
||
264 | 63 | 'blob sub_type text' => self::TYPE_TEXT, |
|
265 | 'numeric' => self::TYPE_DECIMAL, |
||
266 | 104 | 'double precision' => self::TYPE_DOUBLE, |
|
267 | 103 | 'smallint' => self::TYPE_SMALLINT, |
|
268 | ]; |
||
269 | 104 | ||
270 | /** |
||
271 | 104 | * {@inheritdoc} |
|
272 | */ |
||
273 | protected function resolveTableName($name) |
||
274 | { |
||
275 | $resolvedName = new TableSchema(); |
||
276 | $this->resolveTableNames($resolvedName, $name); |
||
277 | return $resolvedName; |
||
278 | } |
||
279 | |||
280 | /** |
||
281 | * Creates a query builder for the database. |
||
282 | * This method may be overridden by child classes to create a DBMS-specific query builder. |
||
283 | * @return QueryBuilder query builder instance |
||
284 | */ |
||
285 | public function createQueryBuilder() |
||
286 | { |
||
287 | 104 | return new QueryBuilder($this->db); |
|
288 | } |
||
289 | |||
290 | 104 | /** |
|
291 | 104 | * @inheritdoc |
|
292 | 88 | */ |
|
293 | 88 | public function createColumnSchemaBuilder($type, $length = null) |
|
294 | 88 | { |
|
295 | 88 | return new ColumnSchemaBuilder($type, $length); |
|
296 | } |
||
297 | 104 | ||
298 | 104 | public function quoteSimpleTableName($name) |
|
299 | 104 | { |
|
300 | 104 | if ($this->db->tablePrefix !== '') { |
|
301 | 104 | return $name; |
|
302 | } |
||
303 | |||
304 | $word = strtoupper(str_replace('%', '', $name)); |
||
305 | if (in_array($word, $this->reservedWords)) { |
||
306 | return strpos($name, '"') !== false ? $name : '"' . $name . '"'; |
||
307 | 104 | } |
|
308 | 16 | ||
309 | 16 | return $name; |
|
310 | 16 | } |
|
311 | 16 | ||
312 | 16 | public function quoteSimpleColumnName($name) |
|
313 | { |
||
314 | 104 | if (in_array(strtoupper($name), $this->reservedWords)) { |
|
315 | 101 | return parent::quoteSimpleColumnName($name); |
|
316 | 47 | } |
|
317 | 47 | return $name; |
|
318 | 3 | } |
|
319 | 3 | ||
320 | 3 | protected function loadTableSchema($name) |
|
321 | 3 | { |
|
322 | 3 | $table = $this->resolveTableName($name); |
|
323 | 47 | if ($this->findColumns($table)) { |
|
324 | 46 | $this->findConstraints($table); |
|
325 | 46 | return $table; |
|
326 | 46 | } |
|
327 | 46 | return null; |
|
328 | 46 | } |
|
329 | |||
330 | 4 | public function getPdoType($data) |
|
331 | 4 | { |
|
332 | static $typeMap = [ |
||
333 | 47 | // php type => PDO type |
|
334 | 89 | 'boolean' => \PDO::PARAM_INT, |
|
335 | 15 | 'integer' => \PDO::PARAM_INT, |
|
336 | 15 | 'string' => \PDO::PARAM_STR, |
|
337 | 15 | 'resource' => \PDO::PARAM_LOB, |
|
338 | 15 | 'NULL' => \PDO::PARAM_NULL, |
|
339 | 15 | ]; |
|
340 | $type = gettype($data); |
||
341 | 15 | ||
342 | return isset($typeMap[$type]) ? $typeMap[$type] : \PDO::PARAM_STR; |
||
343 | } |
||
344 | 104 | ||
345 | /** |
||
346 | 104 | * |
|
347 | 104 | * @param TableSchema $table |
|
348 | 104 | * @param string $name |
|
349 | 104 | */ |
|
350 | 104 | protected function resolveTableNames($table, $name) |
|
351 | { |
||
352 | $parts = explode('.', str_replace('"', '', $name)); |
||
353 | if (isset($parts[1])) { |
||
354 | $table->schemaName = $parts[0]; |
||
355 | 104 | $table->name = strtolower($parts[1]); |
|
356 | $table->fullName = $this->quoteTableName($table->schemaName) . '.' . $this->quoteTableName($table->name); |
||
357 | 104 | } else { |
|
358 | 104 | $table->name = strtolower($parts[0]); |
|
359 | 63 | $table->fullName = $this->quoteTableName($table->name); |
|
360 | 63 | } |
|
361 | 15 | } |
|
362 | |||
363 | 63 | /** |
|
364 | * Collects the table column metadata. |
||
365 | * |
||
366 | * @param TableSchema $table the table metadata |
||
367 | 104 | * @return boolean whether the table exists in the database |
|
368 | */ |
||
369 | protected function findColumns($table) |
||
370 | { |
||
371 | // Zoggo - Converted sql to use join syntax |
||
372 | // robregonm - Added isAutoInc |
||
373 | $sql = 'SELECT |
||
374 | rel.rdb$field_name AS fname, |
||
375 | 104 | rel.rdb$default_source AS fdefault, |
|
376 | fld.rdb$field_type AS fcodtype, |
||
377 | fld.rdb$field_sub_type AS fcodsubtype, |
||
378 | fld.rdb$field_length AS flength, |
||
379 | fld.rdb$character_length AS fcharlength, |
||
380 | fld.rdb$field_scale AS fscale, |
||
381 | fld.rdb$field_precision AS fprecision, |
||
382 | rel.rdb$null_flag AS fnull, |
||
383 | rel.rdb$description AS fcomment, |
||
384 | fld.rdb$default_value AS fdefault_value,'; |
||
385 | |||
386 | if ($this->db->supportColumnIdentity) { |
||
387 | $sql .= ' |
||
388 | rel.rdb$generator_name AS fgenerator_name,'; |
||
389 | } |
||
390 | |||
391 | 104 | $sql .= ' |
|
392 | (SELECT RDB$TRIGGER_SOURCE FROM RDB$TRIGGERS |
||
393 | 104 | WHERE RDB$SYSTEM_FLAG = 0 |
|
394 | AND UPPER(RDB$RELATION_NAME)=UPPER(\'' . $table->name . '\') |
||
395 | AND RDB$TRIGGER_TYPE = 1 |
||
396 | AND RDB$TRIGGER_INACTIVE = 0 |
||
397 | AND (UPPER(REPLACE(RDB$TRIGGER_SOURCE,\' \',\'\')) LIKE \'%NEW.\'||TRIM(rel.rdb$field_name)||\'=GEN_ID%\' |
||
398 | 104 | OR UPPER(REPLACE(RDB$TRIGGER_SOURCE,\' \',\'\')) LIKE \'%NEW.\'||TRIM(rel.rdb$field_name)||\'=NEXTVALUEFOR%\')) |
|
399 | 104 | AS fautoinc |
|
400 | FROM |
||
401 | rdb$relation_fields rel |
||
402 | 29 | JOIN rdb$fields fld ON rel.rdb$field_source=fld.rdb$field_name |
|
403 | 29 | WHERE |
|
404 | UPPER(rel.rdb$relation_name)=UPPER(\'' . $table->name . '\') |
||
405 | 29 | ORDER BY |
|
406 | 29 | rel.rdb$field_position;'; |
|
407 | 29 | try { |
|
408 | $columns = $this->db->createCommand($sql)->queryAll(); |
||
409 | if (empty($columns)) { |
||
410 | 29 | return false; |
|
411 | } |
||
412 | 104 | } catch (Exception $e) { |
|
413 | 104 | return false; |
|
414 | } |
||
415 | 5 | $sql = 'SELECT |
|
416 | idx.rdb$field_name AS fname |
||
417 | FROM |
||
418 | rdb$relation_constraints rc |
||
419 | JOIN rdb$index_segments idx ON idx.rdb$index_name=rc.rdb$index_name |
||
420 | WHERE rc.rdb$constraint_type=\'PRIMARY KEY\' |
||
421 | AND UPPER(rc.rdb$relation_name)=UPPER(\'' . $table->name . '\')'; |
||
422 | 5 | try { |
|
423 | $pkeys = $this->db->createCommand($sql)->queryColumn(); |
||
424 | 5 | } catch (Exception $e) { |
|
425 | return false; |
||
426 | } |
||
427 | $pkeys = array_map('rtrim', $pkeys); |
||
428 | $pkeys = array_map('strtolower', $pkeys); |
||
429 | 5 | foreach ($columns as $key => $column) { |
|
430 | 5 | $column = array_map('strtolower', $column); |
|
431 | $columns[$key]['fprimary'] = in_array(rtrim($column['fname']), $pkeys); |
||
432 | 5 | } |
|
433 | foreach ($columns as $column) { |
||
434 | $c = $this->loadColumnSchema($column); |
||
435 | if ($table->sequenceName === null && $c->autoIncrement) { |
||
436 | $matches = []; |
||
437 | |||
438 | if (isset($column['fgenerator_name']) && $column['fgenerator_name']) { |
||
439 | $table->sequenceName = $column['fgenerator_name']; |
||
440 | } elseif (preg_match("/NEW.{$c->name}\s*=\s*GEN_ID\((\w+)/i", $column['fautoinc'], $matches)) { |
||
441 | $table->sequenceName = $matches[1]; |
||
442 | } elseif (preg_match("/NEW.{$c->name}\s*=\s*NEXT\s+VALUE\s+FOR\s+(\w+)/i", $column['fautoinc'], $matches)) { |
||
443 | $table->sequenceName = $matches[1]; |
||
444 | } |
||
445 | } |
||
446 | $table->columns[$c->name] = $c; |
||
447 | if ($c->isPrimaryKey) { |
||
448 | $table->primaryKey[] = $c->name; |
||
449 | } |
||
450 | 1 | } |
|
451 | return (count($table->columns) > 0); |
||
452 | } |
||
453 | |||
454 | /** |
||
455 | * @return ColumnSchema |
||
456 | * @throws \yii\base\InvalidConfigException |
||
457 | */ |
||
458 | 1 | protected function createColumnSchema() |
|
459 | 1 | { |
|
460 | 1 | return \Yii::createObject('\edgardmessias\db\firebird\ColumnSchema'); |
|
461 | 1 | } |
|
462 | 1 | ||
463 | 1 | /** |
|
464 | * Creates a table column. |
||
465 | 1 | * |
|
466 | * @param array $column column metadata |
||
467 | * @return ColumnSchema normalized column metadata |
||
468 | */ |
||
469 | protected function loadColumnSchema($column) |
||
470 | { |
||
471 | $c = $this->createColumnSchema(); |
||
472 | $c->name = strtolower(rtrim($column['fname'])); |
||
473 | $c->allowNull = (int) $column['fnull'] !== 1; |
||
474 | $c->isPrimaryKey = $column['fprimary']; |
||
475 | $c->autoIncrement = (isset($column['fgenerator_name']) && $column['fgenerator_name']) || (boolean) $column['fautoinc']; |
||
476 | 2 | $c->comment = $column['fcomment'] === null ? '' : $column['fcomment']; |
|
477 | |||
478 | 2 | $c->type = self::TYPE_STRING; |
|
479 | 2 | ||
480 | 1 | $defaultValue = null; |
|
481 | 1 | if (!empty($column['fdefault'])) { |
|
482 | 1 | // remove whitespace, 'DEFAULT ' prefix and surrounding single quotes; all optional |
|
483 | 1 | if (preg_match("/\s*(DEFAULT\s+){0,1}('(.*)'|(.*))\s*/i", $column['fdefault'], $parts)) { |
|
484 | $defaultValue = array_pop($parts); |
||
485 | 1 | } |
|
486 | // handle escaped single quotes like in "funny''quoted''string" |
||
487 | 2 | $defaultValue = str_replace('\'\'', '\'', $defaultValue); |
|
488 | } |
||
489 | if ($defaultValue === null) { |
||
490 | $defaultValue = $column['fdefault_value']; |
||
491 | } |
||
492 | 13 | $dbType = ''; |
|
493 | $baseTypes = [ |
||
494 | 13 | 7 => 'SMALLINT', |
|
495 | 13 | 8 => 'INTEGER', |
|
496 | 13 | 16 => 'INT64', |
|
497 | 13 | 9 => 'QUAD', |
|
498 | 13 | 10 => 'FLOAT', |
|
499 | 12 | 11 => 'D_FLOAT', |
|
500 | 12 | 17 => 'BOOLEAN', |
|
501 | 12 | 27 => 'DOUBLE PRECISION', |
|
502 | 12 => 'DATE', |
||
503 | 12 | 13 => 'TIME', |
|
504 | 35 => 'TIMESTAMP', |
||
505 | 261 => 'BLOB', |
||
506 | 13 | 40 => 'CSTRING', |
|
507 | 13 | 45 => 'BLOB_ID', |
|
508 | 13 | ]; |
|
509 | $baseCharTypes = [ |
||
510 | 13 | 37 => 'VARCHAR', |
|
511 | 14 => 'CHAR', |
||
512 | ]; |
||
513 | 13 | if (array_key_exists((int) $column['fcodtype'], $baseTypes)) { |
|
514 | 12 | $dbType = $baseTypes[(int) $column['fcodtype']]; |
|
515 | 12 | } elseif (array_key_exists((int) $column['fcodtype'], $baseCharTypes)) { |
|
516 | 10 | $c->size = (int) $column['fcharlength']; |
|
517 | 12 | $c->precision = $c->size; |
|
518 | $dbType = $baseCharTypes[(int) $column['fcodtype']] . "($c->size)"; |
||
519 | } |
||
520 | switch ((int) $column['fcodtype']) { |
||
521 | 13 | case 7: |
|
522 | case 8: |
||
523 | switch ((int) $column['fcodsubtype']) { |
||
524 | case 1: |
||
525 | $c->precision = (int) $column['fprecision']; |
||
526 | $c->size = $c->precision; |
||
527 | $c->scale = abs((int) $column['fscale']); |
||
0 ignored issues
–
show
It seems like
abs((int) $column['fscale']) can also be of type double . However, the property $scale is declared as type integer . Maybe add an additional type check?
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly. For example, imagine you have a variable Either this assignment is in error or a type check should be added for that assignment. class Id
{
public $id;
public function __construct($id)
{
$this->id = $id;
}
}
class Account
{
/** @var Id $id */
public $id;
}
$account_id = false;
if (starsAreRight()) {
$account_id = new Id(42);
}
$account = new Account();
if ($account instanceof Id)
{
$account->id = $account_id;
}
![]() |
|||
528 | 2 | $dbType = "NUMERIC({$c->precision},{$c->scale})"; |
|
529 | break; |
||
530 | 2 | case 2: |
|
531 | $c->precision = (int) $column['fprecision']; |
||
532 | $c->size = $c->precision; |
||
533 | $c->scale = abs((int) $column['fscale']); |
||
534 | 2 | $dbType = "DECIMAL({$c->precision},{$c->scale})"; |
|
535 | 2 | break; |
|
536 | } |
||
537 | break; |
||
538 | 1 | case 16: |
|
539 | 1 | switch ((int) $column['fcodsubtype']) { |
|
540 | case 1: |
||
541 | $c->precision = (int) $column['fprecision']; |
||
542 | $c->size = $c->precision; |
||
543 | $c->scale = abs((int) $column['fscale']); |
||
544 | $dbType = "NUMERIC({$c->precision},{$c->scale})"; |
||
545 | break; |
||
546 | case 2: |
||
547 | $c->precision = (int) $column['fprecision']; |
||
548 | $c->size = $c->precision; |
||
549 | $c->scale = abs((int) $column['fscale']); |
||
550 | $dbType = "DECIMAL({$c->precision},{$c->scale})"; |
||
551 | break; |
||
552 | default: |
||
553 | $dbType = 'BIGINT'; |
||
554 | break; |
||
555 | } |
||
556 | break; |
||
557 | case 261: |
||
558 | switch ((int) $column['fcodsubtype']) { |
||
559 | case 1: |
||
560 | $dbType = 'BLOB SUB_TYPE TEXT'; |
||
561 | $c->size = null; |
||
562 | break; |
||
563 | } |
||
564 | break; |
||
565 | } |
||
566 | |||
567 | $c->dbType = strtolower($dbType); |
||
568 | |||
569 | $c->type = self::TYPE_STRING; |
||
570 | if (preg_match('/^([\w\ ]+)(?:\(([^\)]+)\))?/', $c->dbType, $matches)) { |
||
571 | $type = strtolower($matches[1]); |
||
572 | if (isset($this->typeMap[$type])) { |
||
573 | $c->type = $this->typeMap[$type]; |
||
574 | } |
||
575 | } |
||
576 | |||
577 | |||
578 | $c->phpType = $this->getColumnPhpType($c); |
||
579 | |||
580 | $c->defaultValue = null; |
||
581 | if ($defaultValue !== null) { |
||
582 | if (in_array($c->type, [self::TYPE_DATE, self::TYPE_DATETIME, self::TYPE_TIME, self::TYPE_TIMESTAMP]) |
||
583 | && preg_match('/(CURRENT_|NOW|NULL|TODAY|TOMORROW|YESTERDAY)/i', $defaultValue)) { |
||
584 | $c->defaultValue = new Expression(trim($defaultValue)); |
||
585 | } else { |
||
586 | $c->defaultValue = $c->phpTypecast($defaultValue); |
||
587 | } |
||
588 | } |
||
589 | |||
590 | return $c; |
||
591 | } |
||
592 | |||
593 | /** |
||
594 | * Collects the foreign key column details for the given table. |
||
595 | * |
||
596 | * @param TableSchema $table the table metadata |
||
597 | */ |
||
598 | protected function findConstraints($table) |
||
599 | { |
||
600 | // Zoggo - Converted sql to use join syntax |
||
601 | $sql = 'SELECT |
||
602 | a.rdb$constraint_name as fconstraint, |
||
603 | c.rdb$relation_name AS ftable, |
||
604 | d.rdb$field_name AS pfield, |
||
605 | e.rdb$field_name AS ffield |
||
606 | FROM |
||
607 | rdb$ref_constraints b |
||
608 | JOIN rdb$relation_constraints a ON a.rdb$constraint_name=b.rdb$constraint_name |
||
609 | JOIN rdb$relation_constraints c ON b.rdb$const_name_uq=c.rdb$constraint_name |
||
610 | JOIN rdb$index_segments d ON c.rdb$index_name=d.rdb$index_name |
||
611 | JOIN rdb$index_segments e ON a.rdb$index_name=e.rdb$index_name AND e.rdb$field_position = d.rdb$field_position |
||
612 | WHERE |
||
613 | a.rdb$constraint_type=\'FOREIGN KEY\' AND |
||
614 | UPPER(a.rdb$relation_name)=UPPER(\'' . $table->name . '\') '; |
||
615 | try { |
||
616 | $fkeys = $this->db->createCommand($sql)->queryAll(); |
||
617 | } catch (Exception $e) { |
||
618 | return false; |
||
619 | } |
||
620 | |||
621 | $constraints = []; |
||
622 | foreach ($fkeys as $fkey) { |
||
623 | // Zoggo - Added strtolower here to guarantee that values are |
||
624 | // returned lower case. Otherwise gii generates wrong code. |
||
625 | $fkey = array_map('rtrim', $fkey); |
||
626 | $fkey = array_map('strtolower', $fkey); |
||
627 | |||
628 | if (!isset($constraints[$fkey['fconstraint']])) { |
||
629 | $constraints[$fkey['fconstraint']] = [ |
||
630 | $fkey['ftable'] |
||
631 | ]; |
||
632 | } |
||
633 | $constraints[$fkey['fconstraint']][$fkey['ffield']] = $fkey['pfield']; |
||
634 | } |
||
635 | $table->foreignKeys = $constraints; |
||
636 | } |
||
637 | |||
638 | protected function findTableNames($schema = '') |
||
639 | { |
||
640 | $sql = 'SELECT |
||
641 | rdb$relation_name |
||
642 | FROM |
||
643 | rdb$relations |
||
644 | WHERE |
||
645 | (rdb$system_flag is null OR rdb$system_flag=0)'; |
||
646 | try { |
||
647 | $tables = $this->db->createCommand($sql)->queryColumn(); |
||
648 | } catch (Exception $e) { |
||
649 | return false; |
||
650 | } |
||
651 | |||
652 | $tables = array_map('rtrim', $tables); |
||
653 | $tables = array_map('strtolower', $tables); |
||
654 | |||
655 | return $tables; |
||
656 | } |
||
657 | |||
658 | /** |
||
659 | * Returns all unique indexes for the given table. |
||
660 | * Each array element is of the following structure: |
||
661 | * |
||
662 | * ~~~ |
||
663 | * [ |
||
664 | * 'IndexName1' => ['col1' [, ...]], |
||
665 | * 'IndexName2' => ['col2' [, ...]], |
||
666 | * ] |
||
667 | * ~~~ |
||
668 | * |
||
669 | * @param TableSchema $table the table metadata |
||
670 | * @return array all unique indexes for the given table. |
||
671 | * @since 2.0.4 |
||
672 | */ |
||
673 | public function findUniqueIndexes($table) |
||
674 | { |
||
675 | $query = ' |
||
676 | SELECT id.RDB$INDEX_NAME as index_name, ids.RDB$FIELD_NAME as column_name |
||
677 | FROM RDB$INDICES id |
||
678 | INNER JOIN RDB$INDEX_SEGMENTS ids ON ids.RDB$INDEX_NAME = id.RDB$INDEX_NAME |
||
679 | WHERE id.RDB$UNIQUE_FLAG = 1 |
||
680 | AND id.RDB$SYSTEM_FLAG = 0 |
||
681 | AND UPPER(id.RDB$RELATION_NAME) = UPPER(\'' . $table->name . '\') |
||
682 | ORDER BY id.RDB$RELATION_NAME, id.RDB$INDEX_NAME, ids.RDB$FIELD_POSITION'; |
||
683 | $result = []; |
||
684 | $command = $this->db->createCommand($query); |
||
685 | foreach ($command->queryAll() as $row) { |
||
686 | $result[strtolower(rtrim($row['index_name']))][] = strtolower(rtrim($row['column_name'])); |
||
687 | } |
||
688 | return $result; |
||
689 | } |
||
690 | |||
691 | /** |
||
692 | * Sets the isolation level of the current transaction. |
||
693 | * @param string $level The transaction isolation level to use for this transaction. |
||
694 | * This can be one of [[Transaction::READ_UNCOMMITTED]], [[Transaction::READ_COMMITTED]], [[Transaction::REPEATABLE_READ]] |
||
695 | * and [[Transaction::SERIALIZABLE]] but also a string containing DBMS specific syntax to be used |
||
696 | * after `SET TRANSACTION ISOLATION LEVEL`. |
||
697 | * @see http://en.wikipedia.org/wiki/Isolation_%28database_systems%29#Isolation_levels |
||
698 | */ |
||
699 | public function setTransactionIsolationLevel($level) |
||
700 | { |
||
701 | if ($level == Transaction::READ_UNCOMMITTED) { |
||
702 | parent::setTransactionIsolationLevel('READ COMMITTED RECORD_VERSION'); |
||
703 | } elseif ($level == Transaction::REPEATABLE_READ) { |
||
704 | parent::setTransactionIsolationLevel('SNAPSHOT'); |
||
705 | } elseif ($level == Transaction::SERIALIZABLE) { |
||
706 | parent::setTransactionIsolationLevel('SNAPSHOT TABLE STABILITY'); |
||
707 | } else { |
||
708 | parent::setTransactionIsolationLevel($level); |
||
709 | } |
||
710 | } |
||
711 | |||
712 | /** |
||
713 | * @inheritdoc |
||
714 | */ |
||
715 | public function insert($table, $columns) |
||
716 | { |
||
717 | $this->_lastInsertID = false; |
||
718 | $params = []; |
||
719 | $sql = ""; |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
The string literal
does not require double quotes, as per coding-style, please use single quotes.
PHP provides two ways to mark string literals. Either with single quotes String literals in single quotes on the other hand are evaluated very literally and the only two
characters that needs escaping in the literal are the single quote itself ( Double quoted string literals may contain other variables or more complex escape sequences. <?php
$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";
print $doubleQuoted;
will print an indented: If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear. For more information on PHP string literals and available escape sequences see the PHP core documentation. ![]() |
|||
720 | $returnColumns = $this->getTableSchema($table)->primaryKey; |
||
721 | if (!empty($returnColumns)) { |
||
722 | if (!$this->db->supportReturningInsert) { |
||
723 | $returs = []; |
||
724 | $returning = []; |
||
725 | $columnSchemas = $this->getTableSchema($table)->columns; |
||
726 | foreach ((array) $returnColumns as $name) { |
||
727 | $returs[] = $this->quoteColumnName($name) . ' ' . $columnSchemas[$name]->dbType; |
||
728 | $returning[] = $this->quoteColumnName($name); |
||
729 | } |
||
730 | |||
731 | $sql = $this->db->getQueryBuilder()->rawInsert($table, array_keys($columns), array_values($columns), $params); |
||
0 ignored issues
–
show
|
|||
732 | |||
733 | $sql = "EXECUTE block RETURNS (" |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
The string literal
EXECUTE block RETURNS ( does not require double quotes, as per coding-style, please use single quotes.
PHP provides two ways to mark string literals. Either with single quotes String literals in single quotes on the other hand are evaluated very literally and the only two
characters that needs escaping in the literal are the single quote itself ( Double quoted string literals may contain other variables or more complex escape sequences. <?php
$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";
print $doubleQuoted;
will print an indented: If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear. For more information on PHP string literals and available escape sequences see the PHP core documentation. ![]() |
|||
734 | . implode(', ',$returs) |
||
735 | . ") AS BEGIN\n" |
||
736 | . $sql . ' RETURNING ' . implode(', ', $returning) |
||
737 | . ' INTO ' . implode(', ', $returning) |
||
738 | . ";\nSUSPEND;\nEND;"; |
||
739 | } else { |
||
740 | $sql = $this->db->getQueryBuilder()->insert($table, $columns, $params); |
||
741 | $returning = []; |
||
742 | foreach ((array) $returnColumns as $name) { |
||
743 | $returning[] = $this->quoteColumnName($name); |
||
744 | } |
||
745 | $sql .= ' RETURNING ' . implode(', ', $returning); |
||
746 | } |
||
747 | } |
||
748 | |||
749 | $command = $this->db->createCommand($sql, $params); |
||
750 | $command->prepare(false); |
||
751 | $result = $command->queryOne(); |
||
752 | |||
753 | if (!$command->pdoStatement->rowCount()) { |
||
754 | return false; |
||
755 | } else { |
||
756 | if (!empty($returnColumns)) { |
||
757 | foreach ((array) $returnColumns as $name) { |
||
758 | if ($this->getTableSchema($table)->getColumn($name)->autoIncrement) { |
||
759 | $this->_lastInsertID = $result[$name]; |
||
760 | break; |
||
761 | } |
||
762 | } |
||
763 | } |
||
764 | return $result; |
||
765 | } |
||
766 | } |
||
767 | |||
768 | /** |
||
769 | * @inheritdoc |
||
770 | */ |
||
771 | public function getLastInsertID($sequenceName = '') |
||
772 | { |
||
773 | if (!$this->db->isActive) { |
||
774 | throw new InvalidCallException('DB Connection is not active.'); |
||
775 | } |
||
776 | |||
777 | if ($sequenceName !== '') { |
||
778 | return $this->db->createCommand('SELECT GEN_ID(' . $this->db->quoteTableName($sequenceName) . ', 0 ) FROM RDB$DATABASE;')->queryScalar(); |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
The expression
$this->db->createCommand...BASE;')->queryScalar(); of type string|null|false adds false to the return on line 778 which is incompatible with the return type of the parent method yii\db\Schema::getLastInsertID of type string . It seems like you forgot to handle an error condition.
![]() |
|||
779 | } |
||
780 | |||
781 | if ($this->_lastInsertID !== false) { |
||
782 | return $this->_lastInsertID; |
||
0 ignored issues
–
show
The return type of
return $this->_lastInsertID; (false ) is incompatible with the return type of the parent method yii\db\Schema::getLastInsertID of type string .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function ![]() |
|||
783 | } |
||
784 | return null; |
||
785 | } |
||
786 | |||
787 | protected function loadTablePrimaryKey($tableName) |
||
788 | { |
||
789 | static $sql = <<<'SQL' |
||
790 | SELECT RC.RDB$CONSTRAINT_NAME AS NAME, IDX.RDB$FIELD_NAME AS COLUMN_NAME |
||
791 | FROM RDB$RELATION_CONSTRAINTS RC |
||
792 | JOIN RDB$INDEX_SEGMENTS IDX |
||
793 | ON IDX.RDB$INDEX_NAME = RC.RDB$INDEX_NAME |
||
794 | WHERE RC.RDB$CONSTRAINT_TYPE = 'PRIMARY KEY' |
||
795 | AND UPPER(RC.RDB$RELATION_NAME) = UPPER(:tableName) |
||
796 | ORDER BY IDX.RDB$FIELD_POSITION |
||
797 | SQL; |
||
798 | |||
799 | $resolvedName = $this->resolveTableName($tableName); |
||
800 | $constraints = $this->db->createCommand($sql, [ |
||
801 | ':tableName' => $resolvedName->name, |
||
802 | ])->queryAll(); |
||
803 | $constraints = $this->normalizePdoRowKeyCase($constraints, true); |
||
804 | $constraints = ArrayHelper::index($constraints, null, ['name']); |
||
805 | |||
806 | foreach ($constraints as $name => $constraint) { |
||
807 | $columns = ArrayHelper::getColumn($constraint, 'column_name'); |
||
808 | $columns = array_map('trim', $columns); |
||
809 | $columns = array_map('strtolower', $columns); |
||
810 | return new Constraint([ |
||
811 | 'name' => strtolower(trim($name)), |
||
812 | 'columnNames' => $columns, |
||
813 | ]); |
||
814 | } |
||
815 | |||
816 | return null; |
||
817 | } |
||
818 | |||
819 | protected function loadTableUniques($tableName) |
||
820 | { |
||
821 | static $sql = <<<'SQL' |
||
822 | SELECT RC.RDB$CONSTRAINT_NAME AS NAME, IDX.RDB$FIELD_NAME AS COLUMN_NAME |
||
823 | FROM RDB$RELATION_CONSTRAINTS RC |
||
824 | JOIN RDB$INDEX_SEGMENTS IDX |
||
825 | ON IDX.RDB$INDEX_NAME = RC.RDB$INDEX_NAME |
||
826 | WHERE RC.RDB$CONSTRAINT_TYPE = 'UNIQUE' |
||
827 | AND UPPER(RC.RDB$RELATION_NAME) = UPPER(:tableName) |
||
828 | ORDER BY IDX.RDB$FIELD_POSITION |
||
829 | SQL; |
||
830 | |||
831 | $resolvedName = $this->resolveTableName($tableName); |
||
832 | $constraints = $this->db->createCommand($sql, [ |
||
833 | ':tableName' => $resolvedName->name, |
||
834 | ])->queryAll(); |
||
835 | $constraints = $this->normalizePdoRowKeyCase($constraints, true); |
||
836 | $constraints = ArrayHelper::index($constraints, null, ['name']); |
||
837 | |||
838 | $result = []; |
||
839 | foreach ($constraints as $name => $rows) { |
||
840 | $columns = ArrayHelper::getColumn($rows, 'column_name'); |
||
841 | $columns = array_map('trim', $columns); |
||
842 | $columns = array_map('strtolower', $columns); |
||
843 | $result[] = new Constraint([ |
||
844 | 'name' => strtolower(trim($name)), |
||
845 | 'columnNames' => $columns, |
||
846 | ]); |
||
847 | } |
||
848 | |||
849 | return $result; |
||
850 | } |
||
851 | |||
852 | protected function loadTableChecks($tableName) |
||
853 | { |
||
854 | // DISTINCT not work on blob, need cast to varchar |
||
855 | // 8191 Is max for UTF-8 |
||
856 | static $sql = <<<'SQL' |
||
857 | SELECT DISTINCT RC.RDB$CONSTRAINT_NAME AS NAME, |
||
858 | DEP.RDB$FIELD_NAME AS COLUMN_NAME, |
||
859 | CAST(TRIG.RDB$TRIGGER_SOURCE AS VARCHAR(8191)) AS CHECK_EXPR |
||
860 | FROM RDB$RELATION_CONSTRAINTS RC |
||
861 | JOIN RDB$CHECK_CONSTRAINTS CH_CONST |
||
862 | ON CH_CONST.RDB$CONSTRAINT_NAME = RC.RDB$CONSTRAINT_NAME |
||
863 | JOIN RDB$TRIGGERS TRIG |
||
864 | ON TRIG.RDB$TRIGGER_NAME = CH_CONST.RDB$TRIGGER_NAME |
||
865 | JOIN RDB$DEPENDENCIES DEP |
||
866 | ON DEP.RDB$DEPENDENT_NAME = TRIG.RDB$TRIGGER_NAME |
||
867 | AND DEP.RDB$DEPENDED_ON_NAME = TRIG.RDB$RELATION_NAME |
||
868 | WHERE RC.RDB$CONSTRAINT_TYPE = 'CHECK' |
||
869 | AND UPPER(RC.RDB$RELATION_NAME) = UPPER(:tableName) |
||
870 | SQL; |
||
871 | |||
872 | $resolvedName = $this->resolveTableName($tableName); |
||
873 | $constraints = $this->db->createCommand($sql, [ |
||
874 | ':tableName' => $resolvedName->name, |
||
875 | ])->queryAll(); |
||
876 | $constraints = $this->normalizePdoRowKeyCase($constraints, true); |
||
877 | $constraints = ArrayHelper::index($constraints, null, ['name']); |
||
878 | |||
879 | $result = []; |
||
880 | foreach ($constraints as $name => $constraint) { |
||
881 | $columns = ArrayHelper::getColumn($constraint, 'column_name'); |
||
882 | $columns = array_map('trim', $columns); |
||
883 | $columns = array_map('strtolower', $columns); |
||
884 | |||
885 | $check_expr = $constraint[0]['check_expr']; |
||
886 | $check_expr = preg_replace('/^\s*CHECK\s*/i', '', $check_expr); // remove "CHECK " at begin |
||
887 | $check_expr = preg_replace('/^\((.*)\)$/i', '\1', $check_expr); // remove bracket () at begin and end |
||
888 | |||
889 | $result[] = new CheckConstraint([ |
||
890 | 'name' => strtolower(trim($name)), |
||
891 | 'columnNames' => $columns, |
||
892 | 'expression' => $check_expr, |
||
893 | ]); |
||
894 | } |
||
895 | |||
896 | return $result; |
||
897 | } |
||
898 | |||
899 | protected function loadTableIndexes($tableName) |
||
900 | { |
||
901 | static $sql = <<<'SQL' |
||
902 | SELECT IDX.RDB$INDEX_NAME AS NAME, |
||
903 | SEG.RDB$FIELD_NAME AS COLUMN_NAME, |
||
904 | IDX.RDB$UNIQUE_FLAG AS INDEX_IS_UNIQUE, |
||
905 | CASE WHEN CONST.RDB$CONSTRAINT_NAME IS NOT NULL THEN 1 ELSE 0 END AS INDEX_IS_PRIMARY |
||
906 | FROM RDB$INDICES IDX |
||
907 | JOIN RDB$INDEX_SEGMENTS SEG |
||
908 | LEFT JOIN RDB$RELATION_CONSTRAINTS CONST ON CONST.RDB$INDEX_NAME = SEG.RDB$INDEX_NAME AND CONST.RDB$CONSTRAINT_TYPE = 'PRIMARY KEY' |
||
909 | ON SEG.RDB$INDEX_NAME = IDX.RDB$INDEX_NAME |
||
910 | WHERE UPPER(IDX.RDB$RELATION_NAME) = UPPER(:tableName) |
||
911 | ORDER BY SEG.RDB$FIELD_POSITION |
||
912 | SQL; |
||
913 | |||
914 | $resolvedName = $this->resolveTableName($tableName); |
||
915 | $indexes = $this->db->createCommand($sql, [ |
||
916 | ':tableName' => $resolvedName->name, |
||
917 | ])->queryAll(); |
||
918 | $indexes = $this->normalizePdoRowKeyCase($indexes, true); |
||
919 | $indexes = ArrayHelper::index($indexes, null, 'name'); |
||
920 | $result = []; |
||
921 | foreach ($indexes as $name => $index) { |
||
922 | $columns = ArrayHelper::getColumn($index, 'column_name'); |
||
923 | $columns = array_map('trim', $columns); |
||
924 | $columns = array_map('strtolower', $columns); |
||
925 | |||
926 | $result[] = new IndexConstraint([ |
||
927 | 'isPrimary' => (bool) $index[0]['index_is_primary'], |
||
928 | 'isUnique' => (bool) $index[0]['index_is_unique'], |
||
929 | 'name' => strtolower(trim($name)), |
||
930 | 'columnNames' => $columns, |
||
931 | ]); |
||
932 | } |
||
933 | |||
934 | return $result; |
||
935 | } |
||
936 | |||
937 | protected function loadTableDefaultValues($tableName) |
||
0 ignored issues
–
show
|
|||
938 | { |
||
939 | throw new \yii\base\NotSupportedException('FirebirdSQL does not support default value constraints.'); |
||
940 | } |
||
941 | |||
942 | protected function loadTableForeignKeys($tableName) |
||
943 | { |
||
944 | static $sql = <<<'SQL' |
||
945 | SELECT A.RDB$CONSTRAINT_NAME AS NAME, |
||
946 | E.RDB$FIELD_NAME AS COLUMN_NAME, |
||
947 | C.RDB$RELATION_NAME AS FOREIGN_TABLE_NAME, |
||
948 | D.RDB$FIELD_NAME AS FOREIGN_COLUMN_NAME, |
||
949 | B.RDB$UPDATE_RULE AS ON_UPDATE, |
||
950 | B.RDB$DELETE_RULE AS ON_DELETE |
||
951 | FROM RDB$REF_CONSTRAINTS B |
||
952 | JOIN RDB$RELATION_CONSTRAINTS A |
||
953 | ON A.RDB$CONSTRAINT_NAME = B.RDB$CONSTRAINT_NAME |
||
954 | JOIN RDB$RELATION_CONSTRAINTS C |
||
955 | ON B.RDB$CONST_NAME_UQ = C.RDB$CONSTRAINT_NAME |
||
956 | JOIN RDB$INDEX_SEGMENTS D |
||
957 | ON C.RDB$INDEX_NAME = D.RDB$INDEX_NAME |
||
958 | JOIN RDB$INDEX_SEGMENTS E |
||
959 | ON A.RDB$INDEX_NAME = E.RDB$INDEX_NAME |
||
960 | AND E.RDB$FIELD_POSITION = D.RDB$FIELD_POSITION |
||
961 | WHERE A.RDB$CONSTRAINT_TYPE = 'FOREIGN KEY' |
||
962 | AND UPPER(A.RDB$RELATION_NAME) = UPPER(:tableName) |
||
963 | ORDER BY E.RDB$FIELD_POSITION |
||
964 | SQL; |
||
965 | |||
966 | $resolvedName = $this->resolveTableName($tableName); |
||
967 | $constraints = $this->db->createCommand($sql, [ |
||
968 | ':tableName' => $resolvedName->name, |
||
969 | ])->queryAll(); |
||
970 | $constraints = $this->normalizePdoRowKeyCase($constraints, true); |
||
971 | $constraints = ArrayHelper::index($constraints, null, ['name']); |
||
972 | |||
973 | $result = []; |
||
974 | foreach ($constraints as $name => $constraint) { |
||
975 | $columnNames = ArrayHelper::getColumn($constraint, 'column_name'); |
||
976 | $columnNames = array_map('trim', $columnNames); |
||
977 | $columnNames = array_map('strtolower', $columnNames); |
||
978 | |||
979 | $foreignColumnNames = ArrayHelper::getColumn($constraint, 'foreign_column_name'); |
||
980 | $foreignColumnNames = array_map('trim', $foreignColumnNames); |
||
981 | $foreignColumnNames = array_map('strtolower', $foreignColumnNames); |
||
982 | |||
983 | $result[] = new ForeignKeyConstraint([ |
||
984 | 'name' => strtolower(trim($name)), |
||
985 | 'columnNames' => $columnNames, |
||
986 | 'foreignTableName' => strtolower(trim($constraint[0]['foreign_table_name'])), |
||
987 | 'foreignColumnNames' => $foreignColumnNames, |
||
988 | 'onDelete' => trim($constraint[0]['on_delete']), |
||
989 | 'onUpdate' => trim($constraint[0]['on_update']), |
||
990 | ]); |
||
991 | } |
||
992 | |||
993 | return $result; |
||
994 | } |
||
995 | |||
996 | protected function findViewNames($schema = '') |
||
0 ignored issues
–
show
|
|||
997 | { |
||
998 | $sql = <<<'SQL' |
||
999 | SELECT RDB$RELATION_NAME |
||
1000 | FROM RDB$RELATIONS |
||
1001 | WHERE RDB$VIEW_BLR IS NOT NULL |
||
1002 | AND (RDB$SYSTEM_FLAG IS NULL OR RDB$SYSTEM_FLAG = 0) |
||
1003 | SQL; |
||
1004 | |||
1005 | $views = $this->db->createCommand($sql)->queryColumn(); |
||
1006 | $views = array_map('trim', $views); |
||
1007 | $views = array_map('strtolower', $views); |
||
1008 | |||
1009 | return $views; |
||
1010 | } |
||
1011 | } |
||
1012 |
Let’s assume that you have a directory layout like this:
and let’s assume the following content of
Bar.php
:If both files
OtherDir/Foo.php
andSomeDir/Foo.php
are loaded in the same runtime, you will see a PHP error such as the following:PHP Fatal error: Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php
However, as
OtherDir/Foo.php
does not necessarily have to be loaded and the error is only triggered if it is loaded beforeOtherDir/Bar.php
, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias: