install.sql; ADD CONSTRAINT schlägt fehl.

  • Hallo,

    ich brauche eine Tabelle in der Feeds gespeichert werden. Ein Backgroundjob soll regelmäßig nach Updates schauen, ich bekomme die Daten mit einen Timestamp sowie einer Benutzerzuordnung. Beide Daten zusammen sind einzigartig, daher möchte ich diese als UNIQUE CONSTRAINT verwenden um bei den Updates der Feed bereits ausgelesene mittels INSERT ... ON DUPLICATE KEY UPDATE ...zu überspringen.

    So wird das ganze definiert: ALTER TABLE wcf1_gman_feedlist ADD CONSTRAINT charId_feedTime_UQ UNIQUE (charID, feedTime);

    Das WCF versteht diese Anweisung aber falsch und will eine Column an die tabelle tackern: wcf\system\package\PackageInstallationSQLParser->executeAddColumnStatement('wcf1_gman_feedlist', 'CONSTRAINT', [ type => , notNull => , default => , autoIncrement => , key => ])

    Das Resultat ist diese Fehlermeldung:

    Fehlermeldung

    Ein Fehler ist aufgetreten

    Interner Fehlercode: 04c75206f8f49961a95867dac5fe8d1fd445f5eb

    Was ist passiert?

    Leider ist es bei der Verarbeitung zu einem Fehler gekommen und die Ausführung wurde abgebrochen. Falls möglich, leiten Sie bitte den oben stehenden Fehlercode an den Administrator weiter.

    Administratoren können die vollständige Fehlermeldung mit Hilfe dieses Codes in der Administrationsoberfläche unter „Protokoll » Fehler“ einsehen. Zusätzlich wurden die Informationen in die Protokolldatei */log/2016-12-30.txt geschrieben und können beispielsweise mit Hilfe eines FTP-Programms abgerufen werden.

    Hinweis: Der Fehlercode wird zufällig generiert, erlaubt keinen Rückschluss auf die Ursache und ist daher für Dritte nutzlos.

    System Information

    • PHP Version:

      7.0.13-1~dotdeb+8.1

    • WoltLab Suite Core:

      3.0.0 RC 4

    • Peak Memory Usage:

      4.364/128 MiB

    • Request URI:

      /com.sylvansagarde/acp/index.php?install-package/&t=948d42b4ef3c3cc6d98bfcc4e7bca90d61a4a39f

    • Referrer:

      http://192.168.0.14/com.sylvansaga…irm/&queueID=54

    • User Agent:

      Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36

    Error

    • Error Type:

      wcf\system\exception\SystemException

    • Error Message:

      Cannot add column 'CONSTRAINT' to table 'wcf1_gman_feedlist'.

    • File:

      */lib/system/package/PackageInstallationSQLParser.class.php (281)

    • Stack Trace:

      • #0 */lib/system/database/util/SQLParser.class.php (155):
      • wcf\system\package\PackageInstallationSQLParser->executeAddColumnStatement('wcf1_gman_feedlist', 'CONSTRAINT', [ type => , notNull => , default => , autoIncrement => , key => ])
      • #1 */lib/system/database/util/SQLParser.class.php (47):
      • wcf\system\database\util\SQLParser->executeStatement('ALTER TABLE', 'ALTER TABLE wcf1_gman_feedlist ADD CONSTRAINT charId_feedTime_UQ UNIQUE (charID, feedTime)')
      • #2 */lib/system/package/PackageInstallationSQLParser.class.php (103):
      • wcf\system\database\util\SQLParser->execute()
      • #3 */lib/system/package/plugin/SQLPackageInstallationPlugin.class.php (45):
      • wcf\system\package\PackageInstallationSQLParser->test()
      • #4 */lib/system/package/PackageInstallationDispatcher.class.php (595):
      • wcf\system\package\plugin\SQLPackageInstallationPlugin->install()
      • #5 */lib/system/package/PackageInstallationDispatcher.class.php (134):
      • wcf\system\package\PackageInstallationDispatcher->executePIP([ attributes => , pip => , value => ])
      • #6 */lib/acp/action/InstallPackageAction.class.php (72):
      • wcf\system\package\PackageInstallationDispatcher->install('cfdb4fd8')
      • #7 */lib/action/AbstractDialogAction.class.php (68):
      • wcf\acp\action\InstallPackageAction->stepInstall()
      • #8 */lib/action/AbstractAction.class.php (47):
      • wcf\action\AbstractDialogAction->execute()
      • #9 */lib/system/request/Request.class.php (83):
      • wcf\action\AbstractAction->__run()
      • #10 */lib/system/request/RequestHandler.class.php (94):
      • wcf\system\request\Request->execute()
      • #11 */acp/index.php (9):
      • wcf\system\request\RequestHandler->handle('wcf', true)

    Zur besseren Übersicht die komplette install.sql (In Zeile 222 ist besagtes ALTER TABLE zu finden):

    Vielleicht hat ja jemand den entschiedenen Tipp

  • Diese Syntax wird nicht unterstützt, der UNIQUE-Key erhält automatisch einen Namen auf Basis der abdeckten Spalten. Dies funktioniert auch beim Entfernen des Keys.

    Im Übrigen nutzen wir das Anlegen von Tabellen um derartige Keys direkt festzulegen, so befindet sich abseits der Foreign Keys alles an einem Ort.

  • Vielen Dank für die Antworten!

    Alexander Ebert Wie heißt dann der erstellte UNIQUE Key? Kann ich diesen im Datenbank Objekt verwenden? Beispiel: der erstellte Key heißt charID_feedTime

  • Ich glaube, hier besteht ein Missverständnis: \wcf\data\DatabaseObject::$databaseTableIndexName bezieht sich auf den Namen der Spalte die als primärer Index dient, bei Themen zum Beispiel threadID. Der Name des UNIQUE-Keys ist an der Stelle weder gefragt, noch gültig, auch wenn die Bezeichnung möglicherweise etwas irreführend ist.

    Idealerweise solltest du weder Tabellen-Name, noch Index direkt festlegen sondern diese automatisch erzeugen lassen. Dies setzt entsprechende Anpassungen des Namespace und Klassennamens voraus, erlaubt dann aber eine einwandfreie Zuordnung. Wenn du allerdings abweichende Bezeichnungen nutzen willst, dann musst du sie selbst angeben. Die Funktionsweise wird hier erläutert: https://docs.woltlab.com/php_database-objects.html

  • Ah prima, ich wusste gar nicht, dass ich mir $databaseTableIndexNamesparen kann, wenn ich die Indexes wie den Tabellennamen benenne. Da ich mir alle meine DBOs direkt aus der Datenbank generieren lasse, war mir die zusätzlich "Schreibarbeit" immer egal.

    Ich habe aber nun ein weiteres Problem. Ich muss bestimmte columns einen anderen Charset zuordenen. Nur bekomme ich das nicht durch den installer, die zusätzlichen Angaben werde immer ignoriert. Bisher versucht habe ich:

    [...] charID VARCHAR(35) NOT NULL COLLATE utf8mb4_bin, [...]

    oder

    ALTER TABLE wcf1_gman_feedlist CHANGE charID charID VARCHAR(35) NOT NULL COLLATE utf8mb4_bin;

    Ein Blick in den Parser verrät auch warum.

    Daher habe ich mir den Parser lokal gepatcht weil ich gerne an meinem Plugin weiterentwickeln möchte:

    PHP: SQLParsrer.class.php
    else if (preg_match("~^ALTER\s+TABLE\s+(\w+)\s+(?:(ADD)\s+(?:COLUMN\s+)?|(CHANGE)\s+(?:COLUMN\s+)?(\w+)\s+)(\w+)\s+(\w+)(?:\s*\((\s*(?:\d+(?:\s*,\s*\d+)?|'[^']*'(?:\s*,\s*'[^']*')*))\s*\))?(?:\s+UNSIGNED)?(?:\s+(NOT NULL|NULL))?(?:\s+DEFAULT\s+(-?\d+.\d+|-?\d+|NULL|'[^'\\\\]*(?:\\\\.[^'\\\\]*)*'))?(?:\s+(AUTO_INCREMENT))?(?:\s+(UNIQUE|PRIMARY)(?: KEY)?)?(?:\s(COLLATE\s+\w+))~is", $query, $match)) {
    PHP: SQLParsrer.class.php
    if (!empty($match[12])) {
                            if (preg_match('~^COLLATE\s+(\w+)$~', StringUtil::trim($match[12]), $match2)) {
                                $columnData['collation'] = $match2[1];
                            }
                            else {
                                    throw new SystemException("Unsupported SQL statement '".$query."'");
                            }
                        }
    PHP: MySQLDatabaseEditor.class.php
    // coallition
            if (isset($columnData['collation'])) $definition .= " COLLATE ".$columnData['collation'];

    Das ist natürlich reichlich kompliziert. Gibt es eine andere Lösung die Kollation zu ändern?

  • Nur bekomme ich das nicht durch den installer, die zusätzlichen Angaben werde immer ignoriert.

    Wozu willst du auf case-sensitive wechseln? Was genau steht denn in charID drin, damit du darauf angewiesen bist, basierend auf dem Tabellennamen würde ich auf den Charakternamen bei WoW tippen, diese ist aber (zu mindestens im Original) case-insensitive.

  • Ein bekanntes Problem ist aber, dass utf8mb4_unicode_ci keine eindeutige Vergleiche zulässt. Spätestens, wenn die gespeicherten Werte Umlaute oder Akzente verwenden kann SQL die Schlüssel nicht mehr eindeutig identifizieren.

    In der Spalte werden Charakternamen gespeichert. Zum Beispiel: Veneanar und Veneanár. Ich will einen neuen Datensatz für Veneanár anlegen, Veneanar ist schon vorhanden. Die Daten aber nicht neu angelegt, da SQL "so was ähnliches" schon findet.

  • Ja die Daten kommen aus der battle.net API im JSON Format und werden per BULK UPDATE/ INSERT importiert.


    An VARBINARYhabe ich gar nicht gedacht, werde ich mal testen. Danke für den Hinweiß. Ich bin schon halb verrückt geworden weil ich gar nicht wusste Umlaute etc. ignoriert werden und auf Stackoverflow wurde die Verwendung von utf8mb4_bin empfohlen.

    Ich habe alles auf VARBINARY umgestellt und wie es aussieht funktioniert alles prima. Ein Abend ist zwar drauf gegangen, dafür habe ich

    • meine REGEX Kenntnisse aufgefrischt
    • einen besseren Einblick in die API bekommen
    • und jede Menge Leute verrückt gemacht ;)

    Danke an alle für die schnelle Hilfe.

  • Ich hab die Status Code Prüfung ersetzt:

    Damit die cronjobs nicht deaktiviert werden weil ein Spieler z.B. den Char gelöscht hat oder das battle.net mal ein paar Minuten nicht erreichbar ist. Vor allem will ich in den Logs sehen wo es scheitert, da HTTPRequest im Fehlerfall nicht die URL herausrückt. Bei 400-500 Updates suche ich mir ja 'n Wolf.

  • Wie kommst du darauf dass man die URL nicht bekommt ?

    Musst den Fehler nur richtig loggen, dann kann man es sich ganz normal im ACP anschauen:

    Code
    catch (LoggedException $e) {
                $e->getExceptionID(); // log error
                
                // do something like counting the error char up until it counts as deleted etc
            }
  • Ja, das war auch mein erster Gedanke, aber:

  • Danke für den Hinweiß, ich hab es eingebaut. Ich wollte gestern das erste Mal das Plugin packen und richtig testen. Nur gibt es schon wieder ein Problem mit der install.sql:

    Während der Installation sollen zwei Tabellen befüllt werden: wcf1_gman_wow_classes und wcf1_gman_wow_races. Er füllt aber nur die *_races, die *_classes bleibt leer:

    Während der Installation wird kein Fehler angezeigt. Die komplette install.sql findet man hier: https://github.com/Veneanar/info.…gin/install.sql

Participate now!

Don’t have an account yet? Register yourself now and be a part of our community!