Completed
Pull Request — master (#1326)
by
unknown
03:50
created

OracleAdapter::commitTransaction()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 1
nc 1
nop 0
1
<?php
2
/**
3
 * User: t-superofelipe
4
 * Date: 19/02/18
5
 * Time: 11:51
6
 */
7
8
/**
9
 * Phinx
10
 *
11
 * (The MIT license)
12
 * Copyright (c) 2015 Rob Morgan
13
 *
14
 * Permission is hereby granted, free of charge, to any person obtaining a copy
15
 * of this software and associated * documentation files (the "Software"), to
16
 * deal in the Software without restriction, including without limitation the
17
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
18
 * sell copies of the Software, and to permit persons to whom the Software is
19
 * furnished to do so, subject to the following conditions:
20
 *
21
 * The above copyright notice and this permission notice shall be included in
22
 * all copies or substantial portions of the Software.
23
 *
24
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30
 * IN THE SOFTWARE.
31
 *
32
 * @package    Phinx
33
 * @subpackage Phinx\Db\Adapter
34
 */
35
namespace Phinx\Db\Adapter;
36
37
use Phinx\Db\Table;
38
use Phinx\Db\Table\Column;
39
use Phinx\Db\Table\ForeignKey;
40
use Phinx\Db\Table\Index;
41
use Phinx\Migration\MigrationInterface;
42
43
/**
44
 * Phinx Oracle Adapter.
45
 *
46
 * @author Felipe Maia <[email protected]>
47
 */
48
class OracleAdapter extends PdoAdapter implements AdapterInterface
49
{
50
    protected $schema = 'dbo';
51
52
    protected $signedColumnTypes = ['integer' => true, 'biginteger' => true, 'float' => true, 'decimal' => true];
53
54
    /**
55
     * {@inheritdoc}
56
     */
57
    public function connect()
58
    {
59
        if ($this->connection === null) {
60
            if (!extension_loaded('pdo_oci')) {
61
                // @codeCoverageIgnoreStart
62
                throw new \RuntimeException('You need to enable the PDO_OCI extension for Phinx to run properly.');
63
                // @codeCoverageIgnoreEnd
64
            }
65
66
            $options = $this->getOptions();
67
68
            // if port is specified use it, otherwise use the Oracle default
69 View Code Duplication
            if (empty($options['port'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
70
                $dsn = "oci:dbname=//".$options['host']."/".$options['sid']."";
71
            } else {
72
                $dsn = "oci:dbname=//".$options['host'].":".$options['port']."/".$options['sid']."";
73
            }
74
75
            $driverOptions = [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION];
76
77
            try {
78
                $db = new \PDO($dsn, $options['user'], $options['pass'], $driverOptions);
79
            } catch (\PDOException $exception) {
80
                throw new \InvalidArgumentException(sprintf(
81
                    'There was a problem connecting to the database: %s',
82
                    $exception->getMessage()
83
                ));
84
            }
85
            $this->setConnection($db);
86
        }
87
    }
88
89
    /**
90
     * {@inheritdoc}
91
     */
92
    public function disconnect()
93
    {
94
        $this->connection = null;
95
    }
96
97
    /**
98
     * {@inheritdoc}
99
     */
100
    public function hasTransactions()
101
    {
102
        return true;
103
    }
104
105
    /**
106
     * {@inheritdoc}
107
     */
108
    public function beginTransaction()
109
    {
110
//        $this->execute('BEGIN TRANSACTION');
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
111
    }
112
113
    /**
114
     * {@inheritdoc}
115
     */
116
    public function commitTransaction()
117
    {
118
//        $this->execute('COMMIT TRANSACTION');
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
119
    }
120
121
    /**
122
     * {@inheritdoc}
123
     */
124
    public function rollbackTransaction()
125
    {
126
//        $this->execute('ROLLBACK TRANSACTION');
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
127
    }
128
129
    /**
130
     * {@inheritdoc}
131
     */
132
    public function quoteTableName($tableName)
133
    {
134
        return str_replace('.', '].[', $this->quoteColumnName($tableName));
135
    }
136
137
    /**
138
     * {@inheritdoc}
139
     */
140
    public function quoteColumnName($columnName)
141
    {
142
        return '"' . str_replace(']', '"', $columnName) . '"';
143
    }
144
145
    /**
146
     * {@inheritdoc}
147
     */
148
    public function hasTable($tableName)
149
    {
150
        $result = $this->fetchRow(sprintf('SELECT count(*) as count FROM ALL_TABLES WHERE table_name = \'%s\'', $tableName));
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) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
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'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
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')
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
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);
0 ignored issues
show
Unused Code introduced by
The call to OracleAdapter::getForeignKeySqlDefinition() has too many arguments starting with $key.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
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
        {
229
            foreach ($indexes as $index) {
230
                $sql = $this->getIndexSqlDefinition($index, $table->getName());
231
                $this->execute($sql);
232
            }
233
        }
234
235
        if(!$this->hasSequence($table->getName()))
236
        {
237
            $sql = "CREATE SEQUENCE SQ_".$table->getName()." MINVALUE 1 MAXVALUE 99999999999999999 INCREMENT BY 1";
238
            $this->execute($sql);
239
        }
240
    }
241
242
    /**
243
     * Verify if the table has a Sequence for primary Key
244
     *
245
     * @param string $tableName Table name
246
     *
247
     * @return boolean
248
     */
249
    public function hasSequence($tableName)
250
    {
251
        $sql = sprintf("SELECT COUNT(*) as COUNT FROM user_sequences WHERE sequence_name = '%s'", strtoupper("SQ_".$tableName));
252
        $result = $this->fetchRow($sql);
253
        return $result['COUNT'] > 0;
254
    }
255
256
    /**
257
     * Gets the Oracle Column Comment Defininition for a column object.
258
     *
259
     * @param \Phinx\Db\Table\Column $column    Column
260
     * @param string $tableName Table name
261
     *
262
     * @return string
263
     */
264
    protected function getColumnCommentSqlDefinition(Column $column, $tableName)
265
    {
266
        $comment = (strcasecmp($column->getComment(), 'NULL') !== 0) ? $column->getComment() : '';
267
268
        return sprintf(
269
            "COMMENT ON COLUMN \"%s\".\"%s\" IS '%s'",
270
            $tableName,
271
            $column->getName(),
272
            str_replace("'", "", $comment)
273
        );
274
    }
275
276
    /**
277
     * {@inheritdoc}
278
     */
279
    public function renameTable($tableName, $newTableName)
280
    {
281
        $this->execute(sprintf('alter table "%s" rename to "%s"', $tableName, $newTableName));
282
283
        if(!$this->hasSequence("SQ_" . strtoupper($newTableName))){
284
            $this->renameSequence("SQ_" . strtoupper($tableName), "SQ_" . strtoupper($newTableName));
285
        }
286
    }
287
288
    public function renameSequence($sequenceName, $newSequenceName)
289
    {
290
        $this->execute(sprintf('rename "%s" to "%s"', $sequenceName, $newSequenceName));
291
    }
292
293
    /**
294
     * {@inheritdoc}
295
     */
296
    public function dropTable($tableName)
297
    {
298
        $this->execute(sprintf('DROP TABLE %s', $this->quoteTableName($tableName)));
299
        $this->execute(sprintf('DROP SEQUENCE %s', $this->quoteTableName(strtoupper("SQ_" . $tableName))));
300
    }
301
302
    /**
303
     * {@inheritdoc}
304
     */
305
    public function truncateTable($tableName)
306
    {
307
        $sql = sprintf(
308
            'TRUNCATE TABLE %s',
309
            $this->quoteTableName($tableName)
310
        );
311
312
        $this->execute($sql);
313
    }
314
315 View Code Duplication
    public function getColumnComment($tableName, $columnName)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
316
    {
317
        $sql = sprintf("select COMMENTS from ALL_COL_COMMENTS WHERE COLUMN_NAME = '%s' and TABLE_NAME = '%s'",
318
            $columnName, $tableName);
319
        $row = $this->fetchRow($sql);
320
321
        if ($row['COMMENTS'] != 'NULL') {
322
            return $row['COMMENTS'];
323
        }
324
325
        return false;
326
    }
327
328
    /**
329
     * {@inheritdoc}
330
     */
331
    public function getColumns($tableName)
332
    {
333
        $columns = [];
334
335
        $sql = sprintf("select TABLE_NAME \"TABLE_NAME\", COLUMN_NAME \"NAME\", DATA_TYPE \"TYPE\", NULLABLE \"NULL\", DATA_DEFAULT \"DEFAULT\",
336
            DATA_LENGTH \"CHAR_LENGTH\", DATA_PRECISION \"PRECISION\", DATA_SCALE \"SCALE\", COLUMN_ID \"ORDINAL_POSITION\"
337
            FROM ALL_TAB_COLUMNS WHERE table_name = '%s'", $tableName);
338
339
        $rows = $this->fetchAll($sql);
340
341
        foreach ($rows as $columnInfo) {
342
            $default = NULL;
343
            if(trim($columnInfo['DEFAULT']) != 'NULL'){
344
                $default = trim($columnInfo['DEFAULT']);
345
            }
346
347
            $column = new Column();
348
            $column->setName($columnInfo['NAME'])
349
                ->setType($this->getPhinxType($columnInfo['TYPE'], $columnInfo['PRECISION']))
350
                ->setNull($columnInfo['NULL'] !== 'N')
351
                ->setDefault($default)
352
//                TODO VERIFICAR SE � PRIMARY KEY
353
//                ->setIdentity($columnInfo['identity'] === '1')
354
                ->setComment($this->getColumnComment($columnInfo['TABLE_NAME'], $columnInfo['NAME']));
355
356
            if (!empty($columnInfo['CHAR_LENGTH'])) {
357
                $column->setLimit($columnInfo['CHAR_LENGTH']);
358
            }
359
360
            $columns[$columnInfo['NAME']] = $column;
361
        }
362
363
        return $columns;
364
    }
365
366 View Code Duplication
    protected function parseDefault($default)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
367
    {
368
        $default = preg_replace(["/\('(.*)'\)/", "/\(\((.*)\)\)/", "/\((.*)\)/"], '$1', $default);
369
370
        if (strtoupper($default) === 'NULL') {
371
            $default = null;
372
        } elseif (is_numeric($default)) {
373
            $default = (int)$default;
374
        }
375
376
        return $default;
377
    }
378
379
    /**
380
     * {@inheritdoc}
381
     */
382 View Code Duplication
    public function hasColumn($tableName, $columnName)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
383
    {
384
        $sql = sprintf("select count(*) as count from ALL_TAB_COLUMNS 
385
            where table_name = '%s' and column_name = '%s'",
386
            $tableName,
387
            $columnName
388
        );
389
390
        $result = $this->fetchRow($sql);
391
        return $result['COUNT'] > 0;
392
    }
393
394
    /**
395
     * {@inheritdoc}
396
     */
397 View Code Duplication
    public function addColumn(Table $table, Column $column)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
398
    {
399
        $sql = sprintf(
400
            'ALTER TABLE %s ADD %s %s',
401
            $this->quoteTableName($table->getName()),
402
            $this->quoteColumnName($column->getName()),
403
            $this->getColumnSqlDefinition($column)
404
        );
405
406
        $this->execute($sql);
407
    }
408
409
    /**
410
     * {@inheritdoc}
411
     */
412
    public function renameColumn($tableName, $columnName, $newColumnName)
413
    {
414
        if (!$this->hasColumn($tableName, $columnName)) {
415
            throw new \InvalidArgumentException("The specified column does not exist: $columnName");
416
        }
417
//        $this->renameDefault($tableName, $columnName, $newColumnName);
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
418
419
        $this->execute(
420
            sprintf(
421
                "alter table \"%s\" rename column \"%s\" TO \"%s\"",
422
                $tableName,
423
                $columnName,
424
                $newColumnName
425
            )
426
        );
427
    }
428
429 View Code Duplication
    protected function renameDefault($tableName, $columnName, $newColumnName)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
430
    {
431
        $oldConstraintName = "DF_{$tableName}_{$columnName}";
432
        $newConstraintName = "DF_{$tableName}_{$newColumnName}";
433
        $sql = <<<SQL
434
IF (OBJECT_ID('$oldConstraintName', 'D') IS NOT NULL)
435
BEGIN
436
     EXECUTE sp_rename N'%s', N'%s', N'OBJECT'
437
END
438
SQL;
439
        $this->execute(sprintf(
440
            $sql,
441
            $oldConstraintName,
442
            $newConstraintName
443
        ));
444
    }
445
446
    /**
447
     * {@inheritdoc}
448
     */
449
    public function changeColumn($tableName, $columnName, Column $newColumn)
450
    {
451
        $columns = $this->getColumns($tableName);
452
453
        if ($columnName !== $newColumn->getName()) {
454
            $this->renameColumn($tableName, $columnName, $newColumn->getName());
455
        }
456
457
        $setNullSql = ($newColumn->isNull() == $columns[$columnName]->isNull() ? false : true);
458
459
        $this->execute(
460
            sprintf(
461
                'ALTER TABLE %s MODIFY(%s %s)',
462
                $this->quoteTableName($tableName),
463
                $this->quoteColumnName($newColumn->getName()),
464
                $this->getColumnSqlDefinition($newColumn, false, $setNullSql)
465
            )
466
        );
467
        // change column comment if needed
468
        if ($newColumn->getComment()) {
469
            $sql = $this->getColumnCommentSqlDefinition($newColumn, $tableName);
470
            $this->execute($sql);
471
        }
472
473
    }
474
475
    /**
476
     * {@inheritdoc}
477
     */
478
    public function dropColumn($tableName, $columnName)
479
    {
480
        $this->execute(
481
            sprintf(
482
                'ALTER TABLE %s DROP COLUMN %s',
483
                $this->quoteTableName($tableName),
484
                $this->quoteColumnName($columnName)
485
            )
486
        );
487
    }
488
489
    /**
490
     * Get an array of indexes from a particular table.
491
     *
492
     * @param string $tableName Table Name
493
     * @return array
494
     */
495 View Code Duplication
    public function getIndexes($tableName)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
496
    {
497
        $indexes = [];
498
        $sql = "SELECT index_owner as owner, index_name, column_name FROM ALL_IND_COLUMNS WHERE TABLE_NAME = '$tableName'";
499
500
        $rows = $this->fetchAll($sql);
501
        foreach ($rows as $row) {
502
            if (!isset($indexes[$row['INDEX_NAME']])) {
503
                $indexes[$row['INDEX_NAME']] = ['columns' => []];
504
            }
505
            $indexes[$row['INDEX_NAME']]['columns'][] = strtoupper($row['COLUMN_NAME']);
506
        }
507
508
        return $indexes;
509
    }
510
511
    /**
512
     * {@inheritdoc}
513
     */
514 View Code Duplication
    public function hasIndex($tableName, $columns)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
515
    {
516
517
        if (is_string($columns)) {
518
            $columns = [$columns]; // str to array
519
        }
520
521
        $indexes = $this->getIndexes($tableName);
522
        foreach ($indexes as $index) {
523
            $a = array_diff($columns, $index['columns']);
524
525
            if (empty($a)) {
526
                return true;
527
            }
528
        }
529
530
        return false;
531
    }
532
533
    /**
534
     * {@inheritdoc}
535
     */
536 View Code Duplication
    public function hasIndexByName($tableName, $indexName)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
537
    {
538
        $indexes = $this->getIndexes($tableName);
539
540
        foreach ($indexes as $name => $index) {
541
            if ($name === $indexName) {
542
                return true;
543
            }
544
        }
545
546
        return false;
547
    }
548
549
    /**
550
     * {@inheritdoc}
551
     */
552
    public function addIndex(Table $table, Index $index)
553
    {
554
        $sql = $this->getIndexSqlDefinition($index, $table->getName());
555
        $this->execute($sql);
556
    }
557
558
    /**
559
     * {@inheritdoc}
560
     */
561 View Code Duplication
    public function dropIndex($tableName, $columns)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
562
    {
563
        if (is_string($columns)) {
564
            $columns = [$columns]; // str to array
565
        }
566
567
        $indexes = $this->getIndexes($tableName);
568
        $columns = array_map('strtoupper', $columns);
569
570
        foreach ($indexes as $indexName => $index) {
571
            $a = array_diff($columns, $index['columns']);
572
            if (empty($a)) {
573
                $this->execute(
574
                    sprintf(
575
                        'DROP INDEX %s',
576
                        $this->quoteColumnName($indexName)
577
                    )
578
                );
579
580
                return;
581
            }
582
        }
583
    }
584
585
    /**
586
     * {@inheritdoc}
587
     */
588 View Code Duplication
    public function dropIndexByName($tableName, $indexName)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
589
    {
590
        $indexes = $this->getIndexes($tableName);
591
592
        foreach ($indexes as $name => $index) {
593
            if ($name === $indexName) {
594
                $this->execute(
595
                    sprintf(
596
                        'DROP INDEX %s',
597
                        $this->quoteColumnName($indexName),
598
                        $this->quoteTableName($tableName)
599
                    )
600
                );
601
602
                return;
603
            }
604
        }
605
    }
606
607
    /**
608
     * {@inheritdoc}
609
     */
610 View Code Duplication
    public function hasForeignKey($tableName, $columns, $constraint = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
611
    {
612
        if (is_string($columns)) {
613
            $columns = [$columns]; // str to array
614
        }
615
        $foreignKeys = $this->getForeignKeys($tableName);
616
617
        if ($constraint) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $constraint of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
618
            if (isset($foreignKeys[$constraint])) {
619
                return !empty($foreignKeys[$constraint]);
620
            }
621
622
            return false;
623
        } else {
624
            foreach ($foreignKeys as $key) {
625
                $a = array_diff($columns, $key['COLUMNS']);
626
                if (empty($a)) {
627
                    return true;
628
                }
629
            }
630
631
            return false;
632
        }
633
    }
634
635
    /**
636
     * Get an array of foreign keys from a particular table.
637
     *
638
     * @param string $tableName Table Name
639
     * @return array
640
     */
641 View Code Duplication
    protected function getForeignKeys($tableName, $type = 'R')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
642
    {
643
        $foreignKeys = [];
644
        $rows = $this->fetchAll(sprintf(
645
            "SELECT a.CONSTRAINT_NAME, a.TABLE_NAME, b.COLUMN_NAME, 
646
                    (SELECT c.TABLE_NAME from ALL_CONS_COLUMNS c WHERE c.CONSTRAINT_NAME = a.R_CONSTRAINT_NAME) referenced_table_name,
647
                    (SELECT c.COLUMN_NAME from ALL_CONS_COLUMNS c WHERE c.CONSTRAINT_NAME = a.R_CONSTRAINT_NAME) referenced_column_name
648
                    FROM all_constraints a JOIN ALL_CONS_COLUMNS b ON a.CONSTRAINT_NAME = b.CONSTRAINT_NAME
649
                    WHERE a.table_name = '%s'
650
                    AND CONSTRAINT_TYPE = '%s'",
651
            $tableName,
652
            $type
653
        ));
654
655
        foreach ($rows as $row) {
656
            $foreignKeys[$row['CONSTRAINT_NAME']]['TABLE'] = $row['TABLE_NAME'];
657
            $foreignKeys[$row['CONSTRAINT_NAME']]['COLUMNS'][] = $row['COLUMN_NAME'];
658
            $foreignKeys[$row['CONSTRAINT_NAME']]['REFERENCED_TABLE'] = $row['REFERENCED_TABLE_NAME'];
659
            $foreignKeys[$row['CONSTRAINT_NAME']]['REFERENCED_COLUMNS'][] = $row['REFERENCED_COLUMN_NAME'];
660
        }
661
662
        return $foreignKeys;
663
    }
664
665
    /**
666
     * {@inheritdoc}
667
     */
668
    public function addForeignKey(Table $table, ForeignKey $foreignKey)
669
    {
670
671
        $this->execute(
672
            sprintf(
673
                'ALTER TABLE %s ADD %s',
674
                $this->quoteTableName($table->getName()),
675
                $this->getForeignKeySqlDefinition($foreignKey, $table->getName())
676
            )
677
        );
678
    }
679
680
    /**
681
     * {@inheritdoc}
682
     */
683 View Code Duplication
    public function dropForeignKey($tableName, $columns, $constraint = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
684
    {
685
        if (is_string($columns)) {
686
            $columns = [$columns]; // str to array
687
        }
688
689
        if ($constraint) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $constraint of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
690
            $this->execute(
691
                sprintf(
692
                    'ALTER TABLE %s DROP CONSTRAINT %s',
693
                    $this->quoteTableName($tableName),
694
                    $constraint
695
                )
696
            );
697
698
            return;
699
        } else {
700
            foreach ($columns as $column) {
701
                $rows = $this->fetchAll(sprintf(
702
                    "SELECT a.CONSTRAINT_NAME, a.TABLE_NAME, b.COLUMN_NAME, 
703
                    (SELECT c.TABLE_NAME from ALL_CONS_COLUMNS c 
704
                    WHERE c.CONSTRAINT_NAME = a.R_CONSTRAINT_NAME) referenced_table_name,
705
                    (SELECT c.COLUMN_NAME from ALL_CONS_COLUMNS c 
706
                    WHERE c.CONSTRAINT_NAME = a.R_CONSTRAINT_NAME) referenced_column_name
707
                    FROM all_constraints a JOIN ALL_CONS_COLUMNS b ON a.CONSTRAINT_NAME = b.CONSTRAINT_NAME
708
                    WHERE a.table_name = '%s'
709
                    AND CONSTRAINT_TYPE = 'R'
710
                    AND COLUMN_NAME = '%s'",
711
                    $tableName,
712
                    $column
713
                ));
714
                foreach ($rows as $row) {
715
                    $this->dropForeignKey($tableName, $columns, $row['CONSTRAINT_NAME']);
716
                }
717
            }
718
        }
719
    }
720
721
    /**
722
     * {@inheritdoc}
723
     */
724
    public function getSqlType($type, $limit = null)
725
    {
726
//      reference: https://docs.oracle.com/cd/B19306_01/gateways.102/b14270/apa.htm
727
        switch ($type) {
728
            case static::PHINX_TYPE_STRING:
729
                return ['name' => 'VARCHAR2', 'limit' => 255];
730
            case static::PHINX_TYPE_CHAR:
731
                return ['name' => 'CHAR', 'limit' => 255];
732
            case static::PHINX_TYPE_TEXT:
733
                return ['name' => 'LONG'];
734
            case static::PHINX_TYPE_INTEGER:
735
                return ['name' => 'NUMBER', 'precision' => 10];
736
            case static::PHINX_TYPE_BIG_INTEGER:
737
                return ['name' => 'NUMBER', 'precision' => 19];
738
            case static::PHINX_TYPE_FLOAT:
739
                return ['name' => 'FLOAT', 'precision' => 49];
740
            case static::PHINX_TYPE_DECIMAL:
741
                return ['name' => 'NUMBER'];
742
            case static::PHINX_TYPE_DATETIME:
743
                return ['name' => 'DATE'];
744
            case static::PHINX_TYPE_TIMESTAMP:
745
                return ['name' => 'TIMESTAMP'];
746
            case static::PHINX_TYPE_TIME:
747
                return ['name' => 'time'];
748
            case static::PHINX_TYPE_DATE:
749
                return ['name' => 'DATE'];
750
            case static::PHINX_TYPE_BLOB:
751
                return ['name' => 'BLOB'];
752
            case 'CLOB':
753
                return ['name' => 'CLOB'];
754
            case static::PHINX_TYPE_BINARY:
755
                return ['name' => 'RAW', 'limit' => 2000];
756
            case static::PHINX_TYPE_BOOLEAN:
757
                return ['name' => 'NUMBER', 'precision' => 1];
758
            case static::PHINX_TYPE_UUID:
759
                return ['name' => 'RAW', 'precision' => 16, 'default' => 'SYS_GUID()', 'limit' => 2000];
760
            case static::PHINX_TYPE_FILESTREAM:
761
                return ['name' => 'varbinary', 'limit' => 'max'];
762
            // Geospatial database types
763
            case static::PHINX_TYPE_GEOMETRY:
764
            case static::PHINX_TYPE_POINT:
765
            case static::PHINX_TYPE_LINESTRING:
766
            case static::PHINX_TYPE_POLYGON:
767
                // SQL Server stores all spatial data using a single data type.
768
                // Specific types (point, polygon, etc) are set at insert time.
769
                return ['name' => 'geography'];
770
            default:
771
                throw new \RuntimeException('The type: "' . $type . '" is not supported.');
772
        }
773
    }
774
775
    /**
776
     * Returns Phinx type by SQL type
777
     *
778
     * @param string $sqlType SQL Type definition
779
     * @throws \RuntimeException
780
     * @internal param string $sqlType SQL type
781
     * @returns string Phinx type
782
     */
783
    public function getPhinxType($sqlType, $precision = null)
784
    {
785
        if($sqlType === 'VARCHAR2'){
786
            return static::PHINX_TYPE_STRING;
787
        } elseif($sqlType === 'CHAR'){
788
            return static::PHINX_TYPE_CHAR;
789
        } elseif($sqlType == 'LONG') {
790
            return static::PHINX_TYPE_TEXT;
791
        } elseif($sqlType === 'NUMBER' AND $precision === 10) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
792
            return static::PHINX_TYPE_INTEGER;
793
        } elseif($sqlType === 'NUMBER' AND $precision === 19) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
794
            return static::PHINX_TYPE_BIG_INTEGER;
795
        } elseif($sqlType === 'FLOAT') {
796
            return static::PHINX_TYPE_FLOAT;
797
        } elseif ($sqlType === 'TIMESTAMP(6)') {
798
            return static::PHINX_TYPE_TIMESTAMP;
799
        } elseif ($sqlType === 'TIME') {
800
            return static::PHINX_TYPE_TIME;
801
        } elseif ($sqlType === 'DATE') {
802
            return static::PHINX_TYPE_DATE;
803
        } elseif ($sqlType === 'BLOB') {
804
            return static::PHINX_TYPE_BLOB;
805
        } elseif ($sqlType === 'CLOB') {
806
            return 'CLOB';
807
        } elseif ($sqlType === 'RAW' AND $precision === 16) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
808
            return static::PHINX_TYPE_UUID;
809
        } elseif ($sqlType === 'RAW') {
810
            return static::PHINX_TYPE_BLOB;
811
        } elseif ($sqlType === 'NUMBER' AND $precision === 1) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
812
            return static::PHINX_TYPE_BOOLEAN;
813
        } elseif ($sqlType === 'NUMBER') {
814
            return static::PHINX_TYPE_DECIMAL;
815
        } else{
816
            throw new \RuntimeException('The Oracle type: "' . $sqlType . '" is not supported');
817
        }
818
        //TODO Geospatial database types and Filestream type
819
    }
820
821
    /**
822
     * {@inheritdoc}
823
     */
824
    //    TODO
825 View Code Duplication
    public function createDatabase($name, $options = [])
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
826
    {
827
        if (isset($options['collation'])) {
828
            $this->execute(sprintf('CREATE DATABASE [%s] COLLATE [%s]', $name, $options['collation']));
829
        } else {
830
            $this->execute(sprintf('CREATE DATABASE [%s]', $name));
831
        }
832
        $this->execute(sprintf('USE [%s]', $name));
833
    }
834
835
    /**
836
     * {@inheritdoc}
837
     */
838
    public function hasDatabase($name)
839
    {
840
        $result = $this->fetchRow(
841
            sprintf(
842
                'SELECT count(*) as [count] FROM master.dbo.sysdatabases WHERE [name] = \'%s\'',
843
                $name
844
            )
845
        );
846
847
        return $result['count'] > 0;
848
    }
849
850
    /**
851
     * {@inheritdoc}
852
     */
853
//    TODO
854
    public function dropDatabase($name)
855
    {
856
        $sql = <<<SQL
857
USE master;
858
IF EXISTS(select * from sys.databases where name=N'$name')
859
ALTER DATABASE [$name] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
860
DROP DATABASE [$name];
861
SQL;
862
        $this->execute($sql);
863
    }
864
865
    /**
866
     * Get the defintion for a `DEFAULT` statement.
867
     *
868
     * @param  mixed $default
869
     * @return string
870
     */
871
    protected function getDefaultValueDefinition($default)
872
    {
873
        if (is_string($default) && 'CURRENT_TIMESTAMP' !== $default && 'SYSDATE' !== $default) {
874
            $default = $this->getConnection()->quote($default);
875
        } elseif (is_bool($default)) {
876
877
            $default = $this->castToBool($default);
878
        }
879
880
        return isset($default) ? ' DEFAULT ' . $default : 'DEFAULT NULL';
881
    }
882
883
    /**
884
     * Gets the Oracle Column Definition for a Column object.
885
     *
886
     * @param \Phinx\Db\Table\Column $column Column
887
     * @return string
888
     */
889
    protected function getColumnSqlDefinition(Column $column, $create = true, $setNullSql = true)
0 ignored issues
show
Unused Code introduced by
The parameter $create is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
890
    {
891
        $buffer = [];
892
893
        $sqlType = $this->getSqlType($column->getType());
894
895
        $buffer[] = strtoupper($sqlType['name']);
896
        // integers cant have limits in Oracle
897
        $noLimits = [
898
            static::PHINX_TYPE_INTEGER,
899
            static::PHINX_TYPE_BIG_INTEGER,
900
            static::PHINX_TYPE_FLOAT,
901
            static::PHINX_TYPE_UUID,
902
            static::PHINX_TYPE_BOOLEAN
903
        ];
904 View Code Duplication
        if (!in_array($column->getType(), $noLimits) && ($column->getLimit() || isset($sqlType['limit']))) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
905
            $buffer[] = sprintf('(%s)', $column->getLimit() ?: $sqlType['limit']);
906
        }
907 View Code Duplication
        if ($column->getPrecision() && $column->getScale()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
908
            $buffer[] = '(' . $column->getPrecision() . ',' . $column->getScale() . ')';
909
        }
910
911 View Code Duplication
        if ($column->getDefault() === null && $column->isNull()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
912
            $buffer[] = ' DEFAULT NULL';
913
        } else {
914
            $buffer[] = $this->getDefaultValueDefinition($column->getDefault());
915
        }
916
917
        if($setNullSql){
918
            $buffer[] = $column->isNull() ? 'NULL' : 'NOT NULL';
919
        }
920
921
        return implode(' ', $buffer);
922
    }
923
924
    /**
925
     * Gets the Oracle Index Definition for an Index object.
926
     *
927
     * @param \Phinx\Db\Table\Index $index Index
928
     * @return string
929
     */
930 View Code Duplication
    protected function getIndexSqlDefinition(Index $index, $tableName)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
931
    {
932
        if (is_string($index->getName())) {
933
            $indexName = $index->getName();
934
        } else {
935
            $columnNames = $index->getColumns();
936
            if (is_string($columnNames)) {
937
                $columnNames = [$columnNames];
938
            }
939
            $indexName = sprintf('%s_%s', $tableName, implode('_', $columnNames));
940
        }
941
        $def = sprintf(
942
            "CREATE %s INDEX %s ON %s (%s)",
943
            ($index->getType() === Index::UNIQUE ? 'UNIQUE' : ''),
944
            $indexName,
945
            $this->quoteTableName($tableName),
946
            '"' . implode('","', $index->getColumns()) . '"'
947
        );
948
949
        return $def;
950
    }
951
952
    /**
953
     * Gets the Oracle Foreign Key Definition for an ForeignKey object.
954
     *
955
     * @param \Phinx\Db\Table\ForeignKey $foreignKey
956
     * @return string
957
     */
958
    protected function getForeignKeySqlDefinition(ForeignKey $foreignKey, $tableName)
959
    {
960
        $constraintName = $foreignKey->getConstraint() ?: $tableName . '_' . implode('_', $foreignKey->getColumns());
961
        $def = ' CONSTRAINT ' . $this->quoteColumnName(substr($constraintName,0, 27));
962
        $def .= ' FOREIGN KEY ("' . implode('", "', $foreignKey->getColumns()) . '")';
963
        $def .= " REFERENCES {$this->quoteTableName($foreignKey->getReferencedTable()->getName())} (\"" . implode('", "', $foreignKey->getReferencedColumns()) . '")';
964
        if ($foreignKey->getOnDelete() && $foreignKey->getOnDelete() != "NO ACTION") {
965
            $def .= " ON DELETE {$foreignKey->getOnDelete()}";
966
        }
967
        if ($foreignKey->getOnUpdate()) {
968
            $def .= " ON UPDATE {$foreignKey->getOnUpdate()}";
969
        }
970
971
        return $def;
972
    }
973
974
    /**
975
     * {@inheritdoc}
976
     */
977
    public function getColumnTypes()
978
    {
979
        return array_merge(parent::getColumnTypes(), ['filestream']);
980
    }
981
982
    /**
983
     * Records a migration being run.
984
     *
985
     * @param \Phinx\Migration\MigrationInterface $migration Migration
986
     * @param string $direction Direction
987
     * @param int $startTime Start Time
988
     * @param int $endTime End Time
989
     * @return \Phinx\Db\Adapter\AdapterInterface
990
     */
991
    public function migrated(\Phinx\Migration\MigrationInterface $migration, $direction, $startTime, $endTime)
992
    {
993
        $startTime = "TO_TIMESTAMP('$startTime', 'YYYY-MM-DD HH24:MI:SS')";
994
        $endTime = "TO_TIMESTAMP('$endTime', 'YYYY-MM-DD HH24:MI:SS')";
995
996 View Code Duplication
        if (strcasecmp($direction, MigrationInterface::UP) === 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
997
            // up
998
            $sql = sprintf(
999
                "INSERT INTO \"%s\" (%s, %s, %s, %s, %s) VALUES ('%s', '%s', %s, %s, %s)",
1000
                $this->getSchemaTableName(),
1001
                $this->quoteColumnName('version'),
1002
                $this->quoteColumnName('migration_name'),
1003
                $this->quoteColumnName('start_time'),
1004
                $this->quoteColumnName('end_time'),
1005
                $this->quoteColumnName('breakpoint'),
1006
                $migration->getVersion(),
1007
                substr($migration->getName(), 0, 100),
1008
                $startTime,
1009
                $endTime,
1010
                $this->castToBool(false)
1011
            );
1012
1013
            $this->execute($sql);
1014
        } else {
1015
            // down
1016
            $sql = sprintf(
1017
                "DELETE FROM \"%s\" WHERE %s = '%s'",
1018
                $this->getSchemaTableName(),
1019
                $this->quoteColumnName('version'),
1020
                $migration->getVersion()
1021
            );
1022
1023
            $this->execute($sql);
1024
        }
1025
1026
        return $this;
1027
    }
1028
1029
    /**
1030
     * {@inheritdoc}
1031
     */
1032
    public function bulkinsert(Table $table, $rows)
1033
    {
1034
        $sql = "INSERT ALL ";
1035
1036
        $vals = [];
1037
        $tableName = $table->getName();
1038
        $primaryKeyColumn = current($this->getForeignKeys($tableName, 'P'));
1039
        $sequenceNextVal = $this->getNextValSequence('SQ_' . $tableName);
1040
//        buscar sequence e primary key padr�o para incrementar PK com a SEQUENCE.NEXTVAL
1041
1042
        foreach ($rows as $key => $row) {
1043
            $pk = ($sequenceNextVal + $key);
1044
            $row[$primaryKeyColumn['COLUMNS'][0]] = (int) $pk;
1045
1046
            $sql .= sprintf(
1047
                "INTO %s ",
1048
                $this->quoteTableName($tableName)
1049
            );
1050
1051
            $keys = array_keys($row);
1052
            $sql .= "(" . implode(', ', array_map([$this, 'quoteColumnName'], $keys)) . ") VALUES";
1053
1054
            foreach ($row as $v) {
1055
                $vals[] = $v;
1056
            }
1057
1058
            $count_keys = count($keys);
1059
            $query = " (" . implode(', ', array_fill(0, $count_keys, '?')) . ") ";
1060
1061
            $queries = array_fill(0, 1, $query);
1062
            $sql .= implode(',', $queries);
1063
        }
1064
        $sql .= "SELECT 1 FROM DUAL";
1065
        $stmt = $this->getConnection()->prepare($sql);
1066
        $stmt->execute($vals);
1067
    }
1068
1069
    protected function getNextValSequence($sequence)
1070
    {
1071
        $sql = "SELECT %s.NEXTVAL FROM DUAL";
1072
        $rows = $this->fetchAll(sprintf($sql, $sequence));
1073
        return $rows[0]['NEXTVAL'];
1074
    }
1075
    
1076
    /**
1077
     * {@inheritdoc}
1078
     */
1079 View Code Duplication
    public function getVersionLog()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
1080
    {
1081
        $result = [];
1082
1083
        switch ($this->options['version_order']) {
1084
            case \Phinx\Config\Config::VERSION_ORDER_CREATION_TIME:
1085
                $orderBy = '"version" ASC';
1086
                break;
1087
            case \Phinx\Config\Config::VERSION_ORDER_EXECUTION_TIME:
1088
                $orderBy = '"start_time" ASC, "version" ASC';
1089
                break;
1090
            default:
1091
                throw new \RuntimeException('Invalid version_order configuration option');
1092
        }
1093
1094
        $rows = $this->fetchAll(sprintf('SELECT * FROM %s ORDER BY %s', $this->quoteColumnName(
1095
            $this->getSchemaTableName()), $orderBy));
1096
        foreach ($rows as $version) {
1097
            $result[$version['version']] = $version;
1098
        }
1099
1100
        return $result;
1101
    }
1102
}
1103