hawkmaster: Probleme mit Umlauten Postgres UTF8

Hallo zusammen,
ich habe eine PG 9.0 Datenbankserver. Der Server selbst scheint auf UTF8 zu stehen. Zumindest zeigt mit ein;
SHOW server_encoding
das so an.
Die Datenbank "testdb" zeigt im PGAdmin bei Encoding = UTF8 and, Bei Collation und CharacterType ist "German_Germany.1252" eingestellt.

Meine PHP Seite verbindet mit PDO. Vorher hatte ich MySQL. Der MySQL Server hatte auch MySQL-Zeichensatz: UTF-8 Unicode (utf8)
Bei der MySQL Verbindung verwende ich $DBO->query("SET NAMES 'utf8'");
Dies habe ich so auch bei Postgres versucht.
Alle PHP Seiten stehen auf <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

Wenn ich bei Postgres in die Tabelle "mytext" in die Spalte "german" den Text "grün" speichern möchte, bekomme ich die Meldung:

Character not in repertoire: 7 FEHLER: ungültige Byte-Sequenz für Kodierung »UTF8«: 0xe3bc6e'
Im Webinterface wird mir insertText('gr??n',..
angezeigt.
In MySQL hatte ich hier keine Probleme. Auch ein Abschalten von SET NAMES 'utf8' brachte nichts.
Ich bin noch ein echter PG Anfänger. Ich habe einiges gegoogelt, komme aber nicht recht weiter.

Hat jemand einen Tipp für mich?
vielen Dank und viele Grüße
hawk

  1. Hi!

    Bei der MySQL Verbindung verwende ich $DBO->query("SET NAMES 'utf8'");
    Dies habe ich so auch bei Postgres versucht.

    Einfach mal so, oder hast du dich schlau gemacht, ob das so geht?

    Das Handbuch sagt, für die Client-Verbindungen wird die Kodierung der Datenbank angenommen. Außerdem könne man verbindungsspezifisch unter anderem mit SET NAMES eine individuelle Kodierung festlegen, woraufhin dann zwischen Client-Daten und Datenbank umkodiert wird.

    Alle PHP Seiten stehen auf <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

    Unwichtig. Schau lieber genau dort, wo es Probleme gibt, also zwischen DBMS und PHP. Stimmen die Bytewerte, die zum DBMS gehen sollen und stimmen die, die von dort kommen?

    Wenn ich bei Postgres in die Tabelle "mytext" in die Spalte "german" den Text "grün" speichern möchte, bekomme ich die Meldung:
    Character not in repertoire: 7 FEHLER: ungültige Byte-Sequenz für Kodierung »UTF8«: 0xe3bc6e'

    Wenn du dir das mal in Bits umrechnest, und dir dann anschaust, wie UTF-8 kodiert wird, sollte auffallen, dass PostgreSQL Recht hat. Das ist keine gültige UTF-8-Sequenz

    E3        BC        6E
    1110 0011 1011 1100 0110 0011

    Mit 1110 fangen 3-Byte-Sequenzen an. Dabei müssen zwei mit 10 beginnende Bytes folgen. Das trifft für 6E nicht zu.

    Im Webinterface wird mir insertText('gr??n',.. angezeigt.

    Mal 6E allein betrachtet entspricht das dem n. Wenn man E3BC zu C3BC korrigiert, ergibt das ein ü. Die Frage ist also, wo die falsche Byte-Sequenz herkommt.

    Lo!

    1. Hallo dedlfix,
      recht herzlichen Dank für deine Hinweise.
      Dadurch konnte ich das Problem eingrenzen.
      Es ist aber schon seltsam :-)

      Ich habe eine Funktion insertText:

        
      $textid = insertText($_POST['addvalues'],$_POST['addvalues'],$_POST['addvalues'],$_POST['addvalues'],$_POST['addvalues'],strtolower($_POST['addvalues']),'1');//inserts text and returns last insert id = textID  
      
      

      das Problem liegt bei "strtolower($_POST['addvalues'])". Ich möchte in einer Spalte alles in Kleinbuchstaben haben.
      Die Kontrollausgabe im Browser zeigt für diesen Wert anstatt "grün" dann gr�n an

      speichere mit grün,grün,grün,grün,grün,gr�n,1

      Bei MySQL hatte ich hier nie Probleme.
      Was passiert hier denn?

      vielen Dank und viele Grüße
      hawk

      1. Hi nochmals,

        ich habs auf php.net gelesen das strtolower keine Umlaut umwandelt.
        man soll mb_strtolower nehmen

        mb_strtolower("grün",'UTF-8');

        Ich frage mich nur warum dies dann aber bei MySQL ging?

        1. Hi!

          ich habs auf php.net gelesen das strtolower keine Umlaut umwandelt.

          Doch, nur keine UTF-8-kodierten. Die Stringfunktionen interpretieren alles nach ISO-8859-1. Da wird dann aus einem ü (C3BC) eben ein 㼠(E3BC).

          Ich frage mich nur warum dies dann aber bei MySQL ging?

          Geht nicht, es wird aber keine Fehlermeldung erzeugt, nur eine Warnung (abzufragen mit SHOW WARNINGS). Im Feld landet auch nicht das was du erhoffst.

          Lo!

          1. Hallo dedlfix,

            vielen Dank für deine Hilfe.
            Ich habe jetzt alle relevanten Stellen mit der MB Funktion ersetzt.
            Jetzt klappt es. vielleicht ist es mir vorher wirklich nicht aufgefallen bei MySQL

            Ich habe mal noch etwas anderes. Ich möchte ungern einen zweiten Thread aufmachen.

            Bei MySQL gibt es ja INSERT IGNORE... Damit kann man z.b. UNIQUE CONTRAINTS bzw. doppelte Eingaben verhindern. bzw. es gibt keine Fehlermeldung wenn die Unique Spalte verletzt wird.
            Bei Postgres gibt es das nicht.

            Ich habe nun den Fall gehabt (hier mit dem Wert "grün") in der Spalte "Farbe" Dieser Wertr darf nur einmal vorkommen.
            Ich verhindere zwar mit Javascript das man den gleichen Wert nochtmals speichern kann. Jedoch, wenn jemand im Browser auf F5 oder Refresh klickt, kann trotzdem ein Fehler auftreten.

            Wie könnte man bei PG dies abfangen?
            Vielleicht vor dem Insert immer zuerst einen Select machen und prüfen ob dieser Wert schon da ist?

            vielen Dank und viele Grüße
            hawk

            1. Hi,

              Bei MySQL gibt es ja INSERT IGNORE... Damit kann man z.b. UNIQUE CONTRAINTS bzw. doppelte Eingaben verhindern.

              Ein Unique Constraint ist nichts, was man „verhindern“ will.
              Informiere dich bitte erst mal, was dieser Begriff bedeutet.

              Ich habe nun den Fall gehabt (hier mit dem Wert "grün") in der Spalte "Farbe" Dieser Wertr darf nur einmal vorkommen.
              Ich verhindere zwar mit Javascript das man den gleichen Wert nochtmals speichern kann. Jedoch, wenn jemand im Browser auf F5 oder Refresh klickt, kann trotzdem ein Fehler auftreten.

              Wie könnte man bei PG dies abfangen?

              Mit einem Unique Constraint bzw. Unique Index.

              MfG ChrisB

              --
              RGB is totally confusing - I mean, at least #C0FFEE should be brown, right?
            2. Hallo,

              Bei MySQL gibt es ja INSERT IGNORE... Damit kann man z.b. UNIQUE CONTRAINTS bzw. doppelte Eingaben verhindern. bzw. es gibt keine Fehlermeldung wenn die Unique Spalte verletzt wird.
              Bei Postgres gibt es das nicht.

              Ich habe nun den Fall gehabt (hier mit dem Wert "grün") in der Spalte "Farbe" Dieser Wertr darf nur einmal vorkommen.
              Wie könnte man bei PG dies abfangen?

              indem Dein Anwendungscode damit rechnet, dass dieser Fehler auftritt und darauf angemessen reagiert. Bei MySQL scheinst Du solche Anweisungen "still" ignoriert zu haben. Falls das genügt, dann reagiere ganz genauso auf durchaus erwartete Fehler, die PostgreSQL Dir meldet - ung ignoriere sie auch hier.

              Freundliche Grüße

              Vinzenz

              1. Hallo Vinzenz,

                Danke für deine Hilfe.

                indem Dein Anwendungscode damit rechnet, dass dieser Fehler auftritt und darauf angemessen reagiert. Bei MySQL scheinst Du solche Anweisungen "still" ignoriert zu haben. Falls das genügt, dann reagiere ganz genauso auf durchaus erwartete Fehler, die PostgreSQL Dir meldet - ung ignoriere sie auch hier.

                Das war ja meine eigentliche Frage. Es gibt ja bei Postgres kein "IGNORE"
                Wie kann man bei Postgres solch ein "IGNORE" nachbauen?
                Mir fällt momentan nur ein; vor dem Insert ein Select zu machen ob es die entsprechende ID schon gibt und wenn nicht ein Insert.

                vielen Dank und viele Grüße
                hawk

                1. Hi!

                  Wie kann man bei Postgres solch ein "IGNORE" nachbauen?

                  Man läuft einfach in die Unique-Constraint-Verletzung rein und ignoriert dann gezielt diesen Fehler. Alle anderen behandelt man wie üblich.

                  Mir fällt momentan nur ein; vor dem Insert ein Select zu machen ob es die entsprechende ID schon gibt und wenn nicht ein Insert.

                  Sowas ist schlecht. Zwischen Select und Insert kann ein anderer bereits erfolgreich ein Insert getätigt haben. Und dann bekommst du sowieso den oben genannten Fehler. Also bau es gleich wie oben vorgeschlagen auf.

                  Lo!

                  1. Hi dedlfix,

                    danke dir für den Hinweis.

                    Man läuft einfach in die Unique-Constraint-Verletzung rein und ignoriert dann gezielt diesen Fehler. Alle anderen behandelt man wie üblich.

                    Hmm,
                    Meinst du das ich dann den bisherigen Insert in einen Try & Catch Block einbaue?

                    $dbInsertPapercolor = $DBO->prepare("INSERT  INTO papercolor (papercolor, languageid, textid) VALUES (:papercolor,:languageid,:textid)");
                    $dbInsertPapercolor->bindParam(':papercolor', $papercolor);
                    $dbInsertPapercolor->bindParam(':languageid', $userlanguageID);
                    $dbInsertPapercolor->bindParam(':textid', $textID);
                    $dbInsertPapercolor->execute();

                    Wie aber gezielt nur die Unique Contraint Verletzung ignorieren?

                    Dies wäre ja die Fehlermeldung OHNE Catch:
                    Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[23505]: <br />
                    Unique violation: 7 FEHLER: doppelter Schlüsselwert verletzt Unique-Constraint

                    vielen Dank und viele Grüße
                    hawk

                    1. Hi!

                      Man läuft einfach in die Unique-Constraint-Verletzung rein und ignoriert dann gezielt diesen Fehler. Alle anderen behandelt man wie üblich.
                      Meinst du das ich dann den bisherigen Insert in einen Try & Catch Block einbaue?

                      Da steht er doch sowieso schon für die normale Fehlerbehandlung, oder etwa nicht?

                      Wie aber gezielt nur die Unique Contraint Verletzung ignorieren?

                      Zunächst feststellen, wie man den Fehler erkennt. Dazu gibt es sicherlich eindeutige Daten in den Eigenschaften des Exception-Objekts.

                      Dies wäre ja die Fehlermeldung OHNE Catch:
                      Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[23505]: <br />
                      Unique violation: 7 FEHLER: doppelter Schlüsselwert verletzt Unique-Constraint

                      Als Programm interessiert nicht der Text, der für den Programmierer/Administrator bestimmt ist. Ein Programm arbeitet leichter mit (Roh-)Daten, also such dir diese. Die wichtigste Vorgehensweise dafür ist, var_dump() auf alles anzuwenden, was nicht bei drei ... vom Garbage Collector weggeräumt wurde.

                      Lo!

      2. Hi!

        das Problem liegt bei "strtolower($_POST['addvalues'])". Ich möchte in einer Spalte alles in Kleinbuchstaben haben.
        Die Kontrollausgabe im Browser zeigt für diesen Wert anstatt "grün" dann gr�n an

        Schau dir Bytewerte an, nicht das was irgendwelche Systeme noch dreimal uminterpretieren und irgendwann zu einem Zeichen auf dem Bildschirm machen. bin2hex() oder einfacher urlencode() lassen sich dafür verwenden.

        Bei MySQL hatte ich hier nie Probleme.
        Was passiert hier denn?

        Das kann man dann zu erraten versuchen, wenn man nicht nur Fragezeichen zu sehen bekommt. Vielleicht ist dir der Fehler vorher nur nie aufgefallen.

        Lo!