1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* @author Morris Jobke <[email protected]> |
4
|
|
|
* @author Robin Appelman <[email protected]> |
5
|
|
|
* @author Thomas Müller <[email protected]> |
6
|
|
|
* |
7
|
|
|
* @copyright Copyright (c) 2017, ownCloud GmbH |
8
|
|
|
* @license AGPL-3.0 |
9
|
|
|
* |
10
|
|
|
* This code is free software: you can redistribute it and/or modify |
11
|
|
|
* it under the terms of the GNU Affero General Public License, version 3, |
12
|
|
|
* as published by the Free Software Foundation. |
13
|
|
|
* |
14
|
|
|
* This program is distributed in the hope that it will be useful, |
15
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
16
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17
|
|
|
* GNU Affero General Public License for more details. |
18
|
|
|
* |
19
|
|
|
* You should have received a copy of the GNU Affero General Public License, version 3, |
20
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/> |
21
|
|
|
* |
22
|
|
|
*/ |
23
|
|
|
|
24
|
|
|
namespace OC\DB; |
25
|
|
|
|
26
|
|
|
use Doctrine\DBAL\Schema\Column; |
27
|
|
|
use Doctrine\DBAL\Schema\ColumnDiff; |
28
|
|
|
use Doctrine\DBAL\Schema\Index; |
29
|
|
|
use Doctrine\DBAL\Schema\Schema; |
30
|
|
|
use Doctrine\DBAL\Schema\Table; |
31
|
|
|
use Doctrine\DBAL\Schema\ForeignKeyConstraint; |
32
|
|
|
|
33
|
|
|
class OracleMigrator extends NoCheckMigrator { |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* Quote a column's name but changing the name requires recreating |
37
|
|
|
* the column instance and copying over all properties. |
38
|
|
|
* |
39
|
|
|
* @param Column $column old column |
40
|
|
|
* @return Column new column instance with new name |
41
|
|
|
*/ |
42
|
|
|
protected function quoteColumn($column) { |
43
|
|
|
$newColumn = new Column( |
44
|
|
|
$this->connection->quoteIdentifier($column->getName()), |
45
|
|
|
$column->getType() |
46
|
|
|
); |
47
|
|
|
$newColumn->setAutoincrement($column->getAutoincrement()); |
48
|
|
|
$newColumn->setColumnDefinition($column->getColumnDefinition()); |
49
|
|
|
$newColumn->setComment($column->getComment()); |
50
|
|
|
$newColumn->setDefault($column->getDefault()); |
51
|
|
|
$newColumn->setFixed($column->getFixed()); |
52
|
|
|
$newColumn->setLength($column->getLength()); |
53
|
|
|
$newColumn->setNotnull($column->getNotnull()); |
54
|
|
|
$newColumn->setPrecision($column->getPrecision()); |
55
|
|
|
$newColumn->setScale($column->getScale()); |
56
|
|
|
$newColumn->setUnsigned($column->getUnsigned()); |
57
|
|
|
$newColumn->setPlatformOptions($column->getPlatformOptions()); |
58
|
|
|
$newColumn->setCustomSchemaOptions($column->getPlatformOptions()); |
59
|
|
|
return $newColumn; |
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* Quote an index's name but changing the name requires recreating |
64
|
|
|
* the index instance and copying over all properties. |
65
|
|
|
* |
66
|
|
|
* @param Index $index old index |
67
|
|
|
* @return Index new index instance with new name |
68
|
|
|
*/ |
69
|
|
|
protected function quoteIndex($index) { |
70
|
|
|
return new Index( |
71
|
|
|
//TODO migrate existing uppercase indexes, then $this->connection->quoteIdentifier($index->getName()), |
72
|
|
|
$index->getName(), |
73
|
|
|
array_map(function($columnName) { |
74
|
|
|
return $this->connection->quoteIdentifier($columnName); |
75
|
|
|
}, $index->getColumns()), |
76
|
|
|
$index->isUnique(), |
77
|
|
|
$index->isPrimary(), |
78
|
|
|
$index->getFlags(), |
79
|
|
|
$index->getOptions() |
80
|
|
|
); |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* Quote an ForeignKeyConstraint's name but changing the name requires recreating |
85
|
|
|
* the ForeignKeyConstraint instance and copying over all properties. |
86
|
|
|
* |
87
|
|
|
* @param ForeignKeyConstraint $fkc old fkc |
88
|
|
|
* @return ForeignKeyConstraint new fkc instance with new name |
89
|
|
|
*/ |
90
|
|
|
protected function quoteForeignKeyConstraint($fkc) { |
91
|
|
|
return new ForeignKeyConstraint( |
92
|
|
|
array_map(function($columnName) { |
93
|
|
|
return $this->connection->quoteIdentifier($columnName); |
94
|
|
|
}, $fkc->getLocalColumns()), |
95
|
|
|
$this->connection->quoteIdentifier($fkc->getForeignTableName()), |
96
|
|
|
array_map(function($columnName) { |
97
|
|
|
return $this->connection->quoteIdentifier($columnName); |
98
|
|
|
}, $fkc->getForeignColumns()), |
99
|
|
|
$fkc->getName(), |
100
|
|
|
$fkc->getOptions() |
101
|
|
|
); |
102
|
|
|
} |
103
|
|
|
|
104
|
|
|
/** |
105
|
|
|
* @param Schema $targetSchema |
106
|
|
|
* @param \Doctrine\DBAL\Connection $connection |
107
|
|
|
* @return \Doctrine\DBAL\Schema\SchemaDiff |
108
|
|
|
*/ |
109
|
|
|
protected function getDiff(Schema $targetSchema, \Doctrine\DBAL\Connection $connection) { |
110
|
|
|
$schemaDiff = parent::getDiff($targetSchema, $connection); |
111
|
|
|
|
112
|
|
|
// oracle forces us to quote the identifiers |
113
|
|
|
$schemaDiff->newTables = array_map(function(Table $table) { |
114
|
|
|
return new Table( |
115
|
|
|
$this->connection->quoteIdentifier($table->getName()), |
116
|
|
|
array_map(function(Column $column) { |
117
|
|
|
return $this->quoteColumn($column); |
118
|
|
|
}, $table->getColumns()), |
119
|
|
|
array_map(function(Index $index) { |
120
|
|
|
return $this->quoteIndex($index); |
121
|
|
|
}, $table->getIndexes()), |
122
|
|
|
array_map(function(ForeignKeyConstraint $fck) { |
123
|
|
|
return $this->quoteForeignKeyConstraint($fck); |
124
|
|
|
}, $table->getForeignKeys()), |
125
|
|
|
0, |
126
|
|
|
$table->getOptions() |
127
|
|
|
); |
128
|
|
|
}, $schemaDiff->newTables); |
129
|
|
|
|
130
|
|
|
$schemaDiff->removedTables = array_map(function(Table $table) { |
131
|
|
|
return new Table( |
132
|
|
|
$this->connection->quoteIdentifier($table->getName()), |
133
|
|
|
$table->getColumns(), |
134
|
|
|
$table->getIndexes(), |
135
|
|
|
$table->getForeignKeys(), |
136
|
|
|
0, |
137
|
|
|
$table->getOptions() |
138
|
|
|
); |
139
|
|
|
}, $schemaDiff->removedTables); |
140
|
|
|
|
141
|
|
|
foreach ($schemaDiff->changedTables as $tableDiff) { |
142
|
|
|
$tableDiff->name = $this->connection->quoteIdentifier($tableDiff->name); |
143
|
|
|
|
144
|
|
|
$tableDiff->addedColumns = array_map(function(Column $column) { |
145
|
|
|
return $this->quoteColumn($column); |
146
|
|
|
}, $tableDiff->addedColumns); |
147
|
|
|
|
148
|
|
|
foreach ($tableDiff->changedColumns as $column) { |
149
|
|
|
$column->oldColumnName = $this->connection->quoteIdentifier($column->oldColumnName); |
150
|
|
|
// auto increment is not relevant for oracle and can anyhow not be applied on change |
151
|
|
|
$column->changedProperties = array_diff($column->changedProperties, ['autoincrement', 'unsigned']); |
152
|
|
|
} |
153
|
|
|
// remove columns that no longer have changed (because autoincrement and unsigned are not supported) |
154
|
|
|
$tableDiff->changedColumns = array_filter($tableDiff->changedColumns, function (ColumnDiff $column) { |
155
|
|
|
return count($column->changedProperties) > 0; |
156
|
|
|
}); |
157
|
|
|
|
158
|
|
|
$tableDiff->removedColumns = array_map(function(Column $column) { |
159
|
|
|
return $this->quoteColumn($column); |
160
|
|
|
}, $tableDiff->removedColumns); |
161
|
|
|
|
162
|
|
|
$tableDiff->renamedColumns = array_map(function(Column $column) { |
163
|
|
|
return $this->quoteColumn($column); |
164
|
|
|
}, $tableDiff->renamedColumns); |
165
|
|
|
|
166
|
|
|
$tableDiff->addedIndexes = array_map(function(Index $index) { |
167
|
|
|
return $this->quoteIndex($index); |
168
|
|
|
}, $tableDiff->addedIndexes); |
169
|
|
|
|
170
|
|
|
$tableDiff->changedIndexes = array_map(function(Index $index) { |
171
|
|
|
return $this->quoteIndex($index); |
172
|
|
|
}, $tableDiff->changedIndexes); |
173
|
|
|
|
174
|
|
|
$tableDiff->removedIndexes = array_map(function(Index $index) { |
175
|
|
|
return $this->quoteIndex($index); |
176
|
|
|
}, $tableDiff->removedIndexes); |
177
|
|
|
|
178
|
|
|
$tableDiff->renamedIndexes = array_map(function(Index $index) { |
179
|
|
|
return $this->quoteIndex($index); |
180
|
|
|
}, $tableDiff->renamedIndexes); |
181
|
|
|
|
182
|
|
|
$tableDiff->addedForeignKeys = array_map(function(ForeignKeyConstraint $fkc) { |
183
|
|
|
return $this->quoteForeignKeyConstraint($fkc); |
184
|
|
|
}, $tableDiff->addedForeignKeys); |
185
|
|
|
|
186
|
|
|
$tableDiff->changedForeignKeys = array_map(function(ForeignKeyConstraint $fkc) { |
187
|
|
|
return $this->quoteForeignKeyConstraint($fkc); |
188
|
|
|
}, $tableDiff->changedForeignKeys); |
189
|
|
|
|
190
|
|
|
$tableDiff->removedForeignKeys = array_map(function(ForeignKeyConstraint $fkc) { |
191
|
|
|
return $this->quoteForeignKeyConstraint($fkc); |
192
|
|
|
}, $tableDiff->removedForeignKeys); |
193
|
|
|
} |
194
|
|
|
|
195
|
|
|
return $schemaDiff; |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
/** |
199
|
|
|
* @param string $name |
200
|
|
|
* @return string |
201
|
|
|
*/ |
202
|
|
|
protected function generateTemporaryTableName($name) { |
203
|
|
|
return 'oc_' . uniqid(); |
204
|
|
|
} |
205
|
|
|
|
206
|
|
|
/** |
207
|
|
|
* @param $statement |
208
|
|
|
* @return string |
209
|
|
|
*/ |
210
|
|
|
protected function convertStatementToScript($statement) { |
211
|
|
|
if (substr($statement, -1) === ';') { |
212
|
|
|
return $statement . PHP_EOL . '/' . PHP_EOL; |
213
|
|
|
} |
214
|
|
|
$script = $statement . ';'; |
215
|
|
|
$script .= PHP_EOL; |
216
|
|
|
$script .= PHP_EOL; |
217
|
|
|
return $script; |
218
|
|
|
} |
219
|
|
|
|
220
|
|
|
protected function getFilterExpression() { |
221
|
|
|
return '/^"' . preg_quote($this->config->getSystemValue('dbtableprefix', 'oc_')) . '/'; |
222
|
|
|
} |
223
|
|
|
|
224
|
|
|
} |
225
|
|
|
|