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

OracleAdapter::renameDefault()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 16
Code Lines 10

Duplication

Lines 16
Ratio 100 %

Importance

Changes 0
Metric Value
dl 16
loc 16
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 10
nc 1
nop 3
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'])) {
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...
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');
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...
105
    }
106
107
    /**
108
     * {@inheritdoc}
109
     */
110
    public function commitTransaction()
111
    {
112
//        $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...
113
    }
114
115
    /**
116
     * {@inheritdoc}
117
     */
118
    public function rollbackTransaction()
119
    {
120
//        $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...
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) {
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
            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)
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...
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;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by Phinx\Db\Adapter\OracleAdapter::getColumnComment of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
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)
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...
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)
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...
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)
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...
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)
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...
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)
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...
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)
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...
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)
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...
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)
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...
603
    {
604
        if (is_string($columns)) {
605
            $columns = [$columns]; // str to array
606
        }
607
        $foreignKeys = $this->getForeignKeys($tableName);
608
609
        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...
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')
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...
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)
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...
678
    {
679
        if (is_string($columns)) {
680
            $columns = [$columns]; // str to array
681
        }
682
683
        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...
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 = [])
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...
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']))) {
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...
897
            $buffer[] = sprintf('(%s)', $column->getLimit() ?: $sqlType['limit']);
898
        }
899 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...
900
            $buffer[] = '(' . $column->getPrecision() . ',' . $column->getScale() . ')';
901
        }
902
903 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...
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)
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...
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) {
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...
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()
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...
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