1 | <?php |
||||
2 | |||||
3 | namespace Graze\Morphism; |
||||
4 | |||||
5 | use Doctrine\DBAL\Connection; |
||||
6 | use Doctrine\DBAL\DBALException; |
||||
7 | use Graze\Morphism\Parse\Token; |
||||
8 | use PDO; |
||||
9 | |||||
10 | /** |
||||
11 | * Fast database schema extractor - instead of using mysqldump, it talks |
||||
12 | * directly to the INFORMATION_SCHEMA, resulting in a 2x speedup. |
||||
13 | * phpcs:ignoreFile Squiz.NamingConventions.ValidVariableName |
||||
14 | */ |
||||
15 | class Extractor |
||||
16 | { |
||||
17 | /** @var Connection */ |
||||
18 | private $dbh = null; |
||||
19 | /** @var array */ |
||||
20 | private $databases = null; |
||||
21 | /** @var bool */ |
||||
22 | private $createDatabase = true; |
||||
23 | /** @var bool */ |
||||
24 | private $quoteNames = true; |
||||
25 | |||||
26 | /** |
||||
27 | * Constructor |
||||
28 | * @param Connection$dbh |
||||
29 | */ |
||||
30 | public function __construct(Connection $dbh) |
||||
31 | { |
||||
32 | $this->dbh = $dbh; |
||||
33 | } |
||||
34 | |||||
35 | /** |
||||
36 | * If $flag is true, the extractor will output CREATE DATABASE and USE |
||||
37 | * statements. Defaults to true. |
||||
38 | * |
||||
39 | * @param bool $flag |
||||
40 | */ |
||||
41 | public function setCreateDatabases($flag) |
||||
42 | { |
||||
43 | $this->createDatabase = (bool) $flag; |
||||
44 | } |
||||
45 | |||||
46 | /** |
||||
47 | * Specifies the database schemas to extract. All non-system schemas |
||||
48 | * (i.e. not MYSQL or INFORMATION_SCHEMA) will be extracted if none |
||||
49 | * are specified. |
||||
50 | * |
||||
51 | * @param string[] $databases |
||||
52 | */ |
||||
53 | public function setDatabases(array $databases) |
||||
54 | { |
||||
55 | $this->databases = $databases; |
||||
56 | } |
||||
57 | |||||
58 | /** |
||||
59 | * If $flags is true, the extractor will enclose names of database objects |
||||
60 | * (schemas, tables, columns, etc) in backquotes. Defaults to true. |
||||
61 | * |
||||
62 | * @param bool $flag |
||||
63 | */ |
||||
64 | public function setQuoteNames($flag) |
||||
65 | { |
||||
66 | $this->quoteNames = (bool) $flag; |
||||
67 | } |
||||
68 | |||||
69 | /** |
||||
70 | * Prepare, bind, and execute the specified query against the current |
||||
71 | * connection, and return the result set as an array of objects. |
||||
72 | * |
||||
73 | * @param string $sql |
||||
74 | * @param mixed[] $binds |
||||
75 | * @return array result-row-object[] |
||||
76 | * @throws DBALException |
||||
77 | */ |
||||
78 | private function query($sql, array $binds = []) |
||||
79 | { |
||||
80 | $sth = $this->dbh->prepare($sql); |
||||
81 | $sth->execute($binds); |
||||
0 ignored issues
–
show
|
|||||
82 | $rows = $sth->fetchAll(PDO::FETCH_OBJ); |
||||
0 ignored issues
–
show
The function
Doctrine\DBAL\Statement::fetchAll() has been deprecated: Use fetchAllNumeric(), fetchAllAssociative() or fetchFirstColumn() instead.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() |
|||||
83 | return $rows; |
||||
84 | } |
||||
85 | |||||
86 | /** |
||||
87 | * Returns $count comma-separated placeholders (e.g. "?", "?,?", etc) |
||||
88 | * or "NULL" if $count is zero, suitable for use with an IN() clause in |
||||
89 | * a prepared query. |
||||
90 | * |
||||
91 | * @param int|array $count |
||||
92 | * @return string |
||||
93 | */ |
||||
94 | private static function placeholders($count) |
||||
95 | { |
||||
96 | if (is_array($count)) { |
||||
97 | $count = count($count); |
||||
98 | } |
||||
99 | if ($count == 0) { |
||||
100 | return "NULL"; |
||||
101 | } |
||||
102 | return implode(',', array_fill(0, $count, '?')); |
||||
103 | } |
||||
104 | |||||
105 | /** |
||||
106 | * @return array [$schema => SCHEMATA-object, ...] |
||||
107 | * @throws DBALException |
||||
108 | */ |
||||
109 | private function getSchemata() |
||||
110 | { |
||||
111 | if (count($this->databases) == 0) { |
||||
112 | $rows = $this->query(" |
||||
113 | SELECT * |
||||
114 | FROM INFORMATION_SCHEMA.SCHEMATA |
||||
115 | WHERE SCHEMA_NAME NOT IN ('mysql', 'information_schema') |
||||
116 | "); |
||||
117 | } else { |
||||
118 | $binds = $this->databases; |
||||
119 | $placeholders = self::placeholders($binds); |
||||
120 | $rows = $this->query( |
||||
121 | " |
||||
122 | SELECT * |
||||
123 | FROM INFORMATION_SCHEMA.SCHEMATA |
||||
124 | WHERE SCHEMA_NAME IN ($placeholders) |
||||
125 | ", |
||||
126 | $binds |
||||
127 | ); |
||||
128 | } |
||||
129 | |||||
130 | $schemata = []; |
||||
131 | foreach ($rows as $schema) { |
||||
132 | $schemata[$schema->SCHEMA_NAME] = $schema; |
||||
133 | } |
||||
134 | return $schemata; |
||||
135 | } |
||||
136 | |||||
137 | /** |
||||
138 | * @param array $databases |
||||
139 | * @return array [$schema => [$table => TABLES-object, ...], ...] |
||||
140 | * @throws DBALException |
||||
141 | */ |
||||
142 | private function getTables(array $databases) |
||||
143 | { |
||||
144 | $placeholders = self::placeholders($databases); |
||||
145 | $rows = $this->query( |
||||
146 | " |
||||
147 | SELECT * |
||||
148 | FROM INFORMATION_SCHEMA.TABLES |
||||
149 | WHERE |
||||
150 | TABLE_SCHEMA IN ($placeholders) AND |
||||
151 | TABLE_TYPE = 'BASE TABLE' |
||||
152 | ORDER BY |
||||
153 | TABLE_SCHEMA, |
||||
154 | TABLE_NAME |
||||
155 | ", |
||||
156 | $databases |
||||
157 | ); |
||||
158 | $tables = []; |
||||
159 | foreach ($rows as $table) { |
||||
160 | $tables[$table->TABLE_SCHEMA][$table->TABLE_NAME] = $table; |
||||
161 | } |
||||
162 | return $tables; |
||||
163 | } |
||||
164 | |||||
165 | /** |
||||
166 | * @param string[] $databases |
||||
167 | * @return array [$schema => [$table => [COLUMNS-object, ...], ...], ...] |
||||
168 | * @throws DBALException |
||||
169 | */ |
||||
170 | private function getColumns(array $databases) |
||||
171 | { |
||||
172 | $placeholders = self::placeholders($databases); |
||||
173 | $rows = $this->query( |
||||
174 | " |
||||
175 | SELECT * |
||||
176 | FROM INFORMATION_SCHEMA.COLUMNS |
||||
177 | WHERE TABLE_SCHEMA IN ($placeholders) |
||||
178 | ORDER BY |
||||
179 | TABLE_SCHEMA, |
||||
180 | TABLE_NAME, |
||||
181 | ORDINAL_POSITION |
||||
182 | ", |
||||
183 | $databases |
||||
184 | ); |
||||
185 | $columns = []; |
||||
186 | foreach ($rows as $column) { |
||||
187 | $columns[$column->TABLE_SCHEMA][$column->TABLE_NAME][$column->ORDINAL_POSITION] = $column; |
||||
188 | } |
||||
189 | return $columns; |
||||
190 | } |
||||
191 | |||||
192 | /** |
||||
193 | * @param string[] $databases |
||||
194 | * @return array [$schema => [$table => [$index => [STATISTICS-object, ...], ...], ...], ...] |
||||
195 | * @throws DBALException |
||||
196 | */ |
||||
197 | private function getKeys(array $databases) |
||||
198 | { |
||||
199 | $placeholders = self::placeholders($databases); |
||||
200 | $rows = $this->query( |
||||
201 | " |
||||
202 | SELECT * |
||||
203 | FROM INFORMATION_SCHEMA.STATISTICS |
||||
204 | WHERE TABLE_SCHEMA IN ($placeholders) |
||||
205 | ORDER BY |
||||
206 | TABLE_SCHEMA, |
||||
207 | TABLE_NAME, |
||||
208 | INDEX_NAME = 'PRIMARY' DESC, |
||||
209 | INDEX_NAME, |
||||
210 | SEQ_IN_INDEX |
||||
211 | ", |
||||
212 | $databases |
||||
213 | ); |
||||
214 | $keys = []; |
||||
215 | foreach ($rows as $key) { |
||||
216 | $keys[$key->TABLE_SCHEMA][$key->TABLE_NAME][$key->INDEX_NAME][] = $key; |
||||
217 | } |
||||
218 | return $keys; |
||||
219 | } |
||||
220 | |||||
221 | /** |
||||
222 | * @param string[] $databases |
||||
223 | * @return array [$schema => [$table => [$constraint => [KEY_COLUMN_USAGE-object, ...], ...], ...], ...] |
||||
224 | * @throws DBALException |
||||
225 | */ |
||||
226 | private function getReferences(array $databases) |
||||
227 | { |
||||
228 | $placeholders = self::placeholders($databases); |
||||
229 | $rows = $this->query( |
||||
230 | " |
||||
231 | SELECT * |
||||
232 | FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE |
||||
233 | WHERE TABLE_SCHEMA IN ($placeholders) |
||||
234 | AND REFERENCED_TABLE_SCHEMA IS NOT NULL |
||||
235 | ORDER BY |
||||
236 | TABLE_SCHEMA, |
||||
237 | TABLE_NAME, |
||||
238 | CONSTRAINT_NAME, |
||||
239 | ORDINAL_POSITION |
||||
240 | ", |
||||
241 | $databases |
||||
242 | ); |
||||
243 | $references = []; |
||||
244 | foreach ($rows as $reference) { |
||||
245 | $references[$reference->TABLE_SCHEMA][$reference->TABLE_NAME][$reference->CONSTRAINT_NAME][] = $reference; |
||||
246 | } |
||||
247 | return $references; |
||||
248 | } |
||||
249 | |||||
250 | /** |
||||
251 | * @param array $databases |
||||
252 | * @return array |
||||
253 | * @throws DBALException |
||||
254 | */ |
||||
255 | private function getConstraints(array $databases) |
||||
256 | { |
||||
257 | $placeholders = self::placeholders($databases); |
||||
258 | $rows = $this->query( |
||||
259 | " |
||||
260 | SELECT * |
||||
261 | FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS |
||||
262 | WHERE CONSTRAINT_SCHEMA IN ($placeholders) |
||||
263 | ORDER BY |
||||
264 | CONSTRAINT_SCHEMA, |
||||
265 | TABLE_NAME, |
||||
266 | CONSTRAINT_NAME |
||||
267 | ", |
||||
268 | $databases |
||||
269 | ); |
||||
270 | $constraints = []; |
||||
271 | foreach ($rows as $constraint) { |
||||
272 | $constraints[$constraint->CONSTRAINT_SCHEMA][$constraint->TABLE_NAME][$constraint->CONSTRAINT_NAME] = $constraint; |
||||
273 | } |
||||
274 | return $constraints; |
||||
275 | } |
||||
276 | |||||
277 | /** |
||||
278 | * Returns an array of SQL DDL statements to create the specified database. |
||||
279 | * |
||||
280 | * @param mixed $schema SCHEMA-object |
||||
281 | * @return string[] |
||||
282 | */ |
||||
283 | private function getCreateDatabase($schema) |
||||
284 | { |
||||
285 | $escapedDatabase = Token::escapeIdentifier($schema->SCHEMA_NAME); |
||||
286 | return [ |
||||
287 | "CREATE DATABASE $escapedDatabase" . |
||||
288 | " DEFAULT CHARACTER SET $schema->DEFAULT_CHARACTER_SET_NAME" . |
||||
289 | " COLLATE $schema->DEFAULT_COLLATION_NAME", |
||||
290 | ]; |
||||
291 | } |
||||
292 | |||||
293 | /** |
||||
294 | * Returns an array of SQL statements to select the specified database |
||||
295 | * as the default for the connection. |
||||
296 | * |
||||
297 | * @param mixed $schema SCHEMA-object |
||||
298 | * @return string[] |
||||
299 | */ |
||||
300 | private function getUseDatabase($schema) |
||||
301 | { |
||||
302 | $escapedDatabase = Token::escapeIdentifier($schema->SCHEMA_NAME); |
||||
303 | return [ |
||||
304 | "USE $escapedDatabase", |
||||
305 | ]; |
||||
306 | } |
||||
307 | |||||
308 | /** |
||||
309 | * Returns an array of clauses that will form part of a CREATE TABLE statement |
||||
310 | * to create the specified columns. |
||||
311 | * |
||||
312 | * @param array $columns COLUMNS-object[] |
||||
313 | * @return string[] |
||||
314 | */ |
||||
315 | private function getColumnDefs(array $columns) |
||||
316 | { |
||||
317 | $defColumns = []; |
||||
318 | foreach ($columns as $column) { |
||||
319 | $defColumn = "$column->COLUMN_NAME"; |
||||
320 | $defColumn .= " $column->COLUMN_TYPE"; |
||||
321 | if (!is_null($column->CHARACTER_SET_NAME)) { |
||||
322 | $defColumn .= " CHARACTER SET $column->CHARACTER_SET_NAME"; |
||||
323 | } |
||||
324 | if (!is_null($column->COLLATION_NAME)) { |
||||
325 | $defColumn .= " COLLATE $column->COLLATION_NAME"; |
||||
326 | } |
||||
327 | if ($column->IS_NULLABLE == 'NO') { |
||||
328 | $defColumn .= " NOT NULL"; |
||||
329 | } else { |
||||
330 | $defColumn .= " NULL"; |
||||
331 | } |
||||
332 | // Maria DB defines null default columns as string 'NULL' rather than null, these need to be ignored. |
||||
333 | if (!is_null($column->COLUMN_DEFAULT) && !($column->IS_NULLABLE == 'YES' && $column->COLUMN_DEFAULT == 'NULL')) { |
||||
334 | if (in_array($column->DATA_TYPE, ['timestamp', 'datetime']) && |
||||
335 | $column->COLUMN_DEFAULT == 'CURRENT_TIMESTAMP' |
||||
336 | ) { |
||||
337 | $defColumn .= " DEFAULT $column->COLUMN_DEFAULT"; |
||||
338 | } else { |
||||
339 | $defColumn .= " DEFAULT " . Token::escapeString($column->COLUMN_DEFAULT); |
||||
340 | } |
||||
341 | } |
||||
342 | if ($column->EXTRA != '') { |
||||
343 | $defColumn .= " $column->EXTRA"; |
||||
344 | } |
||||
345 | if ($column->COLUMN_COMMENT != '') { |
||||
346 | $defColumn .= " COMMENT " . Token::escapeString($column->COLUMN_COMMENT); |
||||
347 | } |
||||
348 | $defColumns[] = " $defColumn"; |
||||
349 | } |
||||
350 | return $defColumns; |
||||
351 | } |
||||
352 | |||||
353 | /** |
||||
354 | * Returns an array of clauses that will form part of a CREATE TABLE statement |
||||
355 | * to create the specified indexes. |
||||
356 | * |
||||
357 | * @param array $keys [$index => STATISTICS-object[]] |
||||
358 | * @return string[] |
||||
359 | */ |
||||
360 | private function getKeyDefs(array $keys) |
||||
361 | { |
||||
362 | $defKeys = []; |
||||
363 | foreach ($keys as $key) { |
||||
364 | $firstKeyPart = $key[0]; |
||||
365 | if ($firstKeyPart->INDEX_NAME == 'PRIMARY') { |
||||
366 | $defKey = 'PRIMARY KEY'; |
||||
367 | } else { |
||||
368 | $escapedIndexName = Token::escapeIdentifier($firstKeyPart->INDEX_NAME); |
||||
369 | if ($firstKeyPart->INDEX_TYPE == 'FULLTEXT') { |
||||
370 | $defKey = "FULLTEXT $escapedIndexName"; |
||||
371 | } elseif ($firstKeyPart->NON_UNIQUE) { |
||||
372 | $defKey = "KEY $escapedIndexName"; |
||||
373 | } else { |
||||
374 | $defKey = "UNIQUE KEY $escapedIndexName"; |
||||
375 | } |
||||
376 | } |
||||
377 | $defKeyParts = []; |
||||
378 | foreach ($key as $keyPart) { |
||||
379 | $defKeyPart = $keyPart->COLUMN_NAME; |
||||
380 | if (!is_null($keyPart->SUB_PART)) { |
||||
381 | $defKeyPart .= "($keyPart->SUB_PART)"; |
||||
382 | } |
||||
383 | $defKeyParts[] = $defKeyPart; |
||||
384 | } |
||||
385 | $defKeys[] = " $defKey (" . implode(',', $defKeyParts) . ")"; |
||||
386 | } |
||||
387 | return $defKeys; |
||||
388 | } |
||||
389 | |||||
390 | /** |
||||
391 | * Returns an array of clauses that will form part of a CREATE TABLE statement |
||||
392 | * to create the specified foreign key constraints. |
||||
393 | * |
||||
394 | * @param array $references [$constraint => [KEY_COLUMN_USAGE-object, ...], ...] |
||||
395 | * @param array $constraints [$constraint => REFERENTIAL_CONSTRAINTS-object, ...] |
||||
396 | * @return string[] |
||||
397 | */ |
||||
398 | private function getReferenceDefs(array $references, array $constraints) |
||||
399 | { |
||||
400 | $defReferences = []; |
||||
401 | foreach ($references as $reference) { |
||||
402 | $firstRefPart = $reference[0]; |
||||
403 | $constraintName = Token::escapeIdentifier($firstRefPart->CONSTRAINT_NAME); |
||||
404 | $referencedTable = Token::escapeIdentifier($firstRefPart->REFERENCED_TABLE_NAME); |
||||
405 | if ($firstRefPart->REFERENCED_TABLE_SCHEMA != $firstRefPart->TABLE_SCHEMA) { |
||||
406 | $referencedTable = Token::escapeIdentifier($firstRefPart->REFERENCED_TABLE_SCHEMA) . '.' . $referencedTable; |
||||
407 | } |
||||
408 | $defForeignParts = []; |
||||
409 | $defReferenceParts = []; |
||||
410 | foreach ($reference as $referencePart) { |
||||
411 | $defForeignParts[] = Token::escapeIdentifier($referencePart->COLUMN_NAME); |
||||
412 | $defReferenceParts[] = Token::escapeIdentifier($referencePart->REFERENCED_COLUMN_NAME); |
||||
413 | } |
||||
414 | $constraint = $constraints[$firstRefPart->CONSTRAINT_NAME]; |
||||
415 | $options = ""; |
||||
416 | if ($constraint->MATCH_OPTION != 'NONE') { |
||||
417 | $options = " MATCH " . $constraint->MATCH_OPTION; |
||||
418 | } |
||||
419 | if ($constraint->UPDATE_RULE != 'RESTRICT') { |
||||
420 | $options .= " ON UPDATE " . $constraint->UPDATE_RULE; |
||||
421 | } |
||||
422 | if ($constraint->DELETE_RULE != 'RESTRICT') { |
||||
423 | $options .= " ON DELETE " . $constraint->DELETE_RULE; |
||||
424 | } |
||||
425 | $defReferences[] = |
||||
426 | " CONSTRAINT $constraintName" . |
||||
427 | " FOREIGN KEY (" . implode(',', $defForeignParts) . ")" . |
||||
428 | " REFERENCES $referencedTable (" . implode(',', $defReferenceParts) . ")" . |
||||
429 | $options; |
||||
430 | } |
||||
431 | return $defReferences; |
||||
432 | } |
||||
433 | |||||
434 | /** |
||||
435 | * Returns an array of table options which will form part of the DDL |
||||
436 | * necessary to create the specified table. |
||||
437 | * |
||||
438 | * @param mixed $table TABLES-object[] |
||||
439 | * @return string[] |
||||
440 | */ |
||||
441 | private function getTableOptionDefs($table) |
||||
442 | { |
||||
443 | $defTableOptions = []; |
||||
444 | $defTableOptions[] = "ENGINE=$table->ENGINE"; |
||||
445 | if (strcasecmp($table->ROW_FORMAT, 'COMPACT') != 0) { |
||||
446 | $defTableOptions[] = "ROW_FORMAT=$table->ROW_FORMAT"; |
||||
447 | } |
||||
448 | if ($table->AUTO_INCREMENT) { |
||||
449 | $defTableOptions[] = "AUTO_INCREMENT=$table->AUTO_INCREMENT"; |
||||
450 | } |
||||
451 | $collate = $table->TABLE_COLLATION; |
||||
452 | list($charset) = explode('_', $table->TABLE_COLLATION); |
||||
453 | $defTableOptions[] = "DEFAULT CHARSET=$charset COLLATE=$collate"; |
||||
454 | if ($table->CREATE_OPTIONS != '') { |
||||
455 | $defTableOptions[] = $table->CREATE_OPTIONS; |
||||
456 | } |
||||
457 | if ($table->TABLE_COMMENT != '') { |
||||
458 | $defTableOptions[] = "COMMENT " . Token::escapeString($table->TABLE_COMMENT); |
||||
459 | } |
||||
460 | return $defTableOptions; |
||||
461 | } |
||||
462 | |||||
463 | /** |
||||
464 | * Returns an array of SQL DDL statements to create the specified table. |
||||
465 | * |
||||
466 | * @param mixed $table TABLES-object |
||||
467 | * @param array $columns COLUMNS-object[] |
||||
468 | * @param array $keys [$index => STATISTICS-object[]] |
||||
469 | * @param array $references [$constraint => [KEY_COLUMN_USAGE-object, ...], ...] |
||||
470 | * @param array $constraints [$constraint => REFERENTIAL_CONSTRAINTS-object, ...] |
||||
471 | * @return array |
||||
472 | */ |
||||
473 | private function getCreateTable($table, array $columns, array $keys, array $references, array $constraints) |
||||
474 | { |
||||
475 | $tableName = $table->TABLE_NAME; |
||||
476 | |||||
477 | $defColumns = $this->getColumnDefs($columns); |
||||
478 | $defKeys = $this->getKeyDefs($keys); |
||||
479 | $defReferences = $this->getReferenceDefs($references, $constraints); |
||||
480 | $defTableOptions = $this->getTableOptionDefs($table); |
||||
481 | |||||
482 | return [ |
||||
483 | "CREATE TABLE " . Token::escapeIdentifier($tableName) . " (\n" . |
||||
484 | implode(",\n", array_merge($defColumns, $defKeys, $defReferences)) . "\n" . |
||||
485 | ") " . implode(' ', $defTableOptions), |
||||
486 | ]; |
||||
487 | } |
||||
488 | |||||
489 | /** |
||||
490 | * Returns an array of SQL DDL statements extracted from the database |
||||
491 | * connection provided at construction. |
||||
492 | * |
||||
493 | * @return string[] |
||||
494 | * @throws DBALException |
||||
495 | */ |
||||
496 | public function extract() |
||||
497 | { |
||||
498 | Token::setQuoteNames($this->quoteNames); |
||||
499 | |||||
500 | $schemata = $this->getSchemata(); |
||||
501 | $databases = array_keys($schemata); |
||||
502 | $tables = $this->getTables($databases); |
||||
503 | $columns = $this->getColumns($databases); |
||||
504 | $keys = $this->getKeys($databases); |
||||
505 | $references = $this->getReferences($databases); |
||||
506 | $constraints = $this->getConstraints($databases); |
||||
507 | |||||
508 | $statements = []; |
||||
509 | foreach ($schemata as $database => $schema) { |
||||
510 | if ($this->createDatabase) { |
||||
511 | $statements = array_merge( |
||||
512 | $statements, |
||||
513 | $this->getCreateDatabase($schema), |
||||
514 | $this->getUseDatabase($schema) |
||||
515 | ); |
||||
516 | } |
||||
517 | |||||
518 | foreach (isset($tables[$database]) ? $tables[$database] : [] as $tableName => $table) { |
||||
519 | $tableColumns = $columns[$database][$tableName]; |
||||
520 | $tableKeys = isset($keys[$database][$tableName]) ? $keys[$database][$tableName] : []; |
||||
521 | $tableReferences = isset($references[$database][$tableName]) ? $references[$database][$tableName] : []; |
||||
522 | $tableConstraints = isset($constraints[$database][$tableName]) ? $constraints[$database][$tableName] : []; |
||||
523 | $statements = array_merge($statements, $this->getCreateTable($table, $tableColumns, $tableKeys, $tableReferences, $tableConstraints)); |
||||
524 | } |
||||
525 | } |
||||
526 | |||||
527 | return $statements; |
||||
528 | } |
||||
529 | } |
||||
530 |
This function has been deprecated. The supplier of the function has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.