SQLServer::select()   B
last analyzed

Complexity

Conditions 6
Paths 7

Size

Total Lines 48
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 36
c 1
b 0
f 0
dl 0
loc 48
rs 8.7217
cc 6
nc 7
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 SQLServer.php
33
 *
34
 *  The SQLServer 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   https://www.platine-php.com
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\QueryStatement;
50
use Platine\Database\Schema\AlterTable;
51
use Platine\Database\Schema\BaseColumn;
52
use Platine\Database\Schema\CreateTable;
53
54
/**
55
 * @class SQLServer
56
 * @package Platine\Database\Driver
57
 */
58
class SQLServer extends Driver
59
{
60
    /**
61
     * @inheritdoc
62
     * @var string
63
     */
64
    protected string $dateFormat = 'Y-m-d H:i:s.0000000';
65
66
    /**
67
     * @inheritdoc
68
     * @var string
69
     */
70
    protected string $identifier = '[%s]';
71
72
    /**
73
     * @inheritDoc
74
     */
75
    protected array $modifiers = [
76
        'nullable',
77
        'default',
78
        'autoincrement',
79
        'description'
80
    ];
81
82
    /**
83
     * @inheritDoc
84
     */
85
    protected string $autoincrement = 'IDENTITY';
86
87
    /**
88
     * @inheritDoc
89
     */
90
    public function select(QueryStatement $select): string
91
    {
92
        $limit = $select->getLimit();
93
        if ($limit <= 0) {
94
            return parent::select($select);
95
        }
96
        $offset = $select->getOffset();
97
98
        if ($offset < 0) {
99
            $sql = $select->hasDistinct() ? 'SELECT DISTINCT ' : 'SELECT ';
100
            $sql .= 'TOP ' . $limit . ' ';
101
            $sql .= $this->getColumnList($select->getColumns());
102
            $sql .= $this->getInto($select->getIntoTable());
103
            $sql .= ' FROM ';
104
            $sql .= $this->getTableList($select->getTables());
105
            $sql .= $this->getJoins($select->getJoins());
106
            $sql .= $this->getWheres($select->getWheres());
107
            $sql .= $this->getGroupBy($select->getGroupBy());
108
            $sql .= $this->getHaving($select->getHaving());
109
            $sql .= $this->getOrders($select->getOrder());
110
111
            return $sql;
112
        }
113
114
        $order = trim($this->getOrders($select->getOrder()));
115
116
        if (empty($order)) {
117
            $order = 'ORDER BY (SELECT 0)';
118
        }
119
120
        $sql = $select->hasDistinct() ? 'SELECT DISTINCT ' : 'SELECT ';
121
        $sql .= $this->getColumnList($select->getColumns());
122
        $sql .= ', ROW_NUMBER() OVER (' . $order . ') AS P_ROWNUM';
123
        $sql .= ' FROM ';
124
        $sql .= $this->getTableList($select->getTables());
125
        $sql .= $this->getJoins($select->getJoins());
126
        $sql .= $this->getWheres($select->getWheres());
127
        $sql .= $this->getGroupBy($select->getGroupBy());
128
        $sql .= $this->getHaving($select->getHaving());
129
130
        $limit += $offset;
131
        $offset++;
132
133
        return sprintf(
134
            'SELECT * FROM (%s) AS A1 WHERE P_ROWNUM BETWEEN %d AND %d',
135
            $sql,
136
            $offset,
137
            $limit
138
        );
139
    }
140
141
    /**
142
     * @inheritDoc
143
     */
144
    public function update(QueryStatement $update): string
145
    {
146
        $joins = $this->getJoins($update->getJoins());
147
        $tables = $update->getTables();
148
149
        if ($joins !== '') {
150
            $joins = ' FROM ' . $this->getTableList($tables) . ' ' . $joins;
151
            $tables = array_values($tables);
152
        }
153
        $sql = 'UPDATE ';
154
        $sql .= $this->getTableList($tables);
155
        $sql .= $this->getSetColumns($update->getColumns());
156
        $sql .= $joins;
157
        $sql .= $this->getWheres($update->getWheres());
158
159
        return $sql;
160
    }
161
162
    /**
163
     * @inheritdoc
164
     */
165
    public function renameTable(string $current, string $new): array
166
    {
167
        return [
168
            'sql' => 'sp_rename ' . $this->quoteIdentifier($current)
169
            . ', ' . $this->quoteIdentifier($new),
170
            'params' => []
171
        ];
172
    }
173
174
    /**
175
     * @inheritDoc
176
     */
177
    public function getDatabaseName(): array
178
    {
179
        return [
180
            'sql' => 'SELECT SCHEMA_NAME()',
181
            'params' => []
182
        ];
183
    }
184
185
    /**
186
     * @inheritDoc
187
     */
188
    public function getColumns(string $database, string $table): array
189
    {
190
        $sql = sprintf(
191
            'SELECT %s AS %s, %s AS %s FROM %s.%s WHERE %s = ? '
192
                . 'AND %s = ? ORDER BY %s ASC',
193
            $this->quoteIdentifier('column_name'),
194
            $this->quoteIdentifier('name'),
195
            $this->quoteIdentifier('data_type'),
196
            $this->quoteIdentifier('type'),
197
            $this->quoteIdentifier('information_schema'),
198
            $this->quoteIdentifier('columns'),
199
            $this->quoteIdentifier('table_schema'),
200
            $this->quoteIdentifier('table_name'),
201
            $this->quoteIdentifier('ordinal_position'),
202
        );
203
204
        return [
205
            'sql' => $sql,
206
            'params' => [$database, $table]
207
        ];
208
    }
209
210
    /**
211
     * @inheritdoc
212
     */
213
    protected function getTypeInteger(BaseColumn $column): string
214
    {
215
        $type = 'INTEGER';
216
        switch ($column->get('size', 'normal')) {
217
            case 'tiny':
218
                $type = 'TINYINT';
219
                break;
220
            case 'small':
221
                $type = 'SMALLINT';
222
                break;
223
            case 'medium':
224
                $type = 'INTEGER';
225
                break;
226
            case 'big':
227
                $type = 'BIGINT';
228
                break;
229
        }
230
        return $type;
231
    }
232
233
    /**
234
     * @inheritdoc
235
     */
236
    protected function getTypeDecimal(BaseColumn $column): string
237
    {
238
        $type = 'DECIMAL';
239
        $length = $column->get('length');
240
        $precision = $column->get('precision');
241
        if ($length !== null) {
242
            if ($precision === null) {
243
                $type = 'DECIMAL(' . $this->value($length) . ')';
244
            } else {
245
                $type = 'DECIMAL(' . $this->value($length) . ', '
246
                        . $this->value($precision) . ')';
247
            }
248
        }
249
250
        return $type;
251
    }
252
253
    /**
254
     * @inheritdoc
255
     */
256
    protected function getTypeEnum(BaseColumn $column): string
257
    {
258
        // TODO
259
260
        return '';
261
    }
262
263
    /**
264
     * @inheritdoc
265
     */
266
    protected function getTypeBoolean(BaseColumn $column): string
267
    {
268
        return 'BIT';
269
    }
270
271
    /**
272
     * @inheritdoc
273
     */
274
    protected function getTypeString(BaseColumn $column): string
275
    {
276
        return 'NVARCHAR(' . $this->value($column->get('length', 255)) . ')';
277
    }
278
279
    /**
280
     * @inheritdoc
281
     */
282
    protected function getTypeFixed(BaseColumn $column): string
283
    {
284
        return 'NCHAR(' . $this->value($column->get('length', 255)) . ')';
285
    }
286
287
    /**
288
     * @inheritdoc
289
     */
290
    protected function getTypeText(BaseColumn $column): string
291
    {
292
        return 'NVARCHAR(max)';
293
    }
294
295
    /**
296
     * @inheritdoc
297
     */
298
    protected function getTypeBinary(BaseColumn $column): string
299
    {
300
        return 'VARBINARY(max)';
301
    }
302
303
    /**
304
     * @inheritdoc
305
     */
306
    protected function getTypeTimestamp(BaseColumn $column): string
307
    {
308
        return 'DATETIME';
309
    }
310
311
    /**
312
     * @inheritdoc
313
     */
314
    protected function getRenameColumn(AlterTable $schema, mixed $data): string
315
    {
316
        $column = $data['column'];
317
        return sprintf(
318
            'sp_rename %s.%s, %s, COLUMN',
319
            $this->quoteIdentifier($schema->getTableName()),
320
            $this->quoteIdentifier($data['from']),
321
            $this->quoteIdentifier($column->getName())
322
        );
323
    }
324
325
    /**
326
     * @inheritdoc
327
     */
328
    protected function getEngine(CreateTable $schema): string
329
    {
330
        return '';
331
    }
332
}
333