From: Alexander Ebert Date: Tue, 19 Jul 2011 14:14:02 +0000 (+0200) Subject: Added missing SQL-Parser from revision 4722 X-Git-Tag: 2.0.0_Beta_1~1998^2 X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=08e8d4d099729fbf5359c0a19b8b2a07ccb27003;p=GitHub%2FWoltLab%2FWCF.git Added missing SQL-Parser from revision 4722 --- diff --git a/wcfsetup/install/files/lib/system/package/PackageInstallationSQLParser.class.php b/wcfsetup/install/files/lib/system/package/PackageInstallationSQLParser.class.php new file mode 100644 index 0000000000..e2238a1f58 --- /dev/null +++ b/wcfsetup/install/files/lib/system/package/PackageInstallationSQLParser.class.php @@ -0,0 +1,452 @@ + + * @package com.woltlab.wcf + * @subpackage system.package + * @category Community Framework + */ +class PackageInstallationSQLParser extends SQLParser { + /** + * Package object + * + * @var Package + */ + protected $package; + + /** + * activates the testing mode + * + * @var boolean + */ + protected $test = false; + + /** + * installation type + * + * @var string + */ + protected $action = 'install'; + + /** + * list of existing database tables + * + * @var array + */ + protected $existingTables = array(); + + /** + * list of logged tables + * + * @var array + */ + protected $knownTables = array(); + + /** + * list of package ids + * + * @var array + */ + protected $dependentPackageIDArray = array(); + + /** + * list of conflicted database tables + * + * @var array + */ + protected $conflicts = array(); + + /** + * list of created/deleted tables + * + * @var array + */ + protected $tableLog = array(); + + /** + * list of created/deleted columns + * + * @var array + */ + protected $columnLog = array(); + + /** + * list of created/deleted indices + * + * @var array + */ + protected $indexLog = array(); + + /** + * Creates a new PackageInstallationSQLParser object. + * + * @param string $queries + * @param Package $package + * @param string $action + */ + public function __construct($queries, Package $package, $action = 'install') { + $this->package = $package; + $this->action = $action; + parent::__construct($queries); + } + + /** + * Performs a test of the given queries. + * + * @return array conflicts + */ + public function test() { + $this->conflicts = array(); + + // get all existing tables from database + $this->existingTables = WCF::getDB()->getEditor()->getTableNames(); + + // get logged tables + $this->getKnownTables(); + + // get package ids of dependencies + $this->getDependentPackageIDArray(); + + // enable testing mode + $this->test = true; + + // run test + $this->execute(); + + // disable testing mode + $this->test = false; + + // return conflicts + return $this->conflicts; + } + + /** + * Logs executed sql queries + */ + public function log() { + // tables + foreach ($this->tableLog as $logEntry) { + $sql = "DELETE FROM wcf".WCF_N."_package_installation_sql_log + WHERE sqlTable = ?"; + $statement = WCF::getDB()->prepareStatement($sql); + $statement->execute(array($logEntry['tableName'])); + + if ($logEntry['action'] == 'insert') { + $sql = "INSERT INTO wcf".WCF_N."_package_installation_sql_log + (packageID, sqlTable) + VALUES (?, ?)"; + $statement = WCF::getDB()->prepareStatement($sql); + $statement->execute(array( + $logEntry['packageID'], + $logEntry['tableName'] + )); + } + } + + // columns + if (count($this->columnLog)) { + $sql = "DELETE FROM wcf".WCF_N."_package_installation_sql_log + WHERE sqlTable = ? + AND sqlColumn = ?"; + $deleteStatement = WCF::getDB()->prepareStatement($sql); + + $sql = "INSERT INTO wcf".WCF_N."_package_installation_sql_log + (packageID, sqlTable, sqlColumn) + VALUES (?, ?, ?)"; + $insertStatement = WCF::getDB()->prepareStatement($sql); + + foreach ($this->columnLog as $logEntry) { + $deleteStatement->execute(array( + $logEntry['tableName'], + $logEntry['columnName'] + )); + + if ($logEntry['action'] == 'insert') { + $insertStatement->execute(array( + $logEntry['packageID'], + $logEntry['tableName'], + $logEntry['columnName'] + )); + } + } + } + + // indices + if (count($this->indexLog)) { + $sql = "DELETE FROM wcf".WCF_N."_package_installation_sql_log + WHERE sqlTable = ? + AND sqlIndex = ?"; + $deleteStatement = WCF::getDB()->prepareStatement($sql); + + $sql = "INSERT INTO wcf".WCF_N."_package_installation_sql_log + (packageID, sqlTable, sqlIndex) + VALUES (?, ?, ?)"; + $insertStatement = WCF::getDB()->prepareStatement($sql); + + foreach ($this->indexLog as $logEntry) { + $deleteStatement->execute(array( + $logEntry['tableName'], + $logEntry['indexName'] + )); + + if ($logEntry['action'] == 'insert') { + $insertStatement->execute(array( + $logEntry['packageID'], + $logEntry['tableName'], + $logEntry['indexName'] + )); + } + } + } + } + + /** + * Gets known sql tables and their owners from installation log. + */ + protected function getKnownTables() { + $sql = "SELECT packageID, sqlTable + FROM wcf".WCF_N."_package_installation_sql_log + WHERE sqlColumn = '' + AND sqlIndex = ''"; + $statement = WCF::getDB()->prepareStatement($sql); + $statement->execute(); + while ($row = $statement->fetchArray()) { + $this->knownTables[$row['sqlTable']] = $row['packageID']; + } + } + + /** + * Gets a list of dependent packages. + */ + protected function getDependentPackageIDArray() { + $sql = "SELECT dependency + FROM wcf".WCF_N."_package_dependency + WHERE packageID = ?"; + $statement = WCF::getDB()->prepareStatement($sql); + $statement->execute(array($this->package->packageID)); + $packages = array(); + while ($row = $statement->fetchArray()) { + $this->dependentPackageIDArray[] = $row['dependency']; + } + } + + /** + * Returns the owner of a specific database table column. + * + * @param string $tableName + * @param string $columnName + * @return integer package id + */ + protected function getColumnOwnerID($tableName, $columnName) { + $sql = "SELECT packageID + FROM wcf".WCF_N."_package_installation_sql_log + WHERE sqlTable = ? + AND sqlColum = ?"; + $statement = WCF::getDB()->prepareStatement($sql); + $statement->execute(array( + $tableName, + $columnName + )); + $row = $statement->fetchArray(); + if (!empty($row['packageID'])) return $row['packageID']; + else if (isset($this->knownTables[$tableName])) return $this->knownTables[$tableName]; + else return null; + } + + /** + * Returns the owner of a specific database index. + * + * @param string $tableName + * @param string $indexName + * @return integer package id + */ + protected function getIndexOwnerID($tableName, $indexName) { + $sql = "SELECT packageID + FROM wcf".WCF_N."_package_installation_sql_log + WHERE sqlTable = ? + AND sqlIndex = ?"; + $statement = WCF::getDB()->prepareStatement($sql); + $statement->execute(array( + $tableName, + $indexName + )); + $row = $statement->fetchArray(); + if (!empty($row['packageID'])) return $row['packageID']; + else if (isset($this->knownTables[$tableName])) return $this->knownTables[$tableName]; + else return null; + } + + /** + * @see SQLParser::executeCreateTableStatement() + */ + protected function executeCreateTableStatement($tableName, $columns, $indices = array()) { + if ($this->test) { + if (in_array($tableName, $this->existingTables)) { + if (isset($this->knownTables[$tableName])) { + if ($this->knownTables[$tableName] != $this->package->packageID) { + throw new SystemException("Can not recreate table '.$tableName.'. A package can only overwrite own tables.", 13019); + } + } + else { + if (!isset($this->conflicts[$tableName])) $this->conflicts[$tableName] = array(); + $this->conflicts[$tableName][] = 'CREATE TABLE'; + } + } + } + else { + // log + $this->tableLog[] = array('tableName' => $tableName, 'packageID' => $this->package->packageID, 'action' => 'insert'); + + // execute + parent::executeCreateTableStatement($tableName, $columns, $indices); + } + } + + /** + * @see SQLParser::executeAddColumnStatement() + */ + protected function executeAddColumnStatement($tableName, $columnName, $columnData) { + if ($this->test) { + if (isset($this->knownTables[$tableName])) { + if ($this->knownTables[$tableName] != $this->package->packageID && !in_array($this->knownTables[$tableName], $this->dependentPackageIDArray)) { + throw new SystemException("Can not add column '".$columnName."' to table '.$tableName.'. An installion can only 'ADD' things to tables from the same package environment.", 13019); + } + } + } + else { + // log + $this->columnLog[] = array('tableName' => $tableName, 'columnName' => $columnName, 'packageID' => $this->package->packageID, 'action' => 'insert'); + + // execute + parent::executeAddColumnStatement($tableName, $columnName, $columnData); + } + } + + /** + * @see SQLParser::executeAddColumnStatement() + */ + protected function executeAlterColumnStatement($tableName, $oldColumnName, $newColumnName, $newColumnData) { + if ($this->test) { + if ($ownerPackageID = $this->getColumnOwnerID($tableName, $oldColumnName)) { + if ($ownerPackageID != $this->package->packageID) { + throw new SystemException("Can not alter column '.$oldColumnName.'. A package can only change own columns.", 13019); + } + } + } + else { + // log + if ($oldColumnName != $newColumnName) { + $this->columnLog[] = array('tableName' => $tableName, 'columnName' => $oldColumnName, 'packageID' => $this->package->packageID, 'action' => 'delete'); + $this->columnLog[] = array('tableName' => $tableName, 'columnName' => $newColumnName, 'packageID' => $this->package->packageID, 'action' => 'insert'); + } + + // execute + parent::executeAlterColumnStatement($tableName, $oldColumnName, $newColumnName, $newColumnData); + } + } + + /** + * @see SQLParser::executeAddIndexStatement() + */ + protected function executeAddIndexStatement($tableName, $indexName, $indexData) { + if ($this->test) { + if (isset($this->knownTables[$tableName])) { + if ($this->knownTables[$tableName] != $this->package->packageID && !in_array($this->knownTables[$tableName], $this->dependentPackageIDArray)) { + throw new SystemException("Can not add index '".$indexName."' to table '.$tableName.'. An installion can only 'ADD' things to tables from the same package environment.", 13019); + } + } + } + else { + // log + $this->indexLog[] = array('tableName' => $tableName, 'indexName' => $indexName, 'packageID' => $this->package->packageID, 'action' => 'insert'); + + // execute + parent::executeAddIndexStatement($tableName, $indexName, $indexData); + } + } + + /** + * @see SQLParser::executeDropColumnStatement() + */ + protected function executeDropColumnStatement($tableName, $columnName) { + if ($this->test) { + if ($ownerPackageID = $this->getColumnOwnerID($tableName, $columnName)) { + if ($ownerPackageID != $this->package->packageID) { + throw new SystemException("Can not drop column '.$columnName.'. A package can only drop own columns.", 13019); + } + } + } + else { + // log + $this->columnLog[] = array('tableName' => $tableName, 'columnName' => $columnName, 'packageID' => $this->package->packageID, 'action' => 'delete'); + + // execute + parent::executeDropColumnStatement($tableName, $columnName); + } + } + + /** + * @see SQLParser::executeDropIndexStatement() + */ + protected function executeDropIndexStatement($tableName, $indexName) { + if ($this->test) { + if ($ownerPackageID = $this->getIndexOwnerID($tableName, $columnName)) { + if ($ownerPackageID != $this->package->packageID) { + throw new SystemException("Can not drop index '.$indexName.'. A package can only drop own indices.", 13019); + } + } + } + else { + // log + $this->indexLog[] = array('tableName' => $tableName, 'indexName' => $indexName, 'packageID' => $this->package->packageID, 'action' => 'delete'); + + // execute + parent::executeDropIndexStatement($tableName, $indexName); + } + } + + /** + * @see SQLParser::executeDropTableStatement() + */ + protected function executeDropTableStatement($tableName) { + if ($this->test) { + if (in_array($tableName, $this->existingTables)) { + if (isset($this->knownTables[$tableName])) { + if ($this->knownTables[$tableName] != $this->package->packageID) { + throw new SystemException("Can not drop table '.$tableName.'. A package can only drop own tables.", 13019); + } + } + else { + if (!isset($this->conflicts[$tableName])) $this->conflicts[$tableName] = array(); + $this->conflicts[$tableName][] = 'DROP TABLE'; + } + } + } + else { + // log + $this->tableLog[] = array('tableName' => $tableName, 'packageID' => $this->package->packageID, 'action' => 'delete'); + + // execute + parent::executeDropTableStatement($tableName); + } + } + + /** + * @see SQLParser::executeStandardStatement() + */ + protected function executeStandardStatement($query) { + if (!$this->test) { + parent::executeStandardStatement($query); + } + } +} +?>