Skip to content

Commit 771b8be

Browse files
authored
Merge pull request #6607 from WoltLab/63-install-sql-ddl
Use the PHP-DDL for the WCFSetup
2 parents 797a0dd + 95fb084 commit 771b8be

10 files changed

Lines changed: 5251 additions & 2468 deletions

File tree

.github/workflows/sql.yml

Lines changed: 0 additions & 23 deletions
This file was deleted.

wcfsetup/install/files/lib/data/user/option/UserOptionEditor.class.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,14 +150,12 @@ public static function getColumnDefinition($optionType)
150150
case 'boolean':
151151
$column['notNull'] = true;
152152
$column['default'] = 0;
153-
$column['length'] = 1;
154153
$column['type'] = 'tinyint';
155154
break;
156155

157156
case 'integer':
158157
$column['notNull'] = true;
159158
$column['default'] = 0;
160-
$column['length'] = 10;
161159
$column['type'] = 'int';
162160
break;
163161

wcfsetup/install/files/lib/system/WCFSetup.class.php

Lines changed: 97 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use wcf\system\database\Database;
1515
use wcf\system\database\exception\DatabaseException;
1616
use wcf\system\database\MySQLDatabase;
17+
use wcf\system\database\table\DatabaseTableChangeProcessor;
1718
use wcf\system\database\util\SQLParser;
1819
use wcf\system\devtools\DevtoolsSetup;
1920
use wcf\system\exception\SystemException;
@@ -200,7 +201,7 @@ protected function calcProgress(int $currentStep): void
200201
\file_put_contents(\TMP_DIR . 'lastStep', $currentStep);
201202

202203
// calculate progress
203-
$progress = \round((100 / 22) * ++$currentStep, 0);
204+
$progress = \round((100 / 14) * ++$currentStep, 0);
204205
self::getTPL()->assign(['progress' => $progress]);
205206
}
206207

@@ -275,23 +276,23 @@ protected function dispatch(): ResponseInterface
275276
return $this->createDB();
276277

277278
case 'unzipFiles':
278-
$this->calcProgress(18);
279+
$this->calcProgress(10);
279280
$this->assertNotUnzipped();
280281

281282
return $this->unzipFiles();
282283

283284
case 'installLanguage':
284-
$this->calcProgress(19);
285+
$this->calcProgress(11);
285286

286287
return $this->installLanguage();
287288

288289
case 'createUser':
289-
$this->calcProgress(20);
290+
$this->calcProgress(12);
290291

291292
return $this->createUser();
292293

293294
case 'installPackages':
294-
$this->calcProgress(21);
295+
$this->calcProgress(13);
295296

296297
return $this->installPackages();
297298

@@ -663,58 +664,113 @@ protected function createDB(): ResponseInterface
663664
{
664665
$this->initDB();
665666

666-
// get content of the sql structure file
667-
$sql = \file_get_contents(TMP_DIR . 'setup/db/install.sql');
667+
$dbEditor = self::getDB()->getEditor();
668+
669+
$tableNames = $dbEditor->getTableNames();
670+
if (!\in_array('wcf1_package_installation_sql_log', $tableNames)) {
671+
$dbEditor->createTable('wcf1_package_installation_sql_log', [
672+
['name' => 'packageID', 'data' => ['type' => 'int', 'notNull' => true]],
673+
['name' => 'sqlTable', 'data' => ['type' => 'varchar', 'length' => 100, 'notNull' => true, 'default' => "''"]],
674+
['name' => 'sqlColumn', 'data' => ['type' => 'varchar', 'length' => 100, 'notNull' => true, 'default' => "''"]],
675+
['name' => 'sqlIndex', 'data' => ['type' => 'varchar', 'length' => 100, 'notNull' => true, 'default' => "''"]],
676+
['name' => 'isDone', 'data' => ['type' => 'tinyint', 'notNull' => true, 'default' => 1]],
677+
], [
678+
[
679+
'name' => 'packageID',
680+
'data' => ['type' => 'UNIQUE', 'columns' => 'packageID,sqlTable,sqlColumn,sqlIndex'],
681+
]
682+
]);
668683

669-
// split by offsets
670-
$sqlData = \explode('/* SQL_PARSER_OFFSET */', $sql);
671-
$offset = isset($_POST['offset']) ? \intval($_POST['offset']) : 0;
672-
if (!isset($sqlData[$offset])) {
673-
throw new SystemException("Offset for SQL parser is out of bounds, " . $offset . " was requested, but there are only " . \count($sqlData) . " sections");
684+
$sql = "INSERT INTO wcf1_package_installation_sql_log
685+
(packageID, sqlTable, isDone)
686+
VALUES (?, ?, ?)";
687+
$statement = self::getDB()->prepareUnmanaged($sql);
688+
$statement->execute([1, 'wcf1_package_installation_sql_log', 1]);
674689
}
675-
$sql = $sqlData[$offset];
676690

677-
// execute sql queries
678-
$parser = new SQLParser($sql);
679-
$parser->execute();
691+
$package = new \wcf\data\package\Package(null, ['packageID' => 1, 'package' => 'com.woltlab.wcf']);
692+
$hasPackageTable = false;
693+
$tables = require \TMP_DIR . 'setup/db/install_com.woltlab.wcf.php';
694+
695+
$completed = false;
696+
$processor = new DatabaseTableChangeProcessor(
697+
$package,
698+
null,
699+
$dbEditor,
700+
);
701+
for ($i = 0; $i < 50; $i++) {
702+
$this->createPseudoPackage();
680703

681-
// log sql queries
682-
\preg_match_all("~CREATE\\s+TABLE\\s+(\\w+)~i", $sql, $matches);
704+
if ($processor->process($tables)) {
705+
continue;
706+
}
683707

684-
$sql = "INSERT INTO wcf1_package_installation_sql_log
685-
(packageID, sqlTable)
686-
VALUES (?, ?)";
687-
$statement = self::getDB()->prepare($sql);
688-
foreach ($matches[1] as $tableName) {
689-
$statement->execute([1, $tableName]);
708+
$completed = true;
709+
break;
690710
}
691711

692-
if ($offset < (\count($sqlData) - 1)) {
712+
if (!$completed) {
713+
$offset = isset($_POST['offset']) ? \intval($_POST['offset']) : 0;
693714
WCF::getTPL()->assign([
694715
'__additionalParameters' => [
695716
'offset' => $offset + 1,
696717
],
697718
]);
698719

699720
return $this->gotoNextStep('createDB');
700-
} else {
701-
/*
702-
* Manually install PIPPackageInstallationPlugin since install.sql content is not escaped resulting
703-
* in different behaviour in MySQL and MSSQL. You SHOULD NOT move this into install.sql!
704-
*/
705-
$sql = "INSERT INTO wcf1_package_installation_plugin
706-
(packageID, pluginName, priority, className)
707-
VALUES (?, ?, ?, ?)";
708-
$statement = self::getDB()->prepare($sql);
709-
$statement->execute([
710-
1,
711-
'packageInstallationPlugin',
712-
1,
713-
'wcf\system\package\plugin\PIPPackageInstallationPlugin',
714-
]);
721+
}
722+
723+
$sql = \explode(
724+
"\n",
725+
\file_get_contents(TMP_DIR . 'setup/db/install.sql')
726+
);
727+
foreach ($sql as $line) {
728+
$line = StringUtil::trim($line);
729+
if ($line === '' || \str_starts_with($line, '-- ')) {
730+
continue;
731+
}
732+
733+
WCF::getDB()->prepareUnmanaged($line)->execute();
734+
}
735+
736+
return $this->gotoNextStep('unzipFiles');
737+
}
738+
739+
/**
740+
* Dynamically creates the pseudo row in `wcf1_package` after the table has
741+
* been created. This step is necessary to preserve the integrity of the
742+
* foreign key enforced on the SQL log and PIP table.
743+
*/
744+
private function createPseudoPackage(): void
745+
{
746+
static $hasPseudoPackage = false;
747+
if ($hasPseudoPackage) {
748+
return;
749+
}
715750

716-
return $this->gotoNextStep('unzipFiles');
751+
$sql = "SHOW TABLES FROM " . self::getDB()->getDatabaseName() . " LIKE 'wcf1_package'";
752+
$statement = self::getDB()->prepareUnmanaged($sql);
753+
$statement->execute([]);
754+
$hasTable = $statement->fetchSingleRow();
755+
if ($hasTable === false) {
756+
return;
717757
}
758+
759+
$sql = "SELECT *
760+
FROM wcf1_package
761+
WHERE packageID = ?";
762+
$statement = self::getDB()->prepareUnmanaged($sql);
763+
$statement->execute([1]);
764+
$row = $statement->fetchSingleRow();
765+
if ($row === false) {
766+
$sql = "INSERT INTO wcf1_package
767+
(packageID, package)
768+
VALUES (?, ?)";
769+
$statement = self::getDB()->prepareUnmanaged($sql);
770+
$statement->execute([1, 'com.woltlab.wcf']);
771+
}
772+
773+
$hasPseudoPackage = true;
718774
}
719775

720776
/**

0 commit comments

Comments
 (0)