1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* components |
4
|
|
|
* |
5
|
|
|
* @author Wolfy-J |
6
|
|
|
*/ |
7
|
|
|
namespace Spiral\Database\Drivers\SQLServer; |
8
|
|
|
|
9
|
|
|
use Spiral\Database\Drivers\SQLServer\Schemas\SQLServerColumn; |
10
|
|
|
use Spiral\Database\Entities\AbstractHandler; |
11
|
|
|
use Spiral\Database\Exceptions\SchemaException; |
12
|
|
|
use Spiral\Database\Schemas\Prototypes\AbstractColumn; |
13
|
|
|
use Spiral\Database\Schemas\Prototypes\AbstractIndex; |
14
|
|
|
use Spiral\Database\Schemas\Prototypes\AbstractTable; |
15
|
|
|
|
16
|
|
|
class SQLServerHandler extends AbstractHandler |
17
|
|
|
{ |
18
|
|
|
/** |
19
|
|
|
* {@inheritdoc} |
20
|
|
|
*/ |
21
|
|
|
public function renameTable(string $table, string $name) |
22
|
|
|
{ |
23
|
|
|
$this->run('sp_rename @objname = ?, @newname = ?', [$table, $name]); |
24
|
|
|
} |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* {@inheritdoc} |
28
|
|
|
*/ |
29
|
|
|
public function createColumn(AbstractTable $table, AbstractColumn $column) |
30
|
|
|
{ |
31
|
|
|
$this->run("ALTER TABLE {$this->identify($table)} ADD {$column->sqlStatement($this->driver)}"); |
32
|
|
|
} |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* Driver specific column alter command. |
36
|
|
|
* |
37
|
|
|
* @param AbstractTable $table |
38
|
|
|
* @param AbstractColumn $initial |
39
|
|
|
* @param AbstractColumn $column |
40
|
|
|
* |
41
|
|
|
* @throws SchemaException |
42
|
|
|
*/ |
43
|
|
|
public function alterColumn( |
44
|
|
|
AbstractTable $table, |
45
|
|
|
AbstractColumn $initial, |
46
|
|
|
AbstractColumn $column |
47
|
|
|
) { |
48
|
|
|
if (!$initial instanceof SQLServerColumn || !$column instanceof SQLServerColumn) { |
49
|
|
|
throw new SchemaException('SQlServer handler can work only with SQLServer columns.'); |
50
|
|
|
} |
51
|
|
|
|
52
|
|
|
//In SQLServer we have to drop ALL related indexes and foreign keys while |
53
|
|
|
//applying type change... yeah... |
54
|
|
|
|
55
|
|
|
$indexesBackup = []; |
56
|
|
|
$foreignBackup = []; |
57
|
|
|
foreach ($table->getIndexes() as $index) { |
58
|
|
|
if (in_array($column->getName(), $index->getColumns())) { |
59
|
|
|
$indexesBackup[] = $index; |
60
|
|
|
$this->dropIndex($table, $index); |
61
|
|
|
} |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
foreach ($table->getForeigns() as $foreign) { |
65
|
|
|
if ($column->getName() == $foreign->getColumn()) { |
66
|
|
|
$foreignBackup[] = $foreign; |
67
|
|
|
$this->dropForeign($table, $foreign); |
68
|
|
|
} |
69
|
|
|
} |
70
|
|
|
|
71
|
|
|
//Column will recreate needed constraints |
72
|
|
|
foreach ($column->getConstraints() as $constraint) { |
73
|
|
|
$this->dropConstrain($table, $constraint); |
74
|
|
|
} |
75
|
|
|
|
76
|
|
|
//Rename is separate operation |
77
|
|
|
if ($column->getName() != $initial->getName()) { |
78
|
|
|
$this->renameColumn($table, $initial, $column); |
79
|
|
|
|
80
|
|
|
//This call is required to correctly built set of alter operations |
81
|
|
|
$initial->setName($column->getName()); |
82
|
|
|
} |
83
|
|
|
|
84
|
|
|
foreach ($column->alterOperations($this->driver, $initial) as $operation) { |
85
|
|
|
$this->run("ALTER TABLE {$this->identify($table)} {$operation}"); |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
//Restoring indexes and foreign keys |
89
|
|
|
foreach ($indexesBackup as $index) { |
90
|
|
|
$this->createIndex($table, $index); |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
foreach ($foreignBackup as $foreign) { |
94
|
|
|
$this->createForeign($table, $foreign); |
95
|
|
|
} |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
/** |
99
|
|
|
* @param AbstractTable $table |
100
|
|
|
* @param AbstractColumn $initial |
101
|
|
|
* @param AbstractColumn $column |
102
|
|
|
*/ |
103
|
|
|
private function renameColumn( |
104
|
|
|
AbstractTable $table, |
105
|
|
|
AbstractColumn $initial, |
106
|
|
|
AbstractColumn $column |
107
|
|
|
) { |
108
|
|
|
$this->run("sp_rename ?, ?, 'COLUMN'", [ |
109
|
|
|
$table->getName() . '.' . $initial->getName(), |
110
|
|
|
$column->getName() |
111
|
|
|
]); |
112
|
|
|
} |
113
|
|
|
|
114
|
|
|
/** |
115
|
|
|
* Driver specific index remove (drop) command. |
116
|
|
|
* |
117
|
|
|
* @param AbstractTable $table |
118
|
|
|
* @param AbstractIndex $index |
119
|
|
|
* |
120
|
|
|
* @return self |
121
|
|
|
*/ |
122
|
|
|
public function dropIndex(AbstractTable $table, AbstractIndex $index) |
123
|
|
|
{ |
124
|
|
|
$this->run("DROP INDEX {$index->getName(true)} ON {$table->getName(true)}"); |
|
|
|
|
125
|
|
|
|
126
|
|
|
return $this; |
127
|
|
|
} |
128
|
|
|
} |
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.