1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Phinx |
4
|
|
|
* |
5
|
|
|
* (The MIT license) |
6
|
|
|
* Copyright (c) 2015 Rob Morgan |
7
|
|
|
* |
8
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy |
9
|
|
|
* of this software and associated * documentation files (the "Software"), to |
10
|
|
|
* deal in the Software without restriction, including without limitation the |
11
|
|
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
12
|
|
|
* sell copies of the Software, and to permit persons to whom the Software is |
13
|
|
|
* furnished to do so, subject to the following conditions: |
14
|
|
|
* |
15
|
|
|
* The above copyright notice and this permission notice shall be included in |
16
|
|
|
* all copies or substantial portions of the Software. |
17
|
|
|
* |
18
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
19
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
20
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
21
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
22
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
23
|
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
24
|
|
|
* IN THE SOFTWARE. |
25
|
|
|
* |
26
|
|
|
* @package Phinx |
27
|
|
|
* @subpackage Phinx\Db\Adapter |
28
|
|
|
*/ |
29
|
|
|
namespace Phinx\Db\Adapter; |
30
|
|
|
|
31
|
|
|
use Phinx\Db\Table; |
32
|
|
|
use Phinx\Db\Table\Column; |
33
|
|
|
use Phinx\Db\Table\ForeignKey; |
34
|
|
|
use Phinx\Db\Table\Index; |
35
|
|
|
use Phinx\Migration\MigrationInterface; |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* Phinx Oracle Adapter. |
39
|
|
|
* |
40
|
|
|
* @author Felipe Maia <[email protected]> |
41
|
|
|
*/ |
42
|
|
|
class OracleAdapter extends PdoAdapter implements AdapterInterface |
43
|
|
|
{ |
44
|
|
|
protected $schema = 'dbo'; |
45
|
|
|
|
46
|
|
|
protected $signedColumnTypes = ['integer' => true, 'biginteger' => true, 'float' => true, 'decimal' => true]; |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* {@inheritdoc} |
50
|
|
|
*/ |
51
|
|
|
public function connect() |
52
|
|
|
{ |
53
|
|
|
if ($this->connection === null) { |
54
|
|
|
if (!extension_loaded('pdo_oci')) { |
55
|
|
|
// @codeCoverageIgnoreStart |
56
|
|
|
throw new \RuntimeException('You need to enable the PDO_OCI extension for Phinx to run properly.'); |
57
|
|
|
// @codeCoverageIgnoreEnd |
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
$options = $this->getOptions(); |
61
|
|
|
|
62
|
|
|
// if port is specified use it, otherwise use the Oracle default |
63
|
|
View Code Duplication |
if (empty($options['port'])) { |
|
|
|
|
64
|
|
|
$dsn = "oci:dbname=//" . $options['host'] . "/" . $options['sid'] . ""; |
65
|
|
|
} else { |
66
|
|
|
$dsn = "oci:dbname=//" . $options['host'] . ":" . $options['port'] . "/" . $options['sid'] . ""; |
67
|
|
|
} |
68
|
|
|
|
69
|
|
|
$driverOptions = [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION]; |
70
|
|
|
|
71
|
|
|
try { |
72
|
|
|
$db = new \PDO($dsn, $options['user'], $options['pass'], $driverOptions); |
73
|
|
|
} catch (\PDOException $exception) { |
74
|
|
|
throw new \InvalidArgumentException(sprintf( |
75
|
|
|
'There was a problem connecting to the database: %s', |
76
|
|
|
$exception->getMessage() |
77
|
|
|
)); |
78
|
|
|
} |
79
|
|
|
$this->setConnection($db); |
80
|
|
|
} |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* {@inheritdoc} |
85
|
|
|
*/ |
86
|
|
|
public function disconnect() |
87
|
|
|
{ |
88
|
|
|
$this->connection = null; |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
/** |
92
|
|
|
* {@inheritdoc} |
93
|
|
|
*/ |
94
|
|
|
public function hasTransactions() |
95
|
|
|
{ |
96
|
|
|
return true; |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
/** |
100
|
|
|
* {@inheritdoc} |
101
|
|
|
*/ |
102
|
|
|
public function beginTransaction() |
103
|
|
|
{ |
104
|
|
|
// $this->execute('BEGIN TRANSACTION'); |
|
|
|
|
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
/** |
108
|
|
|
* {@inheritdoc} |
109
|
|
|
*/ |
110
|
|
|
public function commitTransaction() |
111
|
|
|
{ |
112
|
|
|
// $this->execute('COMMIT TRANSACTION'); |
|
|
|
|
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
/** |
116
|
|
|
* {@inheritdoc} |
117
|
|
|
*/ |
118
|
|
|
public function rollbackTransaction() |
119
|
|
|
{ |
120
|
|
|
// $this->execute('ROLLBACK TRANSACTION'); |
|
|
|
|
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
/** |
124
|
|
|
* {@inheritdoc} |
125
|
|
|
*/ |
126
|
|
|
public function quoteTableName($tableName) |
127
|
|
|
{ |
128
|
|
|
return str_replace('.', '].[', $this->quoteColumnName($tableName)); |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
/** |
132
|
|
|
* {@inheritdoc} |
133
|
|
|
*/ |
134
|
|
|
public function quoteColumnName($columnName) |
135
|
|
|
{ |
136
|
|
|
return '"' . str_replace(']', '"', $columnName) . '"'; |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
/** |
140
|
|
|
* {@inheritdoc} |
141
|
|
|
*/ |
142
|
|
|
public function hasTable($tableName) |
143
|
|
|
{ |
144
|
|
|
$result = $this->fetchRow( |
145
|
|
|
sprintf( |
146
|
|
|
'SELECT count(*) as count FROM ALL_TABLES WHERE table_name = \'%s\'', |
147
|
|
|
$tableName |
148
|
|
|
) |
149
|
|
|
); |
150
|
|
|
|
151
|
|
|
return $result['COUNT'] > 0; |
152
|
|
|
} |
153
|
|
|
|
154
|
|
|
/** |
155
|
|
|
* {@inheritdoc} |
156
|
|
|
*/ |
157
|
|
|
public function createTable(Table $table) |
158
|
|
|
{ |
159
|
|
|
$options = $table->getOptions(); |
160
|
|
|
|
161
|
|
|
// Add the default primary key |
162
|
|
|
$columns = $table->getPendingColumns(); |
163
|
|
|
|
164
|
|
|
if (!isset($options['id']) || (isset($options['id']) && $options['id'] === true)) { |
165
|
|
|
$column = new Column(); |
166
|
|
|
$column->setName('id') |
167
|
|
|
->setType('integer') |
168
|
|
|
->setIdentity(true); |
169
|
|
|
|
170
|
|
|
array_unshift($columns, $column); |
171
|
|
|
$options['primary_key'] = 'id'; |
172
|
|
|
} elseif (isset($options['id']) && is_string($options['id'])) { |
173
|
|
|
// Handle id => "field_name" to support AUTO_INCREMENT |
174
|
|
|
$column = new Column(); |
175
|
|
|
$column->setName($options['id']) |
176
|
|
|
->setType('integer') |
177
|
|
|
->setIdentity(true); |
178
|
|
|
|
179
|
|
|
array_unshift($columns, $column); |
180
|
|
|
$options['primary_key'] = $options['id']; |
181
|
|
|
} |
182
|
|
|
|
183
|
|
|
$sql = 'CREATE TABLE '; |
184
|
|
|
$sql .= $this->quoteTableName($table->getName()) . ' ('; |
185
|
|
|
$sqlBuffer = []; |
186
|
|
|
$columnsWithComments = []; |
187
|
|
|
|
188
|
|
View Code Duplication |
foreach ($columns as $column) { |
|
|
|
|
189
|
|
|
$sqlBuffer[] = $this->quoteColumnName($column->getName()) . ' ' . $this->getColumnSqlDefinition($column); |
190
|
|
|
|
191
|
|
|
// set column comments, if needed |
192
|
|
|
if ($column->getComment()) { |
193
|
|
|
$columnsWithComments[] = $column; |
194
|
|
|
} |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
// set the primary key(s) |
198
|
|
View Code Duplication |
if (isset($options['primary_key'])) { |
|
|
|
|
199
|
|
|
$pkSql = sprintf('CONSTRAINT PK_%s PRIMARY KEY (', substr($table->getName(), 0, 28)); |
200
|
|
|
if (is_string($options['primary_key'])) { // handle primary_key => 'id' |
201
|
|
|
$pkSql .= $this->quoteColumnName($options['primary_key']); |
202
|
|
|
} elseif (is_array($options['primary_key'])) { // handle primary_key => array('tag_id', 'resource_id') |
|
|
|
|
203
|
|
|
$pkSql .= implode(',', array_map([$this, 'quoteColumnName'], $options['primary_key'])); |
204
|
|
|
} |
205
|
|
|
$pkSql .= ')'; |
206
|
|
|
$sqlBuffer[] = $pkSql; |
207
|
|
|
} |
208
|
|
|
|
209
|
|
|
// set the foreign keys |
210
|
|
|
$foreignKeys = $table->getForeignKeys(); |
211
|
|
|
foreach ($foreignKeys as $key => $foreignKey) { |
212
|
|
|
$sqlBuffer[] = $this->getForeignKeySqlDefinition($foreignKey, $table->getName(), $key); |
|
|
|
|
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
$sql .= implode(', ', $sqlBuffer); |
216
|
|
|
$sql .= ')'; |
217
|
|
|
|
218
|
|
|
$this->execute($sql); |
219
|
|
|
// process column comments |
220
|
|
|
foreach ($columnsWithComments as $key => $column) { |
221
|
|
|
$sql = $this->getColumnCommentSqlDefinition($column, $table->getName()); |
222
|
|
|
$this->execute($sql); |
223
|
|
|
} |
224
|
|
|
// set the indexes |
225
|
|
|
$indexes = $table->getIndexes(); |
226
|
|
|
|
227
|
|
|
if (!empty($indexes)) { |
228
|
|
|
foreach ($indexes as $index) { |
229
|
|
|
$sql = $this->getIndexSqlDefinition($index, $table->getName()); |
230
|
|
|
$this->execute($sql); |
231
|
|
|
} |
232
|
|
|
} |
233
|
|
|
|
234
|
|
|
if (!$this->hasSequence($table->getName())) { |
235
|
|
|
$sql = "CREATE SEQUENCE SQ_" . $table->getName() . " MINVALUE 1 MAXVALUE 99999999999999999 INCREMENT BY 1"; |
236
|
|
|
$this->execute($sql); |
237
|
|
|
} |
238
|
|
|
} |
239
|
|
|
|
240
|
|
|
/** |
241
|
|
|
* Verify if the table has a Sequence for primary Key |
242
|
|
|
* |
243
|
|
|
* @param string $tableName Table name |
244
|
|
|
* |
245
|
|
|
* @return bool |
246
|
|
|
*/ |
247
|
|
|
public function hasSequence($tableName) |
248
|
|
|
{ |
249
|
|
|
$sql = sprintf( |
250
|
|
|
"SELECT COUNT(*) as COUNT FROM user_sequences WHERE sequence_name = '%s'", |
251
|
|
|
strtoupper("SQ_" . $tableName) |
252
|
|
|
); |
253
|
|
|
$result = $this->fetchRow($sql); |
254
|
|
|
|
255
|
|
|
return $result['COUNT'] > 0; |
256
|
|
|
} |
257
|
|
|
|
258
|
|
|
/** |
259
|
|
|
* Gets the Oracle Column Comment Defininition for a column object. |
260
|
|
|
* |
261
|
|
|
* @param \Phinx\Db\Table\Column $column Column |
262
|
|
|
* @param string $tableName Table name |
263
|
|
|
* |
264
|
|
|
* @return string |
265
|
|
|
*/ |
266
|
|
|
protected function getColumnCommentSqlDefinition(Column $column, $tableName) |
267
|
|
|
{ |
268
|
|
|
$comment = (strcasecmp($column->getComment(), 'NULL') !== 0) ? $column->getComment() : ''; |
269
|
|
|
|
270
|
|
|
return sprintf( |
271
|
|
|
"COMMENT ON COLUMN \"%s\".\"%s\" IS '%s'", |
272
|
|
|
$tableName, |
273
|
|
|
$column->getName(), |
274
|
|
|
str_replace("'", "", $comment) |
275
|
|
|
); |
276
|
|
|
} |
277
|
|
|
|
278
|
|
|
/** |
279
|
|
|
* {@inheritdoc} |
280
|
|
|
*/ |
281
|
|
|
public function renameTable($tableName, $newTableName) |
282
|
|
|
{ |
283
|
|
|
$this->execute(sprintf('alter table "%s" rename to "%s"', $tableName, $newTableName)); |
284
|
|
|
|
285
|
|
|
if (!$this->hasSequence("SQ_" . strtoupper($newTableName))) { |
286
|
|
|
$this->renameSequence("SQ_" . strtoupper($tableName), "SQ_" . strtoupper($newTableName)); |
287
|
|
|
} |
288
|
|
|
} |
289
|
|
|
|
290
|
|
|
/** |
291
|
|
|
* Rename an Oracle Sequence Object. |
292
|
|
|
* |
293
|
|
|
* @param string $sequenceName Old Sequence Name |
294
|
|
|
* @param string $newSequenceName New Sequence Name |
295
|
|
|
* |
296
|
|
|
* @return void |
297
|
|
|
*/ |
298
|
|
|
public function renameSequence($sequenceName, $newSequenceName) |
299
|
|
|
{ |
300
|
|
|
$this->execute(sprintf('rename "%s" to "%s"', $sequenceName, $newSequenceName)); |
301
|
|
|
} |
302
|
|
|
|
303
|
|
|
/** |
304
|
|
|
* {@inheritdoc} |
305
|
|
|
*/ |
306
|
|
|
public function dropTable($tableName) |
307
|
|
|
{ |
308
|
|
|
$this->execute(sprintf('DROP TABLE %s', $this->quoteTableName($tableName))); |
309
|
|
|
$this->execute(sprintf('DROP SEQUENCE %s', $this->quoteTableName(strtoupper("SQ_" . $tableName)))); |
310
|
|
|
} |
311
|
|
|
|
312
|
|
|
/** |
313
|
|
|
* {@inheritdoc} |
314
|
|
|
*/ |
315
|
|
|
public function truncateTable($tableName) |
316
|
|
|
{ |
317
|
|
|
$sql = sprintf( |
318
|
|
|
'TRUNCATE TABLE %s', |
319
|
|
|
$this->quoteTableName($tableName) |
320
|
|
|
); |
321
|
|
|
|
322
|
|
|
$this->execute($sql); |
323
|
|
|
} |
324
|
|
|
|
325
|
|
|
/** |
326
|
|
|
* Get the comment for a column |
327
|
|
|
* |
328
|
|
|
* @param string $tableName Table Name |
329
|
|
|
* @param string $columnName Column Name |
330
|
|
|
* |
331
|
|
|
* @return string |
332
|
|
|
*/ |
333
|
|
View Code Duplication |
public function getColumnComment($tableName, $columnName) |
|
|
|
|
334
|
|
|
{ |
335
|
|
|
$sql = sprintf( |
336
|
|
|
"select COMMENTS from ALL_COL_COMMENTS WHERE COLUMN_NAME = '%s' and TABLE_NAME = '%s'", |
337
|
|
|
$columnName, |
338
|
|
|
$tableName |
339
|
|
|
); |
340
|
|
|
$row = $this->fetchRow($sql); |
341
|
|
|
|
342
|
|
|
if ($row['COMMENTS'] != 'NULL') { |
343
|
|
|
return $row['COMMENTS']; |
344
|
|
|
} |
345
|
|
|
|
346
|
|
|
return false; |
|
|
|
|
347
|
|
|
} |
348
|
|
|
|
349
|
|
|
/** |
350
|
|
|
* {@inheritdoc} |
351
|
|
|
*/ |
352
|
|
|
public function getColumns($tableName) |
353
|
|
|
{ |
354
|
|
|
$columns = []; |
355
|
|
|
|
356
|
|
|
$sql = sprintf( |
357
|
|
|
"select TABLE_NAME \"TABLE_NAME\", COLUMN_NAME \"NAME\", DATA_TYPE \"TYPE\", NULLABLE \"NULL\", |
358
|
|
|
DATA_DEFAULT \"DEFAULT\", DATA_LENGTH \"CHAR_LENGTH\", DATA_PRECISION \"PRECISION\", DATA_SCALE \"SCALE\", |
359
|
|
|
COLUMN_ID \"ORDINAL_POSITION\" FROM ALL_TAB_COLUMNS WHERE table_name = '%s'", |
360
|
|
|
$tableName |
361
|
|
|
); |
362
|
|
|
|
363
|
|
|
$rows = $this->fetchAll($sql); |
364
|
|
|
|
365
|
|
|
foreach ($rows as $columnInfo) { |
366
|
|
|
$default = null; |
367
|
|
|
if (trim($columnInfo['DEFAULT']) != 'NULL') { |
368
|
|
|
$default = trim($columnInfo['DEFAULT']); |
369
|
|
|
} |
370
|
|
|
|
371
|
|
|
$column = new Column(); |
372
|
|
|
$column->setName($columnInfo['NAME']) |
373
|
|
|
->setType($this->getPhinxType($columnInfo['TYPE'], $columnInfo['PRECISION'])) |
374
|
|
|
->setNull($columnInfo['NULL'] !== 'N') |
375
|
|
|
->setDefault($default) |
376
|
|
|
->setComment($this->getColumnComment($columnInfo['TABLE_NAME'], $columnInfo['NAME'])); |
377
|
|
|
|
378
|
|
|
if (!empty($columnInfo['CHAR_LENGTH'])) { |
379
|
|
|
$column->setLimit($columnInfo['CHAR_LENGTH']); |
380
|
|
|
} |
381
|
|
|
|
382
|
|
|
$columns[$columnInfo['NAME']] = $column; |
383
|
|
|
} |
384
|
|
|
|
385
|
|
|
return $columns; |
386
|
|
|
} |
387
|
|
|
|
388
|
|
|
/** |
389
|
|
|
* {@inheritdoc} |
390
|
|
|
*/ |
391
|
|
View Code Duplication |
public function hasColumn($tableName, $columnName) |
|
|
|
|
392
|
|
|
{ |
393
|
|
|
$sql = sprintf( |
394
|
|
|
"select count(*) as count from ALL_TAB_COLUMNS |
395
|
|
|
where table_name = '%s' and column_name = '%s'", |
396
|
|
|
$tableName, |
397
|
|
|
$columnName |
398
|
|
|
); |
399
|
|
|
|
400
|
|
|
$result = $this->fetchRow($sql); |
401
|
|
|
|
402
|
|
|
return $result['COUNT'] > 0; |
403
|
|
|
} |
404
|
|
|
|
405
|
|
|
/** |
406
|
|
|
* {@inheritdoc} |
407
|
|
|
*/ |
408
|
|
View Code Duplication |
public function addColumn(Table $table, Column $column) |
|
|
|
|
409
|
|
|
{ |
410
|
|
|
$sql = sprintf( |
411
|
|
|
'ALTER TABLE %s ADD %s %s', |
412
|
|
|
$this->quoteTableName($table->getName()), |
413
|
|
|
$this->quoteColumnName($column->getName()), |
414
|
|
|
$this->getColumnSqlDefinition($column) |
415
|
|
|
); |
416
|
|
|
|
417
|
|
|
$this->execute($sql); |
418
|
|
|
} |
419
|
|
|
|
420
|
|
|
/** |
421
|
|
|
* {@inheritdoc} |
422
|
|
|
*/ |
423
|
|
|
public function renameColumn($tableName, $columnName, $newColumnName) |
424
|
|
|
{ |
425
|
|
|
if (!$this->hasColumn($tableName, $columnName)) { |
426
|
|
|
throw new \InvalidArgumentException("The specified column does not exist: $columnName"); |
427
|
|
|
} |
428
|
|
|
|
429
|
|
|
$this->execute( |
430
|
|
|
sprintf( |
431
|
|
|
"alter table \"%s\" rename column \"%s\" TO \"%s\"", |
432
|
|
|
$tableName, |
433
|
|
|
$columnName, |
434
|
|
|
$newColumnName |
435
|
|
|
) |
436
|
|
|
); |
437
|
|
|
} |
438
|
|
|
|
439
|
|
|
/** |
440
|
|
|
* {@inheritdoc} |
441
|
|
|
*/ |
442
|
|
|
public function changeColumn($tableName, $columnName, Column $newColumn) |
443
|
|
|
{ |
444
|
|
|
$columns = $this->getColumns($tableName); |
445
|
|
|
|
446
|
|
|
if ($columnName !== $newColumn->getName()) { |
447
|
|
|
$this->renameColumn($tableName, $columnName, $newColumn->getName()); |
448
|
|
|
} |
449
|
|
|
|
450
|
|
|
$setNullSql = ($newColumn->isNull() == $columns[$columnName]->isNull() ? false : true); |
451
|
|
|
|
452
|
|
|
$this->execute( |
453
|
|
|
sprintf( |
454
|
|
|
'ALTER TABLE %s MODIFY(%s %s)', |
455
|
|
|
$this->quoteTableName($tableName), |
456
|
|
|
$this->quoteColumnName($newColumn->getName()), |
457
|
|
|
$this->getColumnSqlDefinition($newColumn, $setNullSql) |
458
|
|
|
) |
459
|
|
|
); |
460
|
|
|
// change column comment if needed |
461
|
|
|
if ($newColumn->getComment()) { |
462
|
|
|
$sql = $this->getColumnCommentSqlDefinition($newColumn, $tableName); |
463
|
|
|
$this->execute($sql); |
464
|
|
|
} |
465
|
|
|
} |
466
|
|
|
|
467
|
|
|
/** |
468
|
|
|
* {@inheritdoc} |
469
|
|
|
*/ |
470
|
|
|
public function dropColumn($tableName, $columnName) |
471
|
|
|
{ |
472
|
|
|
$this->execute( |
473
|
|
|
sprintf( |
474
|
|
|
'ALTER TABLE %s DROP COLUMN %s', |
475
|
|
|
$this->quoteTableName($tableName), |
476
|
|
|
$this->quoteColumnName($columnName) |
477
|
|
|
) |
478
|
|
|
); |
479
|
|
|
} |
480
|
|
|
|
481
|
|
|
/** |
482
|
|
|
* Get an array of indexes from a particular table. |
483
|
|
|
* |
484
|
|
|
* @param string $tableName Table Name |
485
|
|
|
* @return array |
486
|
|
|
*/ |
487
|
|
View Code Duplication |
public function getIndexes($tableName) |
|
|
|
|
488
|
|
|
{ |
489
|
|
|
$indexes = []; |
490
|
|
|
$sql = "SELECT index_owner as owner,index_name,column_name FROM ALL_IND_COLUMNS |
491
|
|
|
WHERE TABLE_NAME = '$tableName'"; |
492
|
|
|
|
493
|
|
|
$rows = $this->fetchAll($sql); |
494
|
|
|
foreach ($rows as $row) { |
495
|
|
|
if (!isset($indexes[$row['INDEX_NAME']])) { |
496
|
|
|
$indexes[$row['INDEX_NAME']] = ['columns' => []]; |
497
|
|
|
} |
498
|
|
|
$indexes[$row['INDEX_NAME']]['columns'][] = strtoupper($row['COLUMN_NAME']); |
499
|
|
|
} |
500
|
|
|
|
501
|
|
|
return $indexes; |
502
|
|
|
} |
503
|
|
|
|
504
|
|
|
/** |
505
|
|
|
* {@inheritdoc} |
506
|
|
|
*/ |
507
|
|
View Code Duplication |
public function hasIndex($tableName, $columns) |
|
|
|
|
508
|
|
|
{ |
509
|
|
|
if (is_string($columns)) { |
510
|
|
|
$columns = [$columns]; // str to array |
511
|
|
|
} |
512
|
|
|
|
513
|
|
|
$indexes = $this->getIndexes($tableName); |
514
|
|
|
foreach ($indexes as $index) { |
515
|
|
|
$a = array_diff($columns, $index['columns']); |
516
|
|
|
|
517
|
|
|
if (empty($a)) { |
518
|
|
|
return true; |
519
|
|
|
} |
520
|
|
|
} |
521
|
|
|
|
522
|
|
|
return false; |
523
|
|
|
} |
524
|
|
|
|
525
|
|
|
/** |
526
|
|
|
* {@inheritdoc} |
527
|
|
|
*/ |
528
|
|
View Code Duplication |
public function hasIndexByName($tableName, $indexName) |
|
|
|
|
529
|
|
|
{ |
530
|
|
|
$indexes = $this->getIndexes($tableName); |
531
|
|
|
|
532
|
|
|
foreach ($indexes as $name => $index) { |
533
|
|
|
if ($name === $indexName) { |
534
|
|
|
return true; |
535
|
|
|
} |
536
|
|
|
} |
537
|
|
|
|
538
|
|
|
return false; |
539
|
|
|
} |
540
|
|
|
|
541
|
|
|
/** |
542
|
|
|
* {@inheritdoc} |
543
|
|
|
*/ |
544
|
|
|
public function addIndex(Table $table, Index $index) |
545
|
|
|
{ |
546
|
|
|
$sql = $this->getIndexSqlDefinition($index, $table->getName()); |
547
|
|
|
$this->execute($sql); |
548
|
|
|
} |
549
|
|
|
|
550
|
|
|
/** |
551
|
|
|
* {@inheritdoc} |
552
|
|
|
*/ |
553
|
|
View Code Duplication |
public function dropIndex($tableName, $columns) |
|
|
|
|
554
|
|
|
{ |
555
|
|
|
if (is_string($columns)) { |
556
|
|
|
$columns = [$columns]; // str to array |
557
|
|
|
} |
558
|
|
|
|
559
|
|
|
$indexes = $this->getIndexes($tableName); |
560
|
|
|
$columns = array_map('strtoupper', $columns); |
561
|
|
|
|
562
|
|
|
foreach ($indexes as $indexName => $index) { |
563
|
|
|
$a = array_diff($columns, $index['columns']); |
564
|
|
|
if (empty($a)) { |
565
|
|
|
$this->execute( |
566
|
|
|
sprintf( |
567
|
|
|
'DROP INDEX %s', |
568
|
|
|
$this->quoteColumnName($indexName) |
569
|
|
|
) |
570
|
|
|
); |
571
|
|
|
|
572
|
|
|
return; |
573
|
|
|
} |
574
|
|
|
} |
575
|
|
|
} |
576
|
|
|
|
577
|
|
|
/** |
578
|
|
|
* {@inheritdoc} |
579
|
|
|
*/ |
580
|
|
View Code Duplication |
public function dropIndexByName($tableName, $indexName) |
|
|
|
|
581
|
|
|
{ |
582
|
|
|
$indexes = $this->getIndexes($tableName); |
583
|
|
|
|
584
|
|
|
foreach ($indexes as $name => $index) { |
585
|
|
|
if ($name === $indexName) { |
586
|
|
|
$this->execute( |
587
|
|
|
sprintf( |
588
|
|
|
'DROP INDEX %s', |
589
|
|
|
$this->quoteColumnName($indexName), |
590
|
|
|
$this->quoteTableName($tableName) |
591
|
|
|
) |
592
|
|
|
); |
593
|
|
|
|
594
|
|
|
return; |
595
|
|
|
} |
596
|
|
|
} |
597
|
|
|
} |
598
|
|
|
|
599
|
|
|
/** |
600
|
|
|
* {@inheritdoc} |
601
|
|
|
*/ |
602
|
|
View Code Duplication |
public function hasForeignKey($tableName, $columns, $constraint = null) |
|
|
|
|
603
|
|
|
{ |
604
|
|
|
if (is_string($columns)) { |
605
|
|
|
$columns = [$columns]; // str to array |
606
|
|
|
} |
607
|
|
|
$foreignKeys = $this->getForeignKeys($tableName); |
608
|
|
|
|
609
|
|
|
if ($constraint) { |
|
|
|
|
610
|
|
|
if (isset($foreignKeys[$constraint])) { |
611
|
|
|
return !empty($foreignKeys[$constraint]); |
612
|
|
|
} |
613
|
|
|
|
614
|
|
|
return false; |
615
|
|
|
} else { |
616
|
|
|
foreach ($foreignKeys as $key) { |
617
|
|
|
$a = array_diff($columns, $key['COLUMNS']); |
618
|
|
|
if (empty($a)) { |
619
|
|
|
return true; |
620
|
|
|
} |
621
|
|
|
} |
622
|
|
|
|
623
|
|
|
return false; |
624
|
|
|
} |
625
|
|
|
} |
626
|
|
|
|
627
|
|
|
/** |
628
|
|
|
* Get an array of foreign keys from a particular table. |
629
|
|
|
* |
630
|
|
|
* @param string $tableName Table Name |
631
|
|
|
* @param string $type Type of Constraint Type (R, P) |
632
|
|
|
* @return array |
633
|
|
|
*/ |
634
|
|
View Code Duplication |
protected function getForeignKeys($tableName, $type = 'R') |
|
|
|
|
635
|
|
|
{ |
636
|
|
|
$foreignKeys = []; |
637
|
|
|
$rows = $this->fetchAll(sprintf( |
638
|
|
|
"SELECT a.CONSTRAINT_NAME, a.TABLE_NAME, b.COLUMN_NAME, |
639
|
|
|
(SELECT c.TABLE_NAME from ALL_CONS_COLUMNS c |
640
|
|
|
WHERE c.CONSTRAINT_NAME = a.R_CONSTRAINT_NAME) referenced_table_name, |
641
|
|
|
(SELECT c.COLUMN_NAME from ALL_CONS_COLUMNS c |
642
|
|
|
WHERE c.CONSTRAINT_NAME = a.R_CONSTRAINT_NAME) referenced_column_name |
643
|
|
|
FROM all_constraints a JOIN ALL_CONS_COLUMNS b ON a.CONSTRAINT_NAME = b.CONSTRAINT_NAME |
644
|
|
|
WHERE a.table_name = '%s' |
645
|
|
|
AND CONSTRAINT_TYPE = '%s'", |
646
|
|
|
$tableName, |
647
|
|
|
$type |
648
|
|
|
)); |
649
|
|
|
|
650
|
|
|
foreach ($rows as $row) { |
651
|
|
|
$foreignKeys[$row['CONSTRAINT_NAME']]['TABLE'] = $row['TABLE_NAME']; |
652
|
|
|
$foreignKeys[$row['CONSTRAINT_NAME']]['COLUMNS'][] = $row['COLUMN_NAME']; |
653
|
|
|
$foreignKeys[$row['CONSTRAINT_NAME']]['REFERENCED_TABLE'] = $row['REFERENCED_TABLE_NAME']; |
654
|
|
|
$foreignKeys[$row['CONSTRAINT_NAME']]['REFERENCED_COLUMNS'][] = $row['REFERENCED_COLUMN_NAME']; |
655
|
|
|
} |
656
|
|
|
|
657
|
|
|
return $foreignKeys; |
658
|
|
|
} |
659
|
|
|
|
660
|
|
|
/** |
661
|
|
|
* {@inheritdoc} |
662
|
|
|
*/ |
663
|
|
|
public function addForeignKey(Table $table, ForeignKey $foreignKey) |
664
|
|
|
{ |
665
|
|
|
$this->execute( |
666
|
|
|
sprintf( |
667
|
|
|
'ALTER TABLE %s ADD %s', |
668
|
|
|
$this->quoteTableName($table->getName()), |
669
|
|
|
$this->getForeignKeySqlDefinition($foreignKey, $table->getName()) |
670
|
|
|
) |
671
|
|
|
); |
672
|
|
|
} |
673
|
|
|
|
674
|
|
|
/** |
675
|
|
|
* {@inheritdoc} |
676
|
|
|
*/ |
677
|
|
View Code Duplication |
public function dropForeignKey($tableName, $columns, $constraint = null) |
|
|
|
|
678
|
|
|
{ |
679
|
|
|
if (is_string($columns)) { |
680
|
|
|
$columns = [$columns]; // str to array |
681
|
|
|
} |
682
|
|
|
|
683
|
|
|
if ($constraint) { |
|
|
|
|
684
|
|
|
$this->execute( |
685
|
|
|
sprintf( |
686
|
|
|
'ALTER TABLE %s DROP CONSTRAINT %s', |
687
|
|
|
$this->quoteTableName($tableName), |
688
|
|
|
$constraint |
689
|
|
|
) |
690
|
|
|
); |
691
|
|
|
|
692
|
|
|
return; |
693
|
|
|
} else { |
694
|
|
|
foreach ($columns as $column) { |
695
|
|
|
$rows = $this->fetchAll(sprintf( |
696
|
|
|
"SELECT a.CONSTRAINT_NAME, a.TABLE_NAME, b.COLUMN_NAME, |
697
|
|
|
(SELECT c.TABLE_NAME from ALL_CONS_COLUMNS c |
698
|
|
|
WHERE c.CONSTRAINT_NAME = a.R_CONSTRAINT_NAME) referenced_table_name, |
699
|
|
|
(SELECT c.COLUMN_NAME from ALL_CONS_COLUMNS c |
700
|
|
|
WHERE c.CONSTRAINT_NAME = a.R_CONSTRAINT_NAME) referenced_column_name |
701
|
|
|
FROM all_constraints a JOIN ALL_CONS_COLUMNS b ON a.CONSTRAINT_NAME = b.CONSTRAINT_NAME |
702
|
|
|
WHERE a.table_name = '%s' |
703
|
|
|
AND CONSTRAINT_TYPE = 'R' |
704
|
|
|
AND COLUMN_NAME = '%s'", |
705
|
|
|
$tableName, |
706
|
|
|
$column |
707
|
|
|
)); |
708
|
|
|
foreach ($rows as $row) { |
709
|
|
|
$this->dropForeignKey($tableName, $columns, $row['CONSTRAINT_NAME']); |
710
|
|
|
} |
711
|
|
|
} |
712
|
|
|
} |
713
|
|
|
} |
714
|
|
|
|
715
|
|
|
/** |
716
|
|
|
* {@inheritdoc} |
717
|
|
|
*/ |
718
|
|
|
public function getSqlType($type, $limit = null) |
719
|
|
|
{ |
720
|
|
|
// reference: https://docs.oracle.com/cd/B19306_01/gateways.102/b14270/apa.htm |
721
|
|
|
switch ($type) { |
722
|
|
|
case static::PHINX_TYPE_STRING: |
723
|
|
|
return ['name' => 'VARCHAR2', 'limit' => 255]; |
724
|
|
|
case static::PHINX_TYPE_CHAR: |
725
|
|
|
return ['name' => 'CHAR', 'limit' => 255]; |
726
|
|
|
case static::PHINX_TYPE_TEXT: |
727
|
|
|
return ['name' => 'LONG']; |
728
|
|
|
case static::PHINX_TYPE_INTEGER: |
729
|
|
|
return ['name' => 'NUMBER', 'precision' => 10]; |
730
|
|
|
case static::PHINX_TYPE_BIG_INTEGER: |
731
|
|
|
return ['name' => 'NUMBER', 'precision' => 19]; |
732
|
|
|
case static::PHINX_TYPE_FLOAT: |
733
|
|
|
return ['name' => 'FLOAT', 'precision' => 49]; |
734
|
|
|
case static::PHINX_TYPE_DECIMAL: |
735
|
|
|
return ['name' => 'NUMBER']; |
736
|
|
|
case static::PHINX_TYPE_DATETIME: |
737
|
|
|
return ['name' => 'DATE']; |
738
|
|
|
case static::PHINX_TYPE_TIMESTAMP: |
739
|
|
|
return ['name' => 'TIMESTAMP']; |
740
|
|
|
case static::PHINX_TYPE_TIME: |
741
|
|
|
return ['name' => 'time']; |
742
|
|
|
case static::PHINX_TYPE_DATE: |
743
|
|
|
return ['name' => 'DATE']; |
744
|
|
|
case static::PHINX_TYPE_BLOB: |
745
|
|
|
return ['name' => 'BLOB']; |
746
|
|
|
case 'CLOB': |
747
|
|
|
return ['name' => 'CLOB']; |
748
|
|
|
case static::PHINX_TYPE_BINARY: |
749
|
|
|
return ['name' => 'RAW', 'limit' => 2000]; |
750
|
|
|
case static::PHINX_TYPE_BOOLEAN: |
751
|
|
|
return ['name' => 'NUMBER', 'precision' => 1]; |
752
|
|
|
case static::PHINX_TYPE_UUID: |
753
|
|
|
return ['name' => 'RAW', 'precision' => 16, 'default' => 'SYS_GUID()', 'limit' => 2000]; |
754
|
|
|
case static::PHINX_TYPE_FILESTREAM: |
755
|
|
|
return ['name' => 'varbinary', 'limit' => 'max']; |
756
|
|
|
// Geospatial database types |
757
|
|
|
case static::PHINX_TYPE_GEOMETRY: |
758
|
|
|
case static::PHINX_TYPE_POINT: |
759
|
|
|
case static::PHINX_TYPE_LINESTRING: |
760
|
|
|
case static::PHINX_TYPE_POLYGON: |
761
|
|
|
// SQL Server stores all spatial data using a single data type. |
762
|
|
|
// Specific types (point, polygon, etc) are set at insert time. |
763
|
|
|
return ['name' => 'geography']; |
764
|
|
|
default: |
765
|
|
|
throw new \RuntimeException('The type: "' . $type . '" is not supported.'); |
766
|
|
|
} |
767
|
|
|
} |
768
|
|
|
|
769
|
|
|
/** |
770
|
|
|
* Returns Phinx type by SQL type |
771
|
|
|
* |
772
|
|
|
* @param string $sqlType SQL Type definition |
773
|
|
|
* @param int $precision Precision of NUMBER type to define Phinx Type. |
774
|
|
|
* @throws \RuntimeException |
775
|
|
|
* @internal param string $sqlType SQL type |
776
|
|
|
* @return string Phinx type |
777
|
|
|
*/ |
778
|
|
|
public function getPhinxType($sqlType, $precision = null) |
779
|
|
|
{ |
780
|
|
|
if ($sqlType === 'VARCHAR2') { |
781
|
|
|
return static::PHINX_TYPE_STRING; |
782
|
|
|
} elseif ($sqlType === 'CHAR') { |
783
|
|
|
return static::PHINX_TYPE_CHAR; |
784
|
|
|
} elseif ($sqlType == 'LONG') { |
785
|
|
|
return static::PHINX_TYPE_TEXT; |
786
|
|
|
} elseif ($sqlType === 'NUMBER' && $precision === 10) { |
787
|
|
|
return static::PHINX_TYPE_INTEGER; |
788
|
|
|
} elseif ($sqlType === 'NUMBER' && $precision === 19) { |
789
|
|
|
return static::PHINX_TYPE_BIG_INTEGER; |
790
|
|
|
} elseif ($sqlType === 'FLOAT') { |
791
|
|
|
return static::PHINX_TYPE_FLOAT; |
792
|
|
|
} elseif ($sqlType === 'TIMESTAMP(6)') { |
793
|
|
|
return static::PHINX_TYPE_TIMESTAMP; |
794
|
|
|
} elseif ($sqlType === 'TIME') { |
795
|
|
|
return static::PHINX_TYPE_TIME; |
796
|
|
|
} elseif ($sqlType === 'DATE') { |
797
|
|
|
return static::PHINX_TYPE_DATE; |
798
|
|
|
} elseif ($sqlType === 'BLOB') { |
799
|
|
|
return static::PHINX_TYPE_BLOB; |
800
|
|
|
} elseif ($sqlType === 'CLOB') { |
801
|
|
|
return 'CLOB'; |
802
|
|
|
} elseif ($sqlType === 'RAW' && $precision === 16) { |
803
|
|
|
return static::PHINX_TYPE_UUID; |
804
|
|
|
} elseif ($sqlType === 'RAW') { |
805
|
|
|
return static::PHINX_TYPE_BLOB; |
806
|
|
|
} elseif ($sqlType === 'NUMBER' && $precision === 1) { |
807
|
|
|
return static::PHINX_TYPE_BOOLEAN; |
808
|
|
|
} elseif ($sqlType === 'NUMBER') { |
809
|
|
|
return static::PHINX_TYPE_DECIMAL; |
810
|
|
|
} else { |
811
|
|
|
throw new \RuntimeException('The Oracle type: "' . $sqlType . '" is not supported'); |
812
|
|
|
} |
813
|
|
|
} |
814
|
|
|
|
815
|
|
|
/** |
816
|
|
|
* {@inheritdoc} |
817
|
|
|
*/ |
818
|
|
View Code Duplication |
public function createDatabase($name, $options = []) |
|
|
|
|
819
|
|
|
{ |
820
|
|
|
if (isset($options['collation'])) { |
821
|
|
|
$this->execute(sprintf('CREATE DATABASE [%s] COLLATE [%s]', $name, $options['collation'])); |
822
|
|
|
} else { |
823
|
|
|
$this->execute(sprintf('CREATE DATABASE [%s]', $name)); |
824
|
|
|
} |
825
|
|
|
$this->execute(sprintf('USE [%s]', $name)); |
826
|
|
|
} |
827
|
|
|
|
828
|
|
|
/** |
829
|
|
|
* {@inheritdoc} |
830
|
|
|
*/ |
831
|
|
|
public function hasDatabase($name) |
832
|
|
|
{ |
833
|
|
|
$result = $this->fetchRow( |
834
|
|
|
sprintf( |
835
|
|
|
'SELECT count(*) as [count] FROM master.dbo.sysdatabases WHERE [name] = \'%s\'', |
836
|
|
|
$name |
837
|
|
|
) |
838
|
|
|
); |
839
|
|
|
|
840
|
|
|
return $result['count'] > 0; |
841
|
|
|
} |
842
|
|
|
|
843
|
|
|
/** |
844
|
|
|
* {@inheritdoc} |
845
|
|
|
*/ |
846
|
|
|
public function dropDatabase($name) |
847
|
|
|
{ |
848
|
|
|
$sql = <<<SQL |
849
|
|
|
USE master; |
850
|
|
|
IF EXISTS(select * from sys.databases where name=N'$name') |
851
|
|
|
ALTER DATABASE [$name] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; |
852
|
|
|
DROP DATABASE [$name]; |
853
|
|
|
SQL; |
854
|
|
|
$this->execute($sql); |
855
|
|
|
} |
856
|
|
|
|
857
|
|
|
/** |
858
|
|
|
* Get the defintion for a `DEFAULT` statement. |
859
|
|
|
* |
860
|
|
|
* @param mixed $default Default value for column |
861
|
|
|
* @return string |
862
|
|
|
*/ |
863
|
|
|
protected function getDefaultValueDefinition($default) |
864
|
|
|
{ |
865
|
|
|
if (is_string($default) && 'CURRENT_TIMESTAMP' !== $default && 'SYSDATE' !== $default) { |
866
|
|
|
$default = $this->getConnection()->quote($default); |
867
|
|
|
} elseif (is_bool($default)) { |
868
|
|
|
$default = $this->castToBool($default); |
869
|
|
|
} |
870
|
|
|
|
871
|
|
|
return isset($default) ? ' DEFAULT ' . $default : 'DEFAULT NULL'; |
872
|
|
|
} |
873
|
|
|
|
874
|
|
|
/** |
875
|
|
|
* Gets the Oracle Column Definition for a Column object. |
876
|
|
|
* |
877
|
|
|
* @param \Phinx\Db\Table\Column $column Column |
878
|
|
|
* @param bool $setNullSql Set column nullable |
879
|
|
|
* @return string |
880
|
|
|
*/ |
881
|
|
|
protected function getColumnSqlDefinition(Column $column, $setNullSql = true) |
882
|
|
|
{ |
883
|
|
|
$buffer = []; |
884
|
|
|
|
885
|
|
|
$sqlType = $this->getSqlType($column->getType()); |
886
|
|
|
|
887
|
|
|
$buffer[] = strtoupper($sqlType['name']); |
888
|
|
|
// integers cant have limits in Oracle |
889
|
|
|
$noLimits = [ |
890
|
|
|
static::PHINX_TYPE_INTEGER, |
891
|
|
|
static::PHINX_TYPE_BIG_INTEGER, |
892
|
|
|
static::PHINX_TYPE_FLOAT, |
893
|
|
|
static::PHINX_TYPE_UUID, |
894
|
|
|
static::PHINX_TYPE_BOOLEAN |
895
|
|
|
]; |
896
|
|
View Code Duplication |
if (!in_array($column->getType(), $noLimits) && ($column->getLimit() || isset($sqlType['limit']))) { |
|
|
|
|
897
|
|
|
$buffer[] = sprintf('(%s)', $column->getLimit() ?: $sqlType['limit']); |
898
|
|
|
} |
899
|
|
View Code Duplication |
if ($column->getPrecision() && $column->getScale()) { |
|
|
|
|
900
|
|
|
$buffer[] = '(' . $column->getPrecision() . ',' . $column->getScale() . ')'; |
901
|
|
|
} |
902
|
|
|
|
903
|
|
View Code Duplication |
if ($column->getDefault() === null && $column->isNull()) { |
|
|
|
|
904
|
|
|
$buffer[] = ' DEFAULT NULL'; |
905
|
|
|
} else { |
906
|
|
|
$buffer[] = $this->getDefaultValueDefinition($column->getDefault()); |
907
|
|
|
} |
908
|
|
|
|
909
|
|
|
if ($setNullSql) { |
910
|
|
|
$buffer[] = $column->isNull() ? 'NULL' : 'NOT NULL'; |
911
|
|
|
} |
912
|
|
|
|
913
|
|
|
return implode(' ', $buffer); |
914
|
|
|
} |
915
|
|
|
|
916
|
|
|
/** |
917
|
|
|
* Gets the Oracle Index Definition for an Index object. |
918
|
|
|
* |
919
|
|
|
* @param \Phinx\Db\Table\Index $index Index |
920
|
|
|
* @param string $tableName Table Name |
921
|
|
|
* @return string |
922
|
|
|
*/ |
923
|
|
View Code Duplication |
protected function getIndexSqlDefinition(Index $index, $tableName) |
|
|
|
|
924
|
|
|
{ |
925
|
|
|
if (is_string($index->getName())) { |
926
|
|
|
$indexName = $index->getName(); |
927
|
|
|
} else { |
928
|
|
|
$columnNames = $index->getColumns(); |
929
|
|
|
if (is_string($columnNames)) { |
930
|
|
|
$columnNames = [$columnNames]; |
931
|
|
|
} |
932
|
|
|
$indexName = sprintf('%s_%s', $tableName, implode('_', $columnNames)); |
933
|
|
|
} |
934
|
|
|
$def = sprintf( |
935
|
|
|
"CREATE %s INDEX %s ON %s (%s)", |
936
|
|
|
($index->getType() === Index::UNIQUE ? 'UNIQUE' : ''), |
937
|
|
|
$indexName, |
938
|
|
|
$this->quoteTableName($tableName), |
939
|
|
|
'"' . implode('","', $index->getColumns()) . '"' |
940
|
|
|
); |
941
|
|
|
|
942
|
|
|
return $def; |
943
|
|
|
} |
944
|
|
|
|
945
|
|
|
/** |
946
|
|
|
* Gets the Oracle Foreign Key Definition for an ForeignKey object. |
947
|
|
|
* |
948
|
|
|
* @param \Phinx\Db\Table\ForeignKey $foreignKey Foreign Key Object |
949
|
|
|
* @param string $tableName Table Name |
950
|
|
|
* @return string |
951
|
|
|
*/ |
952
|
|
|
protected function getForeignKeySqlDefinition(ForeignKey $foreignKey, $tableName) |
953
|
|
|
{ |
954
|
|
|
$constraintName = $foreignKey->getConstraint() ?: $tableName . '_' . implode('_', $foreignKey->getColumns()); |
955
|
|
|
$def = ' CONSTRAINT ' . $this->quoteColumnName(substr($constraintName, 0, 27)); |
956
|
|
|
$def .= ' FOREIGN KEY ("' . implode('", "', $foreignKey->getColumns()) . '")'; |
957
|
|
|
$def .= " REFERENCES {$this->quoteTableName($foreignKey->getReferencedTable()->getName())} |
958
|
|
|
(\"" . implode('", "', $foreignKey->getReferencedColumns()) . '")'; |
959
|
|
|
if ($foreignKey->getOnDelete() && $foreignKey->getOnDelete() != "NO ACTION") { |
960
|
|
|
$def .= " ON DELETE {$foreignKey->getOnDelete()}"; |
961
|
|
|
} |
962
|
|
|
if ($foreignKey->getOnUpdate()) { |
963
|
|
|
$def .= " ON UPDATE {$foreignKey->getOnUpdate()}"; |
964
|
|
|
} |
965
|
|
|
|
966
|
|
|
return $def; |
967
|
|
|
} |
968
|
|
|
|
969
|
|
|
/** |
970
|
|
|
* {@inheritdoc} |
971
|
|
|
*/ |
972
|
|
|
public function getColumnTypes() |
973
|
|
|
{ |
974
|
|
|
return array_merge(parent::getColumnTypes(), ['filestream']); |
975
|
|
|
} |
976
|
|
|
|
977
|
|
|
/** |
978
|
|
|
* Records a migration being run. |
979
|
|
|
* |
980
|
|
|
* @param \Phinx\Migration\MigrationInterface $migration Migration |
981
|
|
|
* @param string $direction Direction |
982
|
|
|
* @param int $startTime Start Time |
983
|
|
|
* @param int $endTime End Time |
984
|
|
|
* @return \Phinx\Db\Adapter\AdapterInterface |
985
|
|
|
*/ |
986
|
|
|
public function migrated(\Phinx\Migration\MigrationInterface $migration, $direction, $startTime, $endTime) |
987
|
|
|
{ |
988
|
|
|
$startTime = "TO_TIMESTAMP('$startTime', 'YYYY-MM-DD HH24:MI:SS')"; |
989
|
|
|
$endTime = "TO_TIMESTAMP('$endTime', 'YYYY-MM-DD HH24:MI:SS')"; |
990
|
|
|
|
991
|
|
View Code Duplication |
if (strcasecmp($direction, MigrationInterface::UP) === 0) { |
|
|
|
|
992
|
|
|
// up |
993
|
|
|
$sql = sprintf( |
994
|
|
|
"INSERT INTO \"%s\" (%s, %s, %s, %s, %s) VALUES ('%s', '%s', %s, %s, %s)", |
995
|
|
|
$this->getSchemaTableName(), |
996
|
|
|
$this->quoteColumnName('version'), |
997
|
|
|
$this->quoteColumnName('migration_name'), |
998
|
|
|
$this->quoteColumnName('start_time'), |
999
|
|
|
$this->quoteColumnName('end_time'), |
1000
|
|
|
$this->quoteColumnName('breakpoint'), |
1001
|
|
|
$migration->getVersion(), |
1002
|
|
|
substr($migration->getName(), 0, 100), |
1003
|
|
|
$startTime, |
1004
|
|
|
$endTime, |
1005
|
|
|
$this->castToBool(false) |
1006
|
|
|
); |
1007
|
|
|
|
1008
|
|
|
$this->execute($sql); |
1009
|
|
|
} else { |
1010
|
|
|
// down |
1011
|
|
|
$sql = sprintf( |
1012
|
|
|
"DELETE FROM \"%s\" WHERE %s = '%s'", |
1013
|
|
|
$this->getSchemaTableName(), |
1014
|
|
|
$this->quoteColumnName('version'), |
1015
|
|
|
$migration->getVersion() |
1016
|
|
|
); |
1017
|
|
|
|
1018
|
|
|
$this->execute($sql); |
1019
|
|
|
} |
1020
|
|
|
|
1021
|
|
|
return $this; |
1022
|
|
|
} |
1023
|
|
|
|
1024
|
|
|
/** |
1025
|
|
|
* {@inheritdoc} |
1026
|
|
|
*/ |
1027
|
|
|
public function bulkinsert(Table $table, $rows) |
1028
|
|
|
{ |
1029
|
|
|
$sql = "INSERT ALL "; |
1030
|
|
|
|
1031
|
|
|
$vals = []; |
1032
|
|
|
$tableName = $table->getName(); |
1033
|
|
|
$primaryKeyColumn = current($this->getForeignKeys($tableName, 'P')); |
1034
|
|
|
$sequenceNextVal = $this->getNextValSequence('SQ_' . $tableName); |
1035
|
|
|
// buscar sequence e primary key padr�o para incrementar PK com a SEQUENCE.NEXTVAL |
1036
|
|
|
|
1037
|
|
|
foreach ($rows as $key => $row) { |
1038
|
|
|
$pk = ($sequenceNextVal + $key); |
1039
|
|
|
$row[$primaryKeyColumn['COLUMNS'][0]] = (int)$pk; |
1040
|
|
|
|
1041
|
|
|
$sql .= sprintf( |
1042
|
|
|
"INTO %s ", |
1043
|
|
|
$this->quoteTableName($tableName) |
1044
|
|
|
); |
1045
|
|
|
|
1046
|
|
|
$keys = array_keys($row); |
1047
|
|
|
$sql .= "(" . implode(', ', array_map([$this, 'quoteColumnName'], $keys)) . ") VALUES"; |
1048
|
|
|
|
1049
|
|
|
foreach ($row as $v) { |
1050
|
|
|
$vals[] = $v; |
1051
|
|
|
} |
1052
|
|
|
|
1053
|
|
|
$count_keys = count($keys); |
1054
|
|
|
$query = " (" . implode(', ', array_fill(0, $count_keys, '?')) . ") "; |
1055
|
|
|
|
1056
|
|
|
$queries = array_fill(0, 1, $query); |
1057
|
|
|
$sql .= implode(',', $queries); |
1058
|
|
|
} |
1059
|
|
|
$sql .= "SELECT 1 FROM DUAL"; |
1060
|
|
|
$stmt = $this->getConnection()->prepare($sql); |
1061
|
|
|
$stmt->execute($vals); |
1062
|
|
|
} |
1063
|
|
|
|
1064
|
|
|
/** |
1065
|
|
|
* Get Next Auto Increment Value Sequence |
1066
|
|
|
* |
1067
|
|
|
* |
1068
|
|
|
* @param string $sequence Sequence Name |
1069
|
|
|
* @return int |
1070
|
|
|
*/ |
1071
|
|
|
protected function getNextValSequence($sequence) |
1072
|
|
|
{ |
1073
|
|
|
$sql = "SELECT %s.NEXTVAL FROM DUAL"; |
1074
|
|
|
$rows = $this->fetchAll(sprintf($sql, $sequence)); |
1075
|
|
|
|
1076
|
|
|
return $rows[0]['NEXTVAL']; |
1077
|
|
|
} |
1078
|
|
|
|
1079
|
|
|
/** |
1080
|
|
|
* {@inheritdoc} |
1081
|
|
|
*/ |
1082
|
|
View Code Duplication |
public function getVersionLog() |
|
|
|
|
1083
|
|
|
{ |
1084
|
|
|
$result = []; |
1085
|
|
|
|
1086
|
|
|
switch ($this->options['version_order']) { |
1087
|
|
|
case \Phinx\Config\Config::VERSION_ORDER_CREATION_TIME: |
1088
|
|
|
$orderBy = '"version" ASC'; |
1089
|
|
|
break; |
1090
|
|
|
case \Phinx\Config\Config::VERSION_ORDER_EXECUTION_TIME: |
1091
|
|
|
$orderBy = '"start_time" ASC, "version" ASC'; |
1092
|
|
|
break; |
1093
|
|
|
default: |
1094
|
|
|
throw new \RuntimeException('Invalid version_order configuration option'); |
1095
|
|
|
} |
1096
|
|
|
|
1097
|
|
|
$rows = $this->fetchAll(sprintf('SELECT * FROM %s ORDER BY %s', $this->quoteColumnName( |
1098
|
|
|
$this->getSchemaTableName() |
1099
|
|
|
), $orderBy)); |
1100
|
|
|
foreach ($rows as $version) { |
1101
|
|
|
$result[$version['version']] = $version; |
1102
|
|
|
} |
1103
|
|
|
|
1104
|
|
|
return $result; |
1105
|
|
|
} |
1106
|
|
|
} |
1107
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.