Adds missing trailing whitespaces
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / system / package / PackageInstallationSQLParser.class.php
CommitLineData
08e8d4d0 1<?php
567b9611 2namespace wcf\system\package;
08e8d4d0
AE
3use wcf\data\package\Package;
4use wcf\system\database\util\SQLParser;
5use wcf\system\exception\SystemException;
6use wcf\system\WCF;
7
8/**
9 * PackageInstallationSQLParser extends SQLParser by testing and logging functions.
10 *
11 * @author Marcel Werk
9f959ced 12 * @copyright 2001-2012 WoltLab GmbH
08e8d4d0
AE
13 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
14 * @package com.woltlab.wcf
15 * @subpackage system.package
9f959ced 16 * @category Community Framework
08e8d4d0
AE
17 */
18class PackageInstallationSQLParser extends SQLParser {
19 /**
567b9611 20 * package object
9f959ced 21 * @var wcf\data\package\Package
08e8d4d0 22 */
567b9611 23 protected $package = null;
08e8d4d0
AE
24
25 /**
26 * activates the testing mode
08e8d4d0
AE
27 * @var boolean
28 */
29 protected $test = false;
30
31 /**
32 * installation type
08e8d4d0
AE
33 * @var string
34 */
35 protected $action = 'install';
36
37 /**
38 * list of existing database tables
08e8d4d0
AE
39 * @var array
40 */
41 protected $existingTables = array();
42
43 /**
44 * list of logged tables
08e8d4d0
AE
45 * @var array
46 */
47 protected $knownTables = array();
48
49 /**
50 * list of package ids
08e8d4d0
AE
51 * @var array
52 */
567b9611 53 protected $dependentPackageIDs = array();
08e8d4d0
AE
54
55 /**
56 * list of conflicted database tables
08e8d4d0
AE
57 * @var array
58 */
59 protected $conflicts = array();
60
61 /**
62 * list of created/deleted tables
08e8d4d0
AE
63 * @var array
64 */
65 protected $tableLog = array();
66
67 /**
68 * list of created/deleted columns
08e8d4d0
AE
69 * @var array
70 */
71 protected $columnLog = array();
72
73 /**
74 * list of created/deleted indices
08e8d4d0
AE
75 * @var array
76 */
77 protected $indexLog = array();
78
79 /**
80 * Creates a new PackageInstallationSQLParser object.
81 *
567b9611
MW
82 * @param string $queries
83 * @param wcf\data\package\Package $package
84 * @param string $action
08e8d4d0
AE
85 */
86 public function __construct($queries, Package $package, $action = 'install') {
87 $this->package = $package;
88 $this->action = $action;
89 parent::__construct($queries);
90 }
91
92 /**
93 * Performs a test of the given queries.
9f959ced 94 *
08e8d4d0
AE
95 * @return array conflicts
96 */
97 public function test() {
98 $this->conflicts = array();
9f959ced 99
08e8d4d0
AE
100 // get all existing tables from database
101 $this->existingTables = WCF::getDB()->getEditor()->getTableNames();
102
103 // get logged tables
104 $this->getKnownTables();
105
106 // get package ids of dependencies
567b9611 107 $this->getDependentPackageIDs();
08e8d4d0
AE
108
109 // enable testing mode
110 $this->test = true;
111
112 // run test
113 $this->execute();
114
115 // disable testing mode
116 $this->test = false;
117
118 // return conflicts
119 return $this->conflicts;
120 }
121
122 /**
123 * Logs executed sql queries
124 */
125 public function log() {
126 // tables
127 foreach ($this->tableLog as $logEntry) {
128 $sql = "DELETE FROM wcf".WCF_N."_package_installation_sql_log
129 WHERE sqlTable = ?";
130 $statement = WCF::getDB()->prepareStatement($sql);
131 $statement->execute(array($logEntry['tableName']));
132
133 if ($logEntry['action'] == 'insert') {
134 $sql = "INSERT INTO wcf".WCF_N."_package_installation_sql_log
135 (packageID, sqlTable)
136 VALUES (?, ?)";
137 $statement = WCF::getDB()->prepareStatement($sql);
138 $statement->execute(array(
139 $logEntry['packageID'],
140 $logEntry['tableName']
141 ));
142 }
143 }
144
145 // columns
15fa2802 146 if (!empty($this->columnLog)) {
08e8d4d0
AE
147 $sql = "DELETE FROM wcf".WCF_N."_package_installation_sql_log
148 WHERE sqlTable = ?
149 AND sqlColumn = ?";
150 $deleteStatement = WCF::getDB()->prepareStatement($sql);
151
152 $sql = "INSERT INTO wcf".WCF_N."_package_installation_sql_log
153 (packageID, sqlTable, sqlColumn)
154 VALUES (?, ?, ?)";
155 $insertStatement = WCF::getDB()->prepareStatement($sql);
156
157 foreach ($this->columnLog as $logEntry) {
158 $deleteStatement->execute(array(
159 $logEntry['tableName'],
160 $logEntry['columnName']
161 ));
162
163 if ($logEntry['action'] == 'insert') {
164 $insertStatement->execute(array(
165 $logEntry['packageID'],
166 $logEntry['tableName'],
167 $logEntry['columnName']
168 ));
169 }
170 }
171 }
172
173 // indices
15fa2802 174 if (!empty($this->indexLog)) {
08e8d4d0
AE
175 $sql = "DELETE FROM wcf".WCF_N."_package_installation_sql_log
176 WHERE sqlTable = ?
177 AND sqlIndex = ?";
178 $deleteStatement = WCF::getDB()->prepareStatement($sql);
179
180 $sql = "INSERT INTO wcf".WCF_N."_package_installation_sql_log
181 (packageID, sqlTable, sqlIndex)
182 VALUES (?, ?, ?)";
183 $insertStatement = WCF::getDB()->prepareStatement($sql);
184
185 foreach ($this->indexLog as $logEntry) {
186 $deleteStatement->execute(array(
187 $logEntry['tableName'],
188 $logEntry['indexName']
567b9611 189 ));
08e8d4d0
AE
190
191 if ($logEntry['action'] == 'insert') {
192 $insertStatement->execute(array(
193 $logEntry['packageID'],
194 $logEntry['tableName'],
195 $logEntry['indexName']
567b9611 196 ));
08e8d4d0
AE
197 }
198 }
199 }
200 }
201
202 /**
203 * Gets known sql tables and their owners from installation log.
204 */
205 protected function getKnownTables() {
206 $sql = "SELECT packageID, sqlTable
207 FROM wcf".WCF_N."_package_installation_sql_log
208 WHERE sqlColumn = ''
209 AND sqlIndex = ''";
210 $statement = WCF::getDB()->prepareStatement($sql);
211 $statement->execute();
212 while ($row = $statement->fetchArray()) {
213 $this->knownTables[$row['sqlTable']] = $row['packageID'];
214 }
215 }
216
217 /**
218 * Gets a list of dependent packages.
219 */
567b9611 220 protected function getDependentPackageIDs() {
08e8d4d0
AE
221 $sql = "SELECT dependency
222 FROM wcf".WCF_N."_package_dependency
223 WHERE packageID = ?";
224 $statement = WCF::getDB()->prepareStatement($sql);
225 $statement->execute(array($this->package->packageID));
08e8d4d0 226 while ($row = $statement->fetchArray()) {
567b9611 227 $this->dependentPackageIDs[] = $row['dependency'];
08e8d4d0
AE
228 }
229 }
230
231 /**
232 * Returns the owner of a specific database table column.
233 *
234 * @param string $tableName
235 * @param string $columnName
236 * @return integer package id
237 */
238 protected function getColumnOwnerID($tableName, $columnName) {
239 $sql = "SELECT packageID
240 FROM wcf".WCF_N."_package_installation_sql_log
241 WHERE sqlTable = ?
242 AND sqlColum = ?";
243 $statement = WCF::getDB()->prepareStatement($sql);
244 $statement->execute(array(
245 $tableName,
246 $columnName
247 ));
248 $row = $statement->fetchArray();
249 if (!empty($row['packageID'])) return $row['packageID'];
250 else if (isset($this->knownTables[$tableName])) return $this->knownTables[$tableName];
251 else return null;
252 }
253
254 /**
255 * Returns the owner of a specific database index.
256 *
257 * @param string $tableName
258 * @param string $indexName
259 * @return integer package id
260 */
261 protected function getIndexOwnerID($tableName, $indexName) {
262 $sql = "SELECT packageID
263 FROM wcf".WCF_N."_package_installation_sql_log
264 WHERE sqlTable = ?
265 AND sqlIndex = ?";
266 $statement = WCF::getDB()->prepareStatement($sql);
267 $statement->execute(array(
268 $tableName,
269 $indexName
270 ));
271 $row = $statement->fetchArray();
272 if (!empty($row['packageID'])) return $row['packageID'];
273 else if (isset($this->knownTables[$tableName])) return $this->knownTables[$tableName];
274 else return null;
275 }
276
277 /**
9f959ced 278 * @see wcf\system\database\util\SQLParser::executeCreateTableStatement()
08e8d4d0
AE
279 */
280 protected function executeCreateTableStatement($tableName, $columns, $indices = array()) {
281 if ($this->test) {
282 if (in_array($tableName, $this->existingTables)) {
283 if (isset($this->knownTables[$tableName])) {
284 if ($this->knownTables[$tableName] != $this->package->packageID) {
4fe0b42b 285 throw new SystemException("Can not recreate table '.$tableName.'. A package can only overwrite own tables.");
08e8d4d0
AE
286 }
287 }
288 else {
ffdf6f14
AE
289 if (!isset($this->conflicts['CREATE TABLE'])) $this->conflicts['CREATE TABLE'] = array();
290 $this->conflicts['CREATE TABLE'][] = $tableName;
08e8d4d0
AE
291 }
292 }
293 }
294 else {
295 // log
296 $this->tableLog[] = array('tableName' => $tableName, 'packageID' => $this->package->packageID, 'action' => 'insert');
297
298 // execute
299 parent::executeCreateTableStatement($tableName, $columns, $indices);
300 }
301 }
302
303 /**
9f959ced 304 * @see wcf\system\database\util\SQLParser::executeAddColumnStatement()
08e8d4d0
AE
305 */
306 protected function executeAddColumnStatement($tableName, $columnName, $columnData) {
307 if ($this->test) {
308 if (isset($this->knownTables[$tableName])) {
567b9611 309 if ($this->knownTables[$tableName] != $this->package->packageID && !in_array($this->knownTables[$tableName], $this->dependentPackageIDs)) {
4fe0b42b 310 throw new SystemException("Can not add column '".$columnName."' to table '.$tableName.'. An installion can only 'ADD' things to tables from the same package environment.");
08e8d4d0
AE
311 }
312 }
313 }
314 else {
315 // log
316 $this->columnLog[] = array('tableName' => $tableName, 'columnName' => $columnName, 'packageID' => $this->package->packageID, 'action' => 'insert');
317
318 // execute
319 parent::executeAddColumnStatement($tableName, $columnName, $columnData);
320 }
321 }
322
323 /**
9f959ced 324 * @see wcf\system\database\util\SQLParser::executeAddColumnStatement()
08e8d4d0
AE
325 */
326 protected function executeAlterColumnStatement($tableName, $oldColumnName, $newColumnName, $newColumnData) {
327 if ($this->test) {
328 if ($ownerPackageID = $this->getColumnOwnerID($tableName, $oldColumnName)) {
329 if ($ownerPackageID != $this->package->packageID) {
4fe0b42b 330 throw new SystemException("Can not alter column '.$oldColumnName.'. A package can only change own columns.");
08e8d4d0
AE
331 }
332 }
333 }
334 else {
335 // log
336 if ($oldColumnName != $newColumnName) {
337 $this->columnLog[] = array('tableName' => $tableName, 'columnName' => $oldColumnName, 'packageID' => $this->package->packageID, 'action' => 'delete');
338 $this->columnLog[] = array('tableName' => $tableName, 'columnName' => $newColumnName, 'packageID' => $this->package->packageID, 'action' => 'insert');
339 }
340
341 // execute
342 parent::executeAlterColumnStatement($tableName, $oldColumnName, $newColumnName, $newColumnData);
343 }
344 }
345
346 /**
9f959ced 347 * @see wcf\system\database\util\SQLParser::executeAddIndexStatement()
08e8d4d0
AE
348 */
349 protected function executeAddIndexStatement($tableName, $indexName, $indexData) {
350 if ($this->test) {
351 if (isset($this->knownTables[$tableName])) {
567b9611 352 if ($this->knownTables[$tableName] != $this->package->packageID && !in_array($this->knownTables[$tableName], $this->dependentPackageIDs)) {
4fe0b42b 353 throw new SystemException("Can not add index '".$indexName."' to table '.$tableName.'. An installion can only 'ADD' things to tables from the same package environment.");
08e8d4d0
AE
354 }
355 }
356 }
357 else {
358 // log
359 $this->indexLog[] = array('tableName' => $tableName, 'indexName' => $indexName, 'packageID' => $this->package->packageID, 'action' => 'insert');
360
361 // execute
362 parent::executeAddIndexStatement($tableName, $indexName, $indexData);
363 }
364 }
365
366 /**
9f959ced 367 * @see wcf\system\database\util\SQLParser::executeAddForeignKeyStatement()
567b9611
MW
368 */
369 protected function executeAddForeignKeyStatement($tableName, $indexName, $indexData) {
370 if ($this->test) {
371 if (isset($this->knownTables[$tableName])) {
372 if ($this->knownTables[$tableName] != $this->package->packageID && !in_array($this->knownTables[$tableName], $this->dependentPackageIDs)) {
4fe0b42b 373 throw new SystemException("Can not add foreign key '".$indexName."' to table '.$tableName.'. An installion can only 'ADD' things to tables from the same package environment.");
567b9611
MW
374 }
375 }
376 }
377 else {
378 // log
379 $this->indexLog[] = array('tableName' => $tableName, 'indexName' => $indexName, 'packageID' => $this->package->packageID, 'action' => 'insert');
380
381 // execute
382 parent::executeAddForeignKeyStatement($tableName, $indexName, $indexData);
383 }
384 }
385
386 /**
9f959ced 387 * @see wcf\system\database\util\SQLParser::executeDropColumnStatement()
08e8d4d0
AE
388 */
389 protected function executeDropColumnStatement($tableName, $columnName) {
390 if ($this->test) {
391 if ($ownerPackageID = $this->getColumnOwnerID($tableName, $columnName)) {
392 if ($ownerPackageID != $this->package->packageID) {
4fe0b42b 393 throw new SystemException("Can not drop column '.$columnName.'. A package can only drop own columns.");
08e8d4d0
AE
394 }
395 }
396 }
397 else {
398 // log
399 $this->columnLog[] = array('tableName' => $tableName, 'columnName' => $columnName, 'packageID' => $this->package->packageID, 'action' => 'delete');
400
401 // execute
402 parent::executeDropColumnStatement($tableName, $columnName);
403 }
404 }
405
406 /**
9f959ced 407 * @see wcf\system\database\util\SQLParser::executeDropIndexStatement()
08e8d4d0
AE
408 */
409 protected function executeDropIndexStatement($tableName, $indexName) {
410 if ($this->test) {
6286572b 411 if ($ownerPackageID = $this->getIndexOwnerID($tableName, $indexName)) {
08e8d4d0 412 if ($ownerPackageID != $this->package->packageID) {
4fe0b42b 413 throw new SystemException("Can not drop index '.$indexName.'. A package can only drop own indices.");
08e8d4d0
AE
414 }
415 }
416 }
417 else {
418 // log
419 $this->indexLog[] = array('tableName' => $tableName, 'indexName' => $indexName, 'packageID' => $this->package->packageID, 'action' => 'delete');
420
421 // execute
422 parent::executeDropIndexStatement($tableName, $indexName);
423 }
424 }
425
426 /**
9f959ced 427 * @see wcf\system\database\util\SQLParser::executeDropTableStatement()
08e8d4d0
AE
428 */
429 protected function executeDropTableStatement($tableName) {
430 if ($this->test) {
431 if (in_array($tableName, $this->existingTables)) {
432 if (isset($this->knownTables[$tableName])) {
433 if ($this->knownTables[$tableName] != $this->package->packageID) {
4fe0b42b 434 throw new SystemException("Can not drop table '.$tableName.'. A package can only drop own tables.");
08e8d4d0
AE
435 }
436 }
437 else {
ffdf6f14
AE
438 if (!isset($this->conflicts['DROP TABLE'])) $this->conflicts['DROP TABLE'] = array();
439 $this->conflicts['DROP TABLE'][] = $tableName;
08e8d4d0
AE
440 }
441 }
442 }
443 else {
444 // log
445 $this->tableLog[] = array('tableName' => $tableName, 'packageID' => $this->package->packageID, 'action' => 'delete');
446
447 // execute
448 parent::executeDropTableStatement($tableName);
449 }
450 }
451
452 /**
9f959ced 453 * @see wcf\system\database\util\SQLParser::executeStandardStatement()
08e8d4d0
AE
454 */
455 protected function executeStandardStatement($query) {
456 if (!$this->test) {
457 parent::executeStandardStatement($query);
458 }
459 }
460}