Ankündigung

Einklappen
Keine Ankündigung bisher.

MariaDB: NULL trotz NOT NULL

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • MariaDB: NULL trotz NOT NULL

    Huhu,
    ich bin grade dabei Tests für ein Projekt von mir zu schreiben. Dabei schlug ein Test widererwarten Fehl. Bei dem Test wird versucht ein ungültigen Wert in die DB zu schreiben und es wird eine entsprechende Fehlermeldung der Datenbank erwartet. Das Feld 'email' in der DB ist auf UNIQUE und NOT NULL gesetzt. Trotzdem gelingt der Versuch per UPDATE ein NULL in das Feld 'email' zu setzten. Beim INSERT bricht die DB wie zu erwarten mit einem Fehler ab, wenn ich dies versuche. Habs auch per Konsole direkt händisch am SQL Server versucht, und der UPDATE Befehl geht durch. Liegt also nicht an dem PHP Code.
    Klar, wird eine Eingabe NULL im Betrieb des Projektes durch einen Validator vorher abgefangen, nur sollte sich trotzdem die Datenbank nicht so verhalten oder?

    Code:
    CREATE TABLE IF NOT EXISTS `users` (
      `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
      `email` VARCHAR(255) NOT NULL,
      `password` VARCHAR(255) NOT NULL,
      `group` INT UNSIGNED NOT NULL DEFAULT 4,
      `is_active` TINYINT UNSIGNED NOT NULL DEFAULT 0,
      `registrationToken` VARCHAR(64) NULL DEFAULT NULL,
      `resetToken` VARCHAR(64) NULL DEFAULT NULL,
      `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
      `changed_at` TIMESTAMP NULL DEFAULT NULL,
      `deleted_at` TIMESTAMP NULL DEFAULT NULL,
      PRIMARY KEY (`id`),
      UNIQUE INDEX `email_uidx` (`email` ASC),
      INDEX `group_idx` (`group` ASC),
      INDEX `created_idx` (`created_at` ASC),
      CONSTRAINT `group`
        FOREIGN KEY (`group`)
        REFERENCES `groups` (`id`)
        ON DELETE NO ACTION
        ON UPDATE CASCADE)
    ENGINE = InnoDB;
    Code:
    UPDATE users
    SET email=NULL
    WHERE id=4;
    Habe schon gegooglet und auch in der Doku von MariaDB zu dem Thema NULL und NOT NULL gelesen. Fand aber nichts, was dies anspricht.

    Liebe Grüße


  • #2
    Natürlich kannst du NULL dort reinschreiben. NOT NULL gilt als Voreinstellung und NULL ebenso, wenn kein Wert kommt.

    EDIT; ziehe meine Aussage zurück.

    Kommentar


    • #3
      Und du bist dir sicher, dass diese Tabelle-Defintion auch die korrekte ist?

      Mach mal:

      Code:
      UPDATE users SET email=NULL WHERE id=4;
      SHOW CREATE TABLE users;
      Das sollte eigentlich nicht möglich sein. Die Defintion von NULL und NOT NULL gibts nicht als Spaß. Für Abfragen ist es essentiell zu wissen, ob eine Spalte NULL sein kann.

      Kommentar


      • #4
        Ja, ist die korrekte Tabellen-Definition. Allerdings ist mir jetzt in der Konsole aufgefallen, dass er ein Warning schmeißt. Nichts desto trotz ist das Feld anschließend auf NULL gesetzt. Konfigurationsfehler?

        EDIT: Nein, er setzt das Feld nicht auf NULL sondern auf string(0), also einen leeren string. Nichts desto trotz sollte er die UPDATE Funktion hier lieber abbrechen, anstatt Sie durchzuführen.

        Code:
        MariaDB [projectMatch]> update users Set email=NULL WHERE id = 4;
        Query OK, 1 row affected, 1 warning (0.011 sec)
        Rows matched: 1  Changed: 1  Warnings: 1
        
        MariaDB [projectMatch]> show warnings;
        +---------+------+-------------------------------+
        | Level   | Code | Message                       |
        +---------+------+-------------------------------+
        | Warning | 1048 | Column 'email' cannot be null |
        +---------+------+-------------------------------+
        1 row in set (0.000 sec)
        
        MariaDB [projectMatch]> show create table users;
        +-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
        | Table | Create Table                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
        +-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
        | users | CREATE TABLE `users` (
          `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
          `email` varchar(255) COLLATE utf8mb4_bin NOT NULL,
          `password` varchar(255) COLLATE utf8mb4_bin NOT NULL,
          `group` int(10) unsigned NOT NULL DEFAULT 4,
          `is_active` tinyint(3) unsigned NOT NULL DEFAULT 0,
          `registrationToken` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL,
          `resetToken` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL,
          `created_at` timestamp NOT NULL DEFAULT current_timestamp(),
          `changed_at` timestamp NULL DEFAULT NULL,
          `deleted_at` timestamp NULL DEFAULT NULL,
          PRIMARY KEY (`id`),
          UNIQUE KEY `email_uidx` (`email`),
          KEY `group_idx` (`group`),
          KEY `created_idx` (`created_at`),
          CONSTRAINT `group` FOREIGN KEY (`group`) REFERENCES `groups` (`id`) ON DELETE NO ACTION ON UPDATE CASCADE
        ) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin |
        +-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
        1 row in set (0.000 sec)

        Kommentar


        • #5
          MySQL und Derivate sind halt Müll. Warum verwendet man sowas für ein neues Projekt und nicht PostgreSQL? CHECK-Constraints werden ja auch ignoriert, viele Features moderner Datenbanken sind schlicht nicht verfügbar.
          PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

          Kommentar


          • #6
            Alles klar... Je nach Konfiguration verhält sich Mysql und MariaDB sehr lax was fehlerhafte Daten angeht. Es werden diverse Fehler automatisch "korrigiert". Das kann über sql_mode gesteuert werden. (https://dev.mysql.com/doc/refman/8.0/en/sql-mode.html / bei MariaDB das selbe in grün)
            Seit Mysql 5.7 ist das standardmässig strict, aber da sehr viele Anwendungen darauf nicht klar kommen, wird das sehr oft rausgenommen. Das ganze kann bei Bedarf aus der Anwendung gesteuert werden.

            Kommentar


            • #7
              Zitat von akretschmer Beitrag anzeigen
              MySQL und Derivate sind halt Müll. Warum verwendet man sowas für ein neues Projekt und nicht PostgreSQL? CHECK-Constraints werden ja auch ignoriert, viele Features moderner Datenbanken sind schlicht nicht verfügbar.
              Schlichtweg, weil man es halt "immer schon so" gemacht hat. Und man sich noch nie an PostgreSQL oder andere Systeme rangetraut hat. Eigentlich eine dumme Aussage ich weiß, entspricht aber leider der Wahrheit. MySQL hat es bisher immer getan. Ich werde mir aber PostgreSQL gerne mal anschauen. Dennoch gehe ich davon aus, dass mein Problem eine Fehlkonfiguration sein muss und sich auch unter MySQL lösen lassen sollte.

              Zitat von erc
              Je nach Konfiguration verhält sich Mysql und MariaDB sehr lax was fehlerhafte Daten angeht. Es werden diverse Fehler automatisch korrigiert. Das kann über sql_mode gesteuert werden.
              Vielen Dank für die Info. Denke, dass sollte das Problem lösen.

              Nachtrag:
              Code:
              SET GLOBAL sql_mode = 'STRICT_ALL_TABLES';
              löst das Problem. Der Update Vorgang wird abgebrochen und der alte Datensatz wird wieder hergestellt + Exception wird geschmissen, so wie erwartet.

              Kommentar


              • #8
                Wenn du das GLOBAL setzt, machst du das Systemweit. Wenn da noch andere Anwendung laufen, vorsichtig... strict knallt bei unvollständigen inserts, Feldlängenüberschreitungen, falschen Datumsangaben und ungültigen Werten. Und "all tables" ist auch nicht ganz ohne. Wenn du Tabellen mit nicht transaktionsfähigen Engines hast, kann das zu teillweise ausgeführten Queries führen.

                Kommentar


                • #9
                  Zitat von erc Beitrag anzeigen
                  Wenn du das GLOBAL setzt, machst du das Systemweit. Wenn da noch andere Anwendung laufen, vorsichtig... strict knallt bei unvollständigen inserts, Feldlängenüberschreitungen, falschen Datumsangaben und ungültigen Werten. Und "all tables" ist auch nicht ganz ohne. Wenn du Tabellen mit nicht transaktionsfähigen Engines hast, kann das zu teillweise ausgeführten Queries führen.
                  Also ich muss schon sagen .. mir fehlen die Worte.

                  Naja nicht ganz:

                  Da wird gefragt, wie es richtig geht,
                  dann gibt es die richtigen Antworten,
                  und dann kommt eine Warnung,
                  dass man es sich noch mal überlegen soll, es global richtig zu machen?

                  Gefühlt die Hälfte aller mySQL Threads hier drehen sich permanent um den ganzen Schrott, den dieses seltsame Datenbank System verwurstet (durchgehen lässt) oder selbst produziert und wenn dann mal einer zu Ende denkt, dann wird davor gewarnt?!

                  Ebenso verstehe ich die Aussage des TE nicht: "weil man sich nicht an Postgres ran traut"
                  Was tut postgres denn so schlimmes? Es schluckt nicht jeden Scheiß und wirft Fehler, wo es sein muss.
                  Es macht alles richtig und akzeptiert keine fehlerhaften Statements.
                  Es hat nebenbei noch 100x mehr Funktionalität.

                  Was bedeutet es, ein neues Projekt mit einer richtigen DB zu machen?
                  Ich bekomme sofort eine Fehlermeldung, wenn ich falsche Statement abschicke, statt jahrelang Daten falsch zu speichern oder zu reporten.
                  Ich kann mir die Hälfte meiner SQL Statements sparen, weil sie Workarounds für fehlende Implemtierungen oder Fehler by Design sind.

                  Was will man mehr?!

                  Und was soll diese Warnung @erc?

                  Kommentar


                  • #10
                    Zitat von Perry Staltic Beitrag anzeigen
                    Ebenso verstehe ich die Aussage des TE nicht: "weil man sich nicht an Postgres ran traut"
                    Was tut postgres denn so schlimmes? Es schluckt nicht jeden Scheiß und wirft Fehler, wo es sein muss.
                    Es macht alles richtig und akzeptiert keine fehlerhaften Statements.
                    Es hat nebenbei noch 100x mehr Funktionalität.

                    Was bedeutet es, ein neues Projekt mit einer richtigen DB zu machen?
                    Ich bekomme sofort eine Fehlermeldung, wenn ich falsche Statement abschicke, statt jahrelang Daten falsch zu speichern oder zu reporten.
                    Ich kann mir die Hälfte meiner SQL Statements sparen, weil sie Workarounds für fehlende Implemtierungen oder Fehler by Design sind.

                    Was will man mehr?!


                    Mal als Beispiel, was man mit PostgreSQL noch so 'nebenbei' mit machen kann. Angenommen, es bestehen folgende Rahmenbedingungen:
                    • Benutzer können aktiv sein oder nicht. Das machst Du mit Deinem is_active, ich nenne es mal 'valid' und verwende als Datentyp BOOL
                    • aktive Benutzer müssen eine email-adresse haben
                    • inaktive dürfen keine haben, weil nach DSGVO Du für solche Nutzer persönliche Daten nicht speichern darfst
                    • Mailadressen aktiver Nutzer müssen UNIQUE sein
                    • in Abfragen auf aktive Benutzer willst Du in Mailadressen einen Index nutzen


                    Das könnte z.B. eine Uni sein, die bestimmte Daten, aber eben nicht alle, zu aktiven und bereits die Uni verlassenen Studenten. Irgendwann hast Du sehr viele inaktive Einträge, Du willst aber bei einer Suche für aktive Studenten einen effektiven Index haben.

                    Hier die Realisierung mit PostgreSQL, nur die 2 relevanten Spalten mail und valid:

                    Code:
                    test=*# create table mail (mail text, valid bool, check (mail is not null and valid), check (mail is null and not valid));
                    CREATE TABLE
                    test=*# create unique index idx_mail on mail(mail) where valid;
                    CREATE INDEX
                    test=*#
                    Versuche das mal mit MySQL ...


                    PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

                    Kommentar


                    • #11
                      Zitat von Perry Staltic Beitrag anzeigen
                      Und was soll diese Warnung @erc?
                      Diese Warnung soll zum nachdenken anregen. Das Thema sollte vielleicht nochmal etwas tiefer durchdrungen werden! Es wird eine serverweite Einstellung gesetzt, in Form einer flüchtigen Laufzeitvariable. Diese Einstellung hat das potentiall alle möglichen Probleme in bestehenden Anwendungen zu machen. Von geht gar nicht mehr, bis sehr sporadischen Fehlern.
                      Was ist mein Problem damit?
                      -Warum ist strict aus? Siehe oben, strict ist mittlerweile standardmässig aktiv... seit 2015!
                      -in der flüchtigen Laufzeitvariante?
                      -von jemand der Probleme hat NULL von "" zu unterschieden
                      -wurde verstanden was strict macht?
                      -in der all tables Variante werden Queries u.U. nicht mehr atomar ausgeführt (das ist überschaubar, aber in meinen Augen bleibt das auf einem Produktivsystem der völlige Brainfuck!)


                      Kommentar


                      • #12
                        akretschmer : Genau, es gäbe wahrscheinlich 100te so vielfältige Hinweise, was man mit Postgres alles schönes machen kann. Mir fällt gerade diese Sache mit dem Join Limit von 60 oder so ein. So viel brainfuck kann es gar nicht geben, das mit einem Workaround wieder "gut zu machen".
                        Ich fänd es aber spannend, was das für den TE wirklich bedeutet, "nicht ran trauen" an Postgres.

                        Vielleicht geht es ja sogar in eine Richtung, wie erc es schrieb. Dass man einfach Angst hat, (trotz neuem Projekt) dass der ganze alte Mist, den man gewohnt ist- den man vielleicht gerne per copy/paste irgendwo wiederverwenden würde-, nicht mehr funktioniert.Und ja, mglw. könnte tatsächlich der ein oder andere Workaround nicht 1:1 funktionieren, was aber kein Problem ist, wenn man statt dessen auf Standards, robuste Funktion und gerne auch auf tolle Erweiterungen setzt. Hier müsste man fairer Weise sagen, dass es bei Postgres viele Dinge gibt, mit denen man quasi "in der Falle" sitzt, wenn man sie benutzt. Schlicht weil es kein anderer kann. "Falle" ist natürlich relativ. Ist es eine Falle, wenn man die Grenzen nicht spürt?

                        erc: Ich fand, Dein Beitrag klang leider gegenteilig zu dem, was Du mir geantwortet hast. Eher wie: "Bevor Du es richtig machst, überleg Dir lieber noch mal, ob Du nicht lieber alles beim alten lässt" Natürlich kann so eine Änderung ein (bestehendes) System ins Wanken bringen. Aber es ging ja um ein neues. Und das "bewährte" (aka 1000 mal in irgendwelchen Foren abkopierte) Verfahren mit einer solchen Änderung vielleicht irgendwo die Grätsche machen, tja, dieses Risiko muss man wohl eingehen, wenn man dafür sowas wie Konsitenz bekommt.

                        Kommentar


                        • #13
                          Dennoch gehe ich davon aus, dass mein Problem eine Fehlkonfiguration sein muss und sich auch unter MySQL lösen lassen sollte.
                          Genau das ist btw. der Punkt dieses Threads.

                          Kommentar

                          Lädt...
                          X