Passed
Push — develop ( cd2c29...4f7ba8 )
by nguereza
02:28
created

Oracle::quoteIdentifier()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 17
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 9
c 1
b 0
f 0
dl 0
loc 17
rs 9.9666
cc 4
nc 4
nop 1
1
<?php
2
3
/**
4
 * Platine Database
5
 *
6
 * Platine Database is the abstraction layer using PDO with support of query and schema builder
7
 *
8
 * This content is released under the MIT License (MIT)
9
 *
10
 * Copyright (c) 2020 Platine Database
11
 *
12
 * Permission is hereby granted, free of charge, to any person obtaining a copy
13
 * of this software and associated documentation files (the "Software"), to deal
14
 * in the Software without restriction, including without limitation the rights
15
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
 * copies of the Software, and to permit persons to whom the Software is
17
 * furnished to do so, subject to the following conditions:
18
 *
19
 * The above copyright notice and this permission notice shall be included in all
20
 * copies or substantial portions of the Software.
21
 *
22
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
 * SOFTWARE.
29
 */
30
31
/**
32
 *  @file Oracle.php
33
 *
34
 *  The Oracle Driver class
35
 *
36
 *  @package    Platine\Database\Driver
37
 *  @author Platine Developers Team
38
 *  @copyright  Copyright (c) 2020
39
 *  @license    http://opensource.org/licenses/MIT  MIT License
40
 *  @link   http://www.iacademy.cf
41
 *  @version 1.0.0
42
 *  @filesource
43
 */
44
45
declare(strict_types=1);
46
47
namespace Platine\Database\Driver;
48
49
use Platine\Database\Query\Expression;
50
use Platine\Database\Query\QueryStatement;
51
use Platine\Database\Schema\AlterTable;
52
use Platine\Database\Schema\BaseColumn;
53
54
/**
55
 * Class Oracle
56
 * @package Platine\Database\Driver
57
 */
58
class Oracle extends Driver
59
{
60
    /**
61
     * @inheritDoc
62
     */
63
    protected array $modifiers = [
64
        'nullable',
65
        'default',
66
        'autoincrement',
67
        'description'
68
    ];
69
70
    /**
71
     * @inheritDoc
72
     */
73
    protected string $autoincrement = 'GENERATED BY DEFAULT ON NULL AS IDENTITY';
74
75
    /**
76
     * @inheritDoc
77
     */
78
    public function select(QueryStatement $select): string
79
    {
80
        $limit = $select->getLimit();
81
        if ($limit <= 0) {
82
            return parent::select($select);
83
        }
84
85
        $sql = $select->hasDistinct() ? 'SELECT DISTINCT ' : 'SELECT ';
86
        $sql .= $this->getColumnList($select->getColumns());
87
        $sql .= ' FROM ';
88
        $sql .= $this->getTableList($select->getTables());
89
        $sql .= $this->getJoins($select->getJoins());
90
        $sql .= $this->getWheres($select->getWheres());
91
        $sql .= $this->getGroupBy($select->getGroupBy());
92
        $sql .= $this->getHaving($select->getHaving());
93
        $sql .= $this->getOrders($select->getOrder());
94
95
        $offset = $select->getOffset();
96
        if ($offset < 0) {
97
            return sprintf(
98
                'SELECT * FROM (%s) A1 WHERE ROWNUM <= %s',
99
                $sql,
100
                $limit
101
            );
102
        }
103
        $limit += $offset;
104
        $offset++;
105
        return sprintf(
106
            'SELECT * FROM (SELECT A1.*, ROWNUM AS P_ROWNUM FROM (%s) A1 '
107
                . 'WHERE ROWNUM <= %d) WHERE P_ROWNUM >= %d',
108
            $sql,
109
            $limit,
110
            $offset
111
        );
112
    }
113
114
    /**
115
     * @inheritDoc
116
     */
117
    public function getDatabaseName(): array
118
    {
119
        return [
120
            'sql' => 'SELECT user FROM dual',
121
            'params' => []
122
        ];
123
    }
124
125
    /**
126
     * @inheritDoc
127
     */
128
    public function getTables(string $database): array
129
    {
130
        $sql = sprintf(
131
            'SELECT %s FROM %s WHERE owner = ? '
132
                . ' ORDER BY %s ASC',
133
            $this->quoteIdentifier('table_name'),
134
            $this->quoteIdentifier('all_tables'),
135
            $this->quoteIdentifier('table_name'),
136
        );
137
138
        return [
139
            'sql' => $sql,
140
            'params' => [$database]
141
        ];
142
    }
143
144
    /**
145
     * @inheritDoc
146
     */
147
    public function getViews(string $database): array
148
    {
149
        $sql = sprintf(
150
            'SELECT %s FROM %s WHERE owner = ? '
151
                . ' ORDER BY %s ASC',
152
            $this->quoteIdentifier('view_name'),
153
            $this->quoteIdentifier('all_views'),
154
            $this->quoteIdentifier('view_name'),
155
        );
156
157
        return [
158
            'sql' => $sql,
159
            'params' => [$database]
160
        ];
161
    }
162
163
    /**
164
     * @inheritDoc
165
     */
166
    public function getColumns(string $database, string $table): array
167
    {
168
        $sql = sprintf(
169
            'SELECT %s AS %s, %s AS %s FROM %s WHERE LOWER(%s) = ? '
170
                . 'AND LOWER(%s) = ? ORDER BY %s ASC',
171
            $this->quoteIdentifier('column_name'),
172
            $this->quoteIdentifier('name'),
173
            $this->quoteIdentifier('data_type'),
174
            $this->quoteIdentifier('type'),
175
            $this->quoteIdentifier('all_tab_columns'),
176
            $this->quoteIdentifier('owner'),
177
            $this->quoteIdentifier('table_name'),
178
            $this->quoteIdentifier('column_id'),
179
        );
180
181
        return [
182
            'sql' => $sql,
183
            'params' => [$database, $table]
184
        ];
185
    }
186
187
    /**
188
     * @inheritDoc
189
     */
190
    public function getViewColumns(string $database, string $view): array
191
    {
192
        $sql = sprintf(
193
            'SELECT %s AS %s, %s AS %s FROM %s WHERE LOWER(%s) = ? '
194
                . 'AND LOWER(%s) = ? ORDER BY %s ASC',
195
            $this->quoteIdentifier('column_name'),
196
            $this->quoteIdentifier('name'),
197
            $this->quoteIdentifier('data_type'),
198
            $this->quoteIdentifier('type'),
199
            $this->quoteIdentifier('all_tab_columns'),
200
            $this->quoteIdentifier('owner'),
201
            $this->quoteIdentifier('table_name'),
202
            $this->quoteIdentifier('column_id'),
203
        );
204
205
        return [
206
            'sql' => $sql,
207
            'params' => [$database, $view]
208
        ];
209
    }
210
211
    /**
212
     * @inheritDoc
213
     */
214
    protected function quoteIdentifier($value): string
215
    {
216
        if ($value instanceof Expression) {
217
            return $this->getExpressions($value->getExpressions());
218
        }
219
220
        $identifiers = [];
221
222
        foreach (explode('.', $value) as $segment) {
223
            if ($segment === '*') {
224
                $identifiers[] = $segment;
225
            } else {
226
                $identifiers[] = sprintf($this->identifier, strtoupper($segment));
227
            }
228
        }
229
230
        return implode('.', $identifiers);
231
    }
232
233
    /**
234
     * @inheritdoc
235
     */
236
    protected function getTypeInteger(BaseColumn $column): string
237
    {
238
        $type = 'NUMBER(10)';
239
        switch ($column->get('size', 'normal')) {
240
            case 'tiny':
241
                $type = 'NUMBER(3)';
242
                break;
243
            case 'small':
244
                $type = 'NUMBER(5)';
245
                break;
246
            case 'medium':
247
                $type = 'NUMBER(7)';
248
                break;
249
            case 'big':
250
                $type = 'NUMBER(19)';
251
                break;
252
        }
253
        return $type;
254
    }
255
256
    /**
257
     * @inheritdoc
258
     */
259
    protected function getTypeDouble(BaseColumn $column): string
260
    {
261
        return 'FLOAT(24)';
262
    }
263
264
    /**
265
     * @inheritdoc
266
     */
267
    protected function getTypeDecimal(BaseColumn $column): string
268
    {
269
        $type = 'NUMBER(10)';
270
        $length = $column->get('length');
271
        $precision = $column->get('precision');
272
        if ($length !== null) {
273
            if ($precision === null) {
274
                $type = 'NUMBER(' . $this->value($length) . ')';
275
            } else {
276
                $type = 'NUMBER(' . $this->value($length) . ', '
277
                        . $this->value($precision) . ')';
278
            }
279
        }
280
281
        return $type;
282
    }
283
284
    /**
285
     * @inheritdoc
286
     */
287
    protected function getTypeEnum(BaseColumn $column): string
288
    {
289
        $type = 'ENUM';
290
        $values = $column->get('values');
291
292
        if (!empty($values)) {
293
            $values = array_map([$this, 'value'], $values);
294
            $type = 'ENUM(' . implode(',', $values) . ')';
295
        }
296
297
        return $type;
298
    }
299
300
    /**
301
     * @inheritdoc
302
     */
303
    protected function getTypeBoolean(BaseColumn $column): string
304
    {
305
        return 'NUMBER(1)';
306
    }
307
308
    /**
309
     * @inheritdoc
310
     */
311
    protected function getTypeText(BaseColumn $column): string
312
    {
313
        $type = 'CLOB';
314
        switch ($column->get('size', 'normal')) {
315
            case 'tiny':
316
            case 'small':
317
                $type = 'VARCHAR2(2000)';
318
                break;
319
            case 'medium':
320
            case 'big':
321
                $type = 'CLOB';
322
                break;
323
        }
324
        return $type;
325
    }
326
327
    /**
328
     * @inheritdoc
329
     */
330
    protected function getTypeString(BaseColumn $column): string
331
    {
332
        return 'VARCHAR2(' . $this->value($column->get('length', 255)) . ')';
333
    }
334
335
    /**
336
     * @inheritdoc
337
     */
338
    protected function getTypeTime(BaseColumn $column): string
339
    {
340
        return 'DATE';
341
    }
342
343
    /**
344
     * @inheritdoc
345
     */
346
    protected function getTypeDatetime(BaseColumn $column): string
347
    {
348
        return 'DATE';
349
    }
350
351
    /**
352
     * @inheritdoc
353
     */
354
    protected function getTypeBinary(BaseColumn $column): string
355
    {
356
        $type = 'BLOB';
357
        switch ($column->get('size', 'normal')) {
358
            case 'tiny':
359
            case 'small':
360
                $type = 'RAW(2000)';
361
                break;
362
            case 'medium':
363
            case 'big':
364
                $type = 'BLOB';
365
                break;
366
        }
367
        return $type;
368
    }
369
370
    /**
371
     * @inheritdoc
372
     */
373
    protected function getModifyColumn(AlterTable $schema, $data): string
374
    {
375
        return sprintf(
376
            'ALTER TABLE %s MODIFY %s',
377
            $this->quoteIdentifier($schema->getTableName()),
378
            $this->getSchemaColumns([$data])
379
        );
380
    }
381
382
    /**
383
     * @inheritdoc
384
     */
385
    protected function getAddColumn(AlterTable $schema, $data): string
386
    {
387
        return sprintf(
388
            'ALTER TABLE %s ADD %s',
389
            $this->quoteIdentifier($schema->getTableName()),
390
            $this->getSchemaColumns([$data])
391
        );
392
    }
393
394
    /**
395
     * @inheritdoc
396
     */
397
    protected function getSetDefaultValue(AlterTable $schema, $data): string
398
    {
399
        return sprintf(
400
            'ALTER TABLE %s MODIFY %s DEFAULT %s',
401
            $this->quoteIdentifier($schema->getTableName()),
402
            $this->quoteIdentifier($data['column']),
403
            $this->value($data['value'])
404
        );
405
    }
406
407
    /**
408
     * @inheritdoc
409
     */
410
    protected function getDropDefaultValue(AlterTable $schema, $data): string
411
    {
412
        return sprintf(
413
            'ALTER TABLE %s MODIFY %s DEFAULT NULL',
414
            $this->quoteIdentifier($schema->getTableName()),
415
            $this->quoteIdentifier($data)
416
        );
417
    }
418
}
419