Bademeister: Zugriffsfehler bei Output in ein File

Hi.

Ich habe ein akutes Problemchen und hoffe auf Hilfe von den MySQL-Fachleuten.

Vorneweg: Das Problem ist gerade bei der Arbeit an einer MySQL5-Datenbank aufgetreten, und zwar an einem (Uni-)Rechner, an dem ich jetzt gerade nicht mehr sitze. Ich versuche, das Problem bestmoeglich zu schildern, exakte Details, falls benoetigt, kann ich evtl. in Kuerze nachreichen.

Ein Select-Befehl wird von einer Shell aus augefuehrt und funktioniert zunaechst einwandfrei. Um nun das Ergebnis formatiert in ein Outputfile zu schreiben, wird das Statement um

INTO OUTFILE 'filename.csv'
(und die dazugehoerigen Details - Angabe von Feld- und Zeilentrenner) erweitert.

Nun bekommen wir einen Fehler:

ERROR 1045: Access denied for user '....'@'......' using password....;

Erste Frage ist: Welcher Access zu was ist genau denied? Das Outputfile existiert und ist world-writeable. Die Fehlermeldung liest sich ohnehin so, als sei nicht der Zugang zum File, sondern der Zugang zum MySQL-Server denied. Aber wir haben ja bereits eine laufende Verbindung zum Server und es tritt auch nicht auf, wenn das Output-File nicht angegeben ist.

Zweite Frage: Gibt es einen "Workaround"? Also eine andere Methode, von der Shell aus die Daten (CSV-formatiert) in ein File zu schreiben?

Wir haben den Datenbank-Administrator kontaktiert, erwarten aber keine Antwort vor Montag morgen. Kann irgendjemand helfen?

Vielen Dank und Gruesse
der Bademeister

  1. Hello,

    INTO OUTFILE 'filename.csv'
    (und die dazugehoerigen Details - Angabe von Feld- und Zeilentrenner) erweitert.

    Nun bekommen wir einen Fehler:

    ERROR 1045: Access denied for user '....'@'......' using password....;

    Wo soll denn das Outfile erstellt werden?

    MWn hat MySQL aus Sicherheitsgründen inzwischen ein eigenes Verzeichnis für Outfiles eingeführt, das benutzt wird, wenn kein qualifizierter Pfad angegeben wurde.

    Ich gehe jetzt von einem Linux-Host aus, auf dem das Filesyytem liegt, da Du "Uni-Rechner" geschrieben hast.

    http://dev.mysql.com/doc/refman/5.1/en/windows-vs-unix.html

    Eventuell würde es also nützen, wenn Du einen qualifizierten Pfad ggf. unter Zuhilfename der Umgebungsvaribale für HOME desjenigen Users, der die Datenbank benutzt, angibst.

    Liebe Grüße aus dem schönen Oberharz

    Tom vom Berg

    --
    Nur selber lernen macht schlau
    http://bergpost.annerschbarrich.de
    1. Hi Tom.

      MWn hat MySQL aus Sicherheitsgründen inzwischen ein eigenes Verzeichnis für Outfiles eingeführt, das benutzt wird, wenn kein qualifizierter Pfad angegeben wurde.

      Danke. Das kann ich so bisher noch nicht ganz bestaetigen, aber ich habe unabahaengig davon in der Doku jedenfalls den (d.h. einen) Grund gefunden, warum unser Vorhaben zum Scheitern verurteilt war:

      "The SELECT ... INTO OUTFILE statement is intended primarily to let you very quickly dump a table to a text file on the server machine. If you want to create the resulting file on some client host other than the server host, you cannot use SELECT ... INTO OUTFILE. In that case, you should instead use a command such as mysql -e "SELECT ..." >  file_name to generate the file on the client host."

      Ich kann die Fehlermeldung aber immer noch nicht diesem Problem zuordnen, weil sie m.E. einen abgelehnten Zugang zum Datenbank-Server beschreibt. Ausserdem nimmt mir die oben beschriebene Alternative die Meoglichkeit, das den Output zu formatieren. Dennoch werde ich sie erstmal versuchen. Bei weiterem Misserfolg melde ich mich nochmal.

      Ich gehe jetzt von einem Linux-Host aus, auf dem das Filesyytem liegt, da Du "Uni-Rechner" geschrieben hast.

      Ja, es ist ein Linux-Host. Viel mehr weiss ich aber aus dem Kopf auch nicht - wir haben nur von einem externen Windows-Rechner via Exceed zugegriffen und dann ueber eine Linux-Shell den MySQL-Monitor laufen lassen.

      Danke, viele Gruesse,
      der Bademeister

      1. Hello Bademeister,

        MWn hat MySQL aus Sicherheitsgründen inzwischen ein eigenes Verzeichnis für Outfiles eingeführt, das benutzt wird, wenn kein qualifizierter Pfad angegeben wurde.

        Danke. Das kann ich so bisher noch nicht ganz bestaetigen, aber ich habe unabahaengig davon in der Doku jedenfalls den (d.h. einen) Grund gefunden, warum unser Vorhaben zum Scheitern verurteilt war:

        "The SELECT ... INTO OUTFILE statement is intended primarily to let you very quickly dump a table to a text file on the server machine. If you want to create the resulting file on some client host other than the server host, you cannot use SELECT ... INTO OUTFILE. In that case, you should instead use a command such as mysql -e "SELECT ..." >  file_name to generate the file on the client host."

        Es handelt sich wohl auch eher um diese Einschränkung:

        The SELECT ... INTO OUTFILE 'file_name' form of SELECT writes the selected rows to a file. The file is created on the server host, so you must have the FILE privilege to use this syntax. file_name cannot be an existing file, which among other things prevents files such as /etc/passwd and database tables from being destroyed. As of MySQL 5.0.19, the character_set_filesystem  system variable controls the interpretation of the file name

        Ideen zur Lösung:

        1. Die Datei darf noch nicht bestehen
        2. im angegeben Verzeichnis muss der aktive User schreiben dürfen
           (oder ist es doch der MySQL-Server?)
        3. Das FILE-Recht muss für den User gesetzt sein im MySQL-Rechtesystem
           (was dann doch wieder auf den User hindeutet, der im Verzeichnis schreiben dürfen muss)

        Liebe Grüße aus dem schönen Oberharz

        Tom vom Berg

        --
        Nur selber lernen macht schlau
        http://bergpost.annerschbarrich.de
        1. Es handelt sich wohl auch eher um diese Einschränkung:

          The SELECT ... INTO OUTFILE 'file_name' form of SELECT writes the selected rows to a file. The file is created on the server host, so you must have the FILE privilege to use this syntax. file_name cannot be an existing file, which among other things prevents files such as /etc/passwd and database tables from being destroyed. As of MySQL 5.0.19, the character_set_filesystem  system variable controls the interpretation of the file name

          Ja, im Grunde schon. Mir ist in unserer Konstellation leider nicht klar, was der Server-Host ist. Daher habe ich mich inzwischen dazu entschlossen, dieses Vorhaben als gescheitert anzusehen und zu der Alternative ueberzugehen, das Schreiben ins Output-File von der Command-Line aus zu machen. Siehe mein letztes Posting.

        2. Hi!

          1. im angegeben Verzeichnis muss der aktive User schreiben dürfen
               (oder ist es doch der MySQL-Server?)
          2. Das FILE-Recht muss für den User gesetzt sein im MySQL-Rechtesystem
               (was dann doch wieder auf den User hindeutet, der im Verzeichnis schreiben dürfen muss)

          Bitte nicht die MySQL-User und die Unix-User durcheinanderbringen. Soweit ich weiß gibt es keinen Mechanismus, der die einen auf die anderen mappt. Das FILE-Recht muss der MySQL-User haben, die Schreibrechte im Dateisystem der Unix-User, unter dem der MySQL-Server läuft.

          Lo!

          1. Hello,

            1. im angegeben Verzeichnis muss der aktive User schreiben dürfen
                 (oder ist es doch der MySQL-Server?)
            2. Das FILE-Recht muss für den User gesetzt sein im MySQL-Rechtesystem
                 (was dann doch wieder auf den User hindeutet, der im Verzeichnis schreiben dürfen muss)

            Bitte nicht die MySQL-User und die Unix-User durcheinanderbringen. Soweit ich weiß gibt es keinen Mechanismus, der die einen auf die anderen mappt. Das FILE-Recht muss der MySQL-User haben, die Schreibrechte im Dateisystem der Unix-User, unter dem der MySQL-Server läuft.

            Das habe ich eigentlich auch befürchtet.

            Die MySQL-User sollten also tunlichst in einer gemeinsamen User-Gruppe mit dem MySQL-Server sein. Dann können sie in ihrem Home-Dir ein Verzeichnis anlegen, auf das die Gruppe "MySQL-User" rwx-Rechte hat. Es sollte dann möglich sein, dass der MySQL-Server dort schreibt. Da er sich selber davor zurückhält, vorhandene Dateien zu überschreiben, könnte dann auch kein anderer User der Gruppe dort etwas kaputt machen.

            Liebe Grüße aus dem schönen Oberharz

            Tom vom Berg

            --
            Nur selber lernen macht schlau
            http://bergpost.annerschbarrich.de
            1. Hi!

              Die MySQL-User sollten also tunlichst in einer gemeinsamen User-Gruppe mit dem MySQL-Server sein. Dann können sie in ihrem Home-Dir ein Verzeichnis anlegen, auf das die Gruppe "MySQL-User" rwx-Rechte hat. Es sollte dann möglich sein, dass der MySQL-Server dort schreibt. Da er sich selber davor zurückhält, vorhandene Dateien zu überschreiben, könnte dann auch kein anderer User der Gruppe dort etwas kaputt machen.

              Was hält dann die anderen User der Gruppe davon ab, direkt und ohne den MySQL-Server zu bemühen in den mysql-Verzeichnissen der anderen User zu schreiben? Es ist jedenfalls nicht das w-Bit, das der fremde User aufgrund seiner Gruppenzugehörigkeit mitbringt.

              Lo!

              1. Hello,

                Was hält dann die anderen User der Gruppe davon ab, direkt und ohne den MySQL-Server zu bemühen in den mysql-Verzeichnissen der anderen User zu schreiben? Es ist jedenfalls nicht das w-Bit, das der fremde User aufgrund seiner Gruppenzugehörigkeit mitbringt.

                Du hast Recht. Das geht nicht so einfach. Ich muss nochmal in der Erinnerung graben, wie die Lösung dafür aussah. Neu anlegen soll möglich sein, ändern und löschen aber nicht...

                Bei Novell geht das alles ;-)
                Aber ich meine, es gab auch für reine Linux-Hosts eine Lösung, wenn auch ggf. mit ACL oder Arributen.

                Liebe Grüße aus dem schönen Oberharz

                Tom vom Berg

                --
                Nur selber lernen macht schlau
                http://bergpost.annerschbarrich.de
                1. Hallo Tom,

                  Du hast Recht. Das geht nicht so einfach. Ich muss nochmal in der Erinnerung graben, wie die Lösung dafür aussah. Neu anlegen soll möglich sein, ändern und löschen aber nicht...

                  Bei Novell geht das alles ;-)

                  bei NTFS und Windows-NT-Abkömmlingen auch. *duck und weg*

                  Freundliche Grüße

                  Vinzenz

                  1. Hello,

                    Du hast Recht. Das geht nicht so einfach. Ich muss nochmal in der Erinnerung graben, wie die Lösung dafür aussah. Neu anlegen soll möglich sein, ändern und löschen aber nicht...

                    Bei Novell geht das alles ;-)

                    bei NTFS und Windows-NT-Abkömmlingen auch. *duck und weg*

                    Aber für Linux fällt Dir auch nix ein, oder?

                    Ich hatte so in Erinnerung, dass man da was mit einem Root-Flag (Attribut) auf das Verzeichnis machen konnte.

                    Liebe Grüße aus dem schönen Oberharz

                    Tom vom Berg

                    --
                    Nur selber lernen macht schlau
                    http://bergpost.annerschbarrich.de
      2. Wattn Stress.

        Das schreiben des Ergebnisses in ein File klappt nun auf Client-Seite mit dem Shell-Command

        mysql ..... -e "select ..."

        Dazu habe ich noch mehrere Fragen, die mir die Doku nicht beantwortet hat:

        1.: Ist es moeglich, statt des Statements einen Dateinamen einer SQL-Datei zu uebergeben, die ausgefuehrt werden soll?
        2.: Kann man das Format der Ausgabe individuell vorgeben? (XML-Ausgabe kann man laut Doku vorgeben, aber CSV nicht).

        Und noch eine etwas andere Frage: Vorher beim Einlesen eines SQL-Files von geschaetzter Groesse von 4MB bekamen wir einen Fehler, dass die Groesse des Inputs groesser als MAX_ALLOWED_PACKET sei. Der Default-Wert davon ist 16MB. Sogar nach hochsetzten des Wertes auf ca. 100MB kam derselbe Fehler. Wir haben das Zeug einlesen koennen, nachdem wir es gefuenftelt haben und jeweils 10000 Datensaetze auf einmal eingetragen haben. Schon 20000 Datensaetze (ca. 1.5MB) wurden mit dem Verweis auf MAX_ALLOWED_PACKET abgelehnt. Warum?

        Danke, viele Gruesse,
        der Bademeister

        1. Hallo,

          Und noch eine etwas andere Frage: Vorher beim Einlesen eines SQL-Files von geschaetzter Groesse von 4MB bekamen wir einen Fehler, dass die Groesse des Inputs groesser als MAX_ALLOWED_PACKET sei. Der Default-Wert davon ist 16MB. Sogar nach hochsetzten des Wertes auf ca. 100MB kam derselbe Fehler. Wir haben das Zeug einlesen koennen, nachdem wir es gefuenftelt haben und jeweils 10000 Datensaetze auf einmal eingetragen haben. Schon 20000 Datensaetze (ca. 1.5MB) wurden mit dem Verweis auf MAX_ALLOWED_PACKET abgelehnt. Warum?

          1 MB wären vermutlich durchgegangen. :-)

          Steht im Archiv, steht auch im Handbuch, die Werte sind server- wie clientseitig hochzusetzen.

          Kannst Du nur von localhost aus zugreifen?
          Wenn Du remote zugreifen darfst, dann könntest Du den MySQL Query Browser verwenden. Dieser hat eine Option, das Abfrageergebnis im CSV-Format zu speichern - auf dem Client natürlich.

          Freundliche Grüße

          Vinzenz

          1. 1 MB wären vermutlich durchgegangen. :-)

            Steht im Archiv, steht auch im Handbuch, die Werte sind server- wie clientseitig hochzusetzen.

            Hui, danke. Ich weiss, dass meine Handbuch-Suche vorher leider nicht sehr intensiv war. Da wir heute etwas unter Zeitdruck sind, hab ichs mir leicht gemacht und gleich hier gefragt. Vielen Dank, dann ist mir das schon mal klar.

            Kannst Du nur von localhost aus zugreifen?

            (Bisher) Ja. Leider. Vielleicht kann ich klaeren, dass wir remote-Zugriff bekommen. Danke jedenfalls fuer den wertvollen Tipp mit dem Query-Browser.

            Viele Gruesse,
            der Bademeister

        2. Hi!

          mysql ..... -e "select ..."
          1.: Ist es moeglich, statt des Statements einen Dateinamen einer SQL-Datei zu uebergeben, die ausgefuehrt werden soll?

          Klar, so wie du das Ergebnis "wegpipen" kannst (>), kannst du auch anderen Daten "hinpipen" (<). Steht aber als Beispiel im Handbuchkapitel zu mysql.

          2.: Kann man das Format der Ausgabe individuell vorgeben? (XML-Ausgabe kann man laut Doku vorgeben, aber CSV nicht).

          Dafür stehen dir alle Möglichkeiten des SELECT-Statements zur Vefügung. Wenn das was du willst nicht im Handbuch beschrieben ist, ist es nicht implementiert. Als Ersatz kannst du dann immer noch mit Stringfunktionen die Ausgabe zurechtzimmern. CSV ist problemlos möglich, von XML hab ich bisher noch nichts gelesen. Wo genau lasest du das?

          Und noch eine etwas andere Frage: Vorher beim Einlesen eines SQL-Files von geschaetzter Groesse von 4MB bekamen wir einen Fehler, dass die Groesse des Inputs groesser als MAX_ALLOWED_PACKET sei. Der Default-Wert davon ist 16MB. Sogar nach hochsetzten des Wertes auf ca. 100MB kam derselbe Fehler. Wir haben das Zeug einlesen koennen, nachdem wir es gefuenftelt haben und jeweils 10000 Datensaetze auf einmal eingetragen haben. Schon 20000 Datensaetze (ca. 1.5MB) wurden mit dem Verweis auf MAX_ALLOWED_PACKET abgelehnt. Warum?

          War das ein großes Multi-INSERT-Statement oder pro Datensatz ein INSERT?

          Lo!

          1. Hi dedlfix.

            mysql ..... -e "select ..."
            1.: Ist es moeglich, statt des Statements einen Dateinamen einer SQL-Datei zu uebergeben, die ausgefuehrt werden soll?

            Klar, so wie du das Ergebnis "wegpipen" kannst (>), kannst du auch anderen Daten "hinpipen" (<). Steht aber als Beispiel im Handbuchkapitel zu mysql.

            Prima. Ich verstehe zwar nicht ganz, warum das funktoniert, wenn das Statement ohne Parameterangabe (-e o.ae.) einfach reingepiped wird, aber wenn es funktioniert, ist mir auch einigermassen egal, warum :-)

            2.: Kann man das Format der Ausgabe individuell vorgeben? (XML-Ausgabe kann man laut Doku vorgeben, aber CSV nicht).

            Dafür stehen dir alle Möglichkeiten des SELECT-Statements zur Vefügung.

            Wieder Prima. Mir war nicht klar, dass, wie inzwischen beobachtet, die Daten standardmaessig Leerzeichen-separiert zurueckgegeben werden. Dann ist das CSV-Format natuerlich problemlos moeglich.

            Und noch eine etwas andere Frage: Vorher beim Einlesen eines SQL-Files von geschaetzter Groesse von 4MB bekamen wir einen Fehler, dass die Groesse des Inputs groesser als MAX_ALLOWED_PACKET sei. Der Default-Wert davon ist 16MB. Sogar nach hochsetzten des Wertes auf ca. 100MB kam derselbe Fehler. Wir haben das Zeug einlesen koennen, nachdem wir es gefuenftelt haben und jeweils 10000 Datensaetze auf einmal eingetragen haben. Schon 20000 Datensaetze (ca. 1.5MB) wurden mit dem Verweis auf MAX_ALLOWED_PACKET abgelehnt. Warum?

            War das ein großes Multi-INSERT-Statement oder pro Datensatz ein INSERT?

            Ein Multi-Insert. Das duerfte wohl einen entscheidenden Unterschied gemacht haben, jetzt, wo ich weiss, dass die serverseitige MAX_ALLOWED_PACKET-Groesse ueberschritten wurde. Ich hatte unter Packet-Groesse zunaechst die Datei-Groesse beim Einlesen vermutet. Aber mit Vinzenz' Hilfe weiss ich nun ohnehin, wo das Problem lag.

            Ich werde die Dinge heute noch alle ausprobieren und bin dafuer dann nun mal wieder ne Weile weg...

            Vielen Dank Dir und auch Vinzenz und Tom, ich bin auf jeden Fall schon mal viel weiter.

            Viele Gruesse,
            der Bademeister

        3. Hallo,

          1.: Ist es moeglich, statt des Statements einen Dateinamen einer SQL-Datei zu uebergeben, die ausgefuehrt werden soll?

          siehe dedlfix' Antwort.

          2.: Kann man das Format der Ausgabe individuell vorgeben? (XML-Ausgabe kann man laut Doku vorgeben, aber CSV nicht).

          individuell nicht, aber Du hast im Batchmodus, den Du entweder mit

          -b

          oder durch Einlesen der Statements aus einer Datei, was Du ja vorhast, bekommst, nahezu schon tabulatorgetrenntes CSV-Format. Vier spezielle Zeichen sind maskiert, siehe Handbuch, Option --raw.

          Folgendes müsste doch ausreichen (ich hoffe, ich habe nichts übersehen):

          Für jede Zeile
              Entferne das Zeilenende
              Trenne am Tabulator
              Für jeden Eintrag
                  Verdopple das Begrenzungszeichen
                  Entferne die Transportsicherung bei maskierten Zeichen
                  Packe (wenn nötig) den Eintrag in Begrenzungszeichen [1]
              Ende Für
              Verbinde alle Einträge mit dem gewünschten Feldtrennzeichen
              Hänge das gewünschte Zeilenendezeichen an
          Ende Für

          sollte nicht zu schwer umzusetzen sein. Muss ja nicht Shellskript sein, könnte auch in $programmiersprache gelöst sein, könnte aber von STDIN lesen und nach STDOUT ausgeben, damit Du die Ausgabe von mysql einfach durchpipen kannst.

          Freundliche Grüße

          Vinzenz

  2. Hallo,

    Ein Select-Befehl wird von einer Shell aus augefuehrt und funktioniert zunaechst einwandfrei. Um nun das Ergebnis formatiert in ein Outputfile zu schreiben, wird das Statement um

    INTO OUTFILE 'filename.csv'
    (und die dazugehoerigen Details - Angabe von Feld- und Zeilentrenner) erweitert.

    Nun bekommen wir einen Fehler:
    ERROR 1045: Access denied for user '....'@'......' using password....;

    was ist die Ausgabe von

    SHOW GRANTS FOR CURRENT_USER

    Freundliche Grüße

    Vinzenz

    1. Hi Vinzenz.

      was ist die Ausgabe von

      SHOW GRANTS FOR CURRENT_USER

      +----------------------------------------------------------------------------+
      | Grants for ...@%                                                           |
      +----------------------------------------------------------------------------+
      | GRANT USAGE ON *.* TO '...'@'%' IDENTIFIED BY PASSWORD '...'               |
      | GRANT ALL PRIVILEGES ON ....* TO '...'@'%' WITH GRANT OPTION             |
      +----------------------------------------------------------------------------+

      Viele Gruesse,
      der Bademeister

      1. Hi!

        | GRANT ALL PRIVILEGES ON ....* TO '...'@'%' WITH GRANT OPTION             |

        Steht das erste ... für einen Datenbanknamen? FILE ist ein globales Recht, das brauchst du für ON *.*

        Lo!