Failed Conditions
Push — master ( 656579...2742cd )
by Marco
11:55
created

_getPortableTableColumnDefinition()   F

Complexity

Conditions 37
Paths 2496

Size

Total Lines 115
Code Lines 92

Duplication

Lines 7
Ratio 6.09 %

Code Coverage

Tests 0
CRAP Score 1406

Importance

Changes 0
Metric Value
dl 7
loc 115
rs 2
c 0
b 0
f 0
ccs 0
cts 88
cp 0
cc 37
eloc 92
nc 2496
nop 1
crap 1406

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\DBAL\Schema;
21
22
use Doctrine\DBAL\DBALException;
23
use Doctrine\DBAL\Driver\DriverException;
24
use Doctrine\DBAL\Types\Type;
25
26
/**
27
 * Oracle Schema Manager.
28
 *
29
 * @author Konsta Vesterinen <[email protected]>
30
 * @author Lukas Smith <[email protected]> (PEAR MDB2 library)
31
 * @author Benjamin Eberlei <[email protected]>
32
 * @since  2.0
33
 */
34
class OracleSchemaManager extends AbstractSchemaManager
35
{
36
    /**
37
     * {@inheritdoc}
38
     */
39 View Code Duplication
    public function dropDatabase($database)
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...
40
    {
41
        try {
42
            parent::dropDatabase($database);
43
        } catch (DBALException $exception) {
44
            $exception = $exception->getPrevious();
45
46
            if (! $exception instanceof DriverException) {
47
                throw $exception;
48
            }
49
50
            // If we have a error code 1940 (ORA-01940), the drop database operation failed
51
            // because of active connections on the database.
52
            // To force dropping the database, we first have to close all active connections
53
            // on that database and issue the drop database operation again.
54
            if ($exception->getErrorCode() !== 1940) {
55
                throw $exception;
56
            }
57
58
            $this->killUserSessions($database);
59
60
            parent::dropDatabase($database);
61
        }
62
    }
63
64
    /**
65
     * {@inheritdoc}
66
     */
67
    protected function _getPortableViewDefinition($view)
68
    {
69
        $view = \array_change_key_case($view, CASE_LOWER);
70
71
        return new View($this->getQuotedIdentifierName($view['view_name']), $view['text']);
72
    }
73
74
    /**
75
     * {@inheritdoc}
76
     */
77
    protected function _getPortableUserDefinition($user)
78
    {
79
        $user = \array_change_key_case($user, CASE_LOWER);
80
81
        return [
82
            'user' => $user['username'],
83
        ];
84
    }
85
86
    /**
87
     * {@inheritdoc}
88
     */
89
    protected function _getPortableTableDefinition($table)
90
    {
91
        $table = \array_change_key_case($table, CASE_LOWER);
92
93
        return $this->getQuotedIdentifierName($table['table_name']);
94
    }
95
96
    /**
97
     * {@inheritdoc}
98
     *
99
     * @license New BSD License
100
     * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html
101
     */
102
    protected function _getPortableTableIndexesList($tableIndexes, $tableName=null)
103
    {
104
        $indexBuffer = [];
105
        foreach ($tableIndexes as $tableIndex) {
106
            $tableIndex = \array_change_key_case($tableIndex, CASE_LOWER);
107
108
            $keyName = strtolower($tableIndex['name']);
109
110
            if (strtolower($tableIndex['is_primary']) == "p") {
111
                $keyName = 'primary';
112
                $buffer['primary'] = true;
113
                $buffer['non_unique'] = false;
114
            } else {
115
                $buffer['primary'] = false;
116
                $buffer['non_unique'] = ($tableIndex['is_unique'] == 0) ? true : false;
117
            }
118
            $buffer['key_name'] = $keyName;
119
            $buffer['column_name'] = $this->getQuotedIdentifierName($tableIndex['column_name']);
120
            $indexBuffer[] = $buffer;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $buffer seems to be defined later in this foreach loop on line 112. Are you sure it is defined here?
Loading history...
121
        }
122
123
        return parent::_getPortableTableIndexesList($indexBuffer, $tableName);
124
    }
125
126
    /**
127
     * {@inheritdoc}
128
     */
129
    protected function _getPortableTableColumnDefinition($tableColumn)
130
    {
131
        $tableColumn = \array_change_key_case($tableColumn, CASE_LOWER);
132
133
        $dbType = strtolower($tableColumn['data_type']);
134
        if (strpos($dbType, "timestamp(") === 0) {
135
            if (strpos($dbType, "with time zone")) {
136
                $dbType = "timestamptz";
137
            } else {
138
                $dbType = "timestamp";
139
            }
140
        }
141
142
        $unsigned = $fixed = null;
143
144
        if ( ! isset($tableColumn['column_name'])) {
145
            $tableColumn['column_name'] = '';
146
        }
147
148
        // Default values returned from database sometimes have trailing spaces.
149
        $tableColumn['data_default'] = trim($tableColumn['data_default']);
150
151 View Code Duplication
        if ($tableColumn['data_default'] === '' || $tableColumn['data_default'] === 'NULL') {
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...
152
            $tableColumn['data_default'] = null;
153
        }
154
155 View Code Duplication
        if (null !== $tableColumn['data_default']) {
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...
156
            // Default values returned from database are enclosed in single quotes.
157
            $tableColumn['data_default'] = trim($tableColumn['data_default'], "'");
158
        }
159
160
        $precision = null;
161
        $scale = null;
162
163
        $type = $this->_platform->getDoctrineTypeMapping($dbType);
164
        $type = $this->extractDoctrineTypeFromComment($tableColumn['comments'], $type);
165
        $tableColumn['comments'] = $this->removeDoctrineTypeFromComment($tableColumn['comments'], $type);
166
167
        switch ($dbType) {
168
            case 'number':
169
                if ($tableColumn['data_precision'] == 20 && $tableColumn['data_scale'] == 0) {
170
                    $precision = 20;
171
                    $scale = 0;
172
                    $type = 'bigint';
173
                } elseif ($tableColumn['data_precision'] == 5 && $tableColumn['data_scale'] == 0) {
174
                    $type = 'smallint';
175
                    $precision = 5;
176
                    $scale = 0;
177
                } elseif ($tableColumn['data_precision'] == 1 && $tableColumn['data_scale'] == 0) {
178
                    $precision = 1;
179
                    $scale = 0;
180
                    $type = 'boolean';
181
                } elseif ($tableColumn['data_scale'] > 0) {
182
                    $precision = $tableColumn['data_precision'];
183
                    $scale = $tableColumn['data_scale'];
184
                    $type = 'decimal';
185
                }
186
                $length = null;
187
                break;
188
            case 'pls_integer':
189
            case 'binary_integer':
190
                $length = null;
191
                break;
192
            case 'varchar':
193
            case 'varchar2':
194
            case 'nvarchar2':
195
                $length = $tableColumn['char_length'];
196
                $fixed = false;
197
                break;
198
            case 'char':
199
            case 'nchar':
200
                $length = $tableColumn['char_length'];
201
                $fixed = true;
202
                break;
203
            case 'date':
204
            case 'timestamp':
205
                $length = null;
206
                break;
207
            case 'float':
208
            case 'binary_float':
209
            case 'binary_double':
210
                $precision = $tableColumn['data_precision'];
211
                $scale = $tableColumn['data_scale'];
212
                $length = null;
213
                break;
214
            case 'clob':
215
            case 'nclob':
216
                $length = null;
217
                break;
218
            case 'blob':
219
            case 'raw':
220
            case 'long raw':
221
            case 'bfile':
222
                $length = null;
223
                break;
224
            case 'rowid':
225
            case 'urowid':
226
            default:
227
                $length = null;
228
        }
229
230
        $options = [
231
            'notnull'    => (bool) ($tableColumn['nullable'] === 'N'),
232
            'fixed'      => (bool) $fixed,
233
            'unsigned'   => (bool) $unsigned,
234
            'default'    => $tableColumn['data_default'],
235
            'length'     => $length,
236
            'precision'  => $precision,
237
            'scale'      => $scale,
238
            'comment'    => isset($tableColumn['comments']) && '' !== $tableColumn['comments']
239
                ? $tableColumn['comments']
240
                : null,
241
        ];
242
243
        return new Column($this->getQuotedIdentifierName($tableColumn['column_name']), Type::getType($type), $options);
244
    }
245
246
    /**
247
     * {@inheritdoc}
248
     */
249
    protected function _getPortableTableForeignKeysList($tableForeignKeys)
250
    {
251
        $list = [];
252
        foreach ($tableForeignKeys as $value) {
253
            $value = \array_change_key_case($value, CASE_LOWER);
254
            if (!isset($list[$value['constraint_name']])) {
255
                if ($value['delete_rule'] == "NO ACTION") {
256
                    $value['delete_rule'] = null;
257
                }
258
259
                $list[$value['constraint_name']] = [
260
                    'name' => $this->getQuotedIdentifierName($value['constraint_name']),
261
                    'local' => [],
262
                    'foreign' => [],
263
                    'foreignTable' => $value['references_table'],
264
                    'onDelete' => $value['delete_rule'],
265
                ];
266
            }
267
268
            $localColumn = $this->getQuotedIdentifierName($value['local_column']);
269
            $foreignColumn = $this->getQuotedIdentifierName($value['foreign_column']);
270
271
            $list[$value['constraint_name']]['local'][$value['position']] = $localColumn;
272
            $list[$value['constraint_name']]['foreign'][$value['position']] = $foreignColumn;
273
        }
274
275
        $result = [];
276
        foreach ($list as $constraint) {
277
            $result[] = new ForeignKeyConstraint(
278
                array_values($constraint['local']), $this->getQuotedIdentifierName($constraint['foreignTable']),
279
                array_values($constraint['foreign']), $this->getQuotedIdentifierName($constraint['name']),
280
                ['onDelete' => $constraint['onDelete']]
281
            );
282
        }
283
284
        return $result;
285
    }
286
287
    /**
288
     * {@inheritdoc}
289
     */
290
    protected function _getPortableSequenceDefinition($sequence)
291
    {
292
        $sequence = \array_change_key_case($sequence, CASE_LOWER);
293
294
        return new Sequence(
295
            $this->getQuotedIdentifierName($sequence['sequence_name']),
296
            $sequence['increment_by'],
297
            $sequence['min_value']
298
        );
299
    }
300
301
    /**
302
     * {@inheritdoc}
303
     */
304
    protected function _getPortableFunctionDefinition($function)
305
    {
306
        $function = \array_change_key_case($function, CASE_LOWER);
307
308
        return $function['name'];
309
    }
310
311
    /**
312
     * {@inheritdoc}
313
     */
314
    protected function _getPortableDatabaseDefinition($database)
315
    {
316
        $database = \array_change_key_case($database, CASE_LOWER);
317
318
        return $database['username'];
319
    }
320
321
    /**
322
     * {@inheritdoc}
323
     */
324
    public function createDatabase($database = null)
325
    {
326
        if (is_null($database)) {
327
            $database = $this->_conn->getDatabase();
328
        }
329
330
        $params = $this->_conn->getParams();
331
        $username   = $database;
332
        $password   = $params['password'];
333
334
        $query  = 'CREATE USER ' . $username . ' IDENTIFIED BY ' . $password;
335
        $this->_conn->executeUpdate($query);
336
337
        $query = 'GRANT DBA TO ' . $username;
338
        $this->_conn->executeUpdate($query);
339
340
        return true;
341
    }
342
343
    /**
344
     * @param string $table
345
     *
346
     * @return boolean
347
     */
348
    public function dropAutoincrement($table)
349
    {
350
        $sql = $this->_platform->getDropAutoincrementSql($table);
0 ignored issues
show
Bug introduced by
The method getDropAutoincrementSql() does not exist on Doctrine\DBAL\Platforms\AbstractPlatform. It seems like you code against a sub-type of Doctrine\DBAL\Platforms\AbstractPlatform such as Doctrine\DBAL\Platforms\OraclePlatform. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

350
        /** @scrutinizer ignore-call */ 
351
        $sql = $this->_platform->getDropAutoincrementSql($table);
Loading history...
351
        foreach ($sql as $query) {
352
            $this->_conn->executeUpdate($query);
353
        }
354
355
        return true;
356
    }
357
358
    /**
359
     * {@inheritdoc}
360
     */
361
    public function dropTable($name)
362
    {
363
        $this->tryMethod('dropAutoincrement', $name);
364
365
        parent::dropTable($name);
366
    }
367
368
    /**
369
     * Returns the quoted representation of the given identifier name.
370
     *
371
     * Quotes non-uppercase identifiers explicitly to preserve case
372
     * and thus make references to the particular identifier work.
373
     *
374
     * @param string $identifier The identifier to quote.
375
     *
376
     * @return string The quoted identifier.
377
     */
378
    private function getQuotedIdentifierName($identifier)
379
    {
380
        if (preg_match('/[a-z]/', $identifier)) {
381
            return $this->_platform->quoteIdentifier($identifier);
382
        }
383
384
        return $identifier;
385
    }
386
387
    /**
388
     * Kills sessions connected with the given user.
389
     *
390
     * This is useful to force DROP USER operations which could fail because of active user sessions.
391
     *
392
     * @param string $user The name of the user to kill sessions for.
393
     *
394
     * @return void
395
     */
396
    private function killUserSessions($user)
397
    {
398
        $sql = <<<SQL
399
SELECT
400
    s.sid,
401
    s.serial#
402
FROM
403
    gv\$session s,
404
    gv\$process p
405
WHERE
406
    s.username = ?
407
    AND p.addr(+) = s.paddr
408
SQL;
409
410
        $activeUserSessions = $this->_conn->fetchAll($sql, [strtoupper($user)]);
411
412
        foreach ($activeUserSessions as $activeUserSession) {
413
            $activeUserSession = array_change_key_case($activeUserSession, \CASE_LOWER);
414
415
            $this->_execSql(
416
                sprintf(
417
                    "ALTER SYSTEM KILL SESSION '%s, %s' IMMEDIATE",
418
                    $activeUserSession['sid'],
419
                    $activeUserSession['serial#']
420
                )
421
            );
422
        }
423
    }
424
}
425