MYSQL_ROW und Nullterminierung



  • Hi!

    ich möchte aus einer datenbank die ip-adressen von servern auslesen und dann jeweils eine http verbindung aufbauen. funktioniert auch alles soweit (momentan lese ich die server ip aus einer variable nicht aus der datenbank)

    jetzt die frage: welchen datentyp gibt mir MYSQL_ROW zurück? (konnte ich nirgends finden.)
    außerdem ist dieser string nicht nullterminiert und daher denke ich stürzt mir das programm auch ab wenn ich inet_addr row[0] übergebe..

    auszug aus der mysql seite

    Eine typsichere Darstellung einer Datenzeile. Sie ist zurzeit als Array gezählter Byte-Strings implementiert. (Diese dürfen nicht als auf null endende Strings behandelt werden, wenn die Feldwerte Binärdaten enthalten könnten, da solche Werte intern Nullbytes enthalten können.) Die Zeilen werden mit mysql_fetch_row() abgerufen.

    mal abgesehen vom datentyp der mysql_row ist.. kann ich dem einfach die nullterminierung mit "\0" anhängen??

    //GET SERVERS
        MYSQL *conn, mysql;
        MYSQL_RES *mysql_result;
        MYSQL_ROW  row;
    
    //....
    //READ OUT SERVERS IP
        sqlquery_servers = "SELECT f_ip FROM t_servers";
    
        query_result = mysql_query(conn, sqlquery_servers.c_str());
    
        if (query_result !=0) {
            std::cout << mysql_error(conn) << std::endl;
        return 1;
        }
    
        mysql_result = mysql_store_result(conn);
        while ( ( row = mysql_fetch_row(mysql_result)) != NULL ) {
            std::cout << "result: " << row[0] << std::endl;
        }
    
        //CLOSE CONNECTION
        mysql_close(conn);
    
    //.....
    //Verbindungsaufbau:
                //addr auf null setzen
                memset(&addr, 0, sizeof(SOCKADDR_IN));
    
                //und wieder füllen
                addr.sin_family = AF_INET;
                addr.sin_port = htons(80);
                addr.sin_addr.s_addr = inet_addr(server1); //sollte dann aus der DB gelesen werden....
    
                //Verbindung aufbauen
                rc = connect(new_socket, (SOCKADDR*)&addr, sizeof(SOCKADDR));
    
                if(rc == SOCKET_ERROR) {
                    errormsg = "Fehler: Verbindungsaufbau fehlgeschlagen, Fehler Code: ";
                    errormsg += WSAGetLastError();
    
                    closesocket(new_socket);
                    WSACleanup();
    
                }
    

    inet_Addr erwartet ja einen nullterminierten string...

    PS.: wer kann Nullterminierung in 4 Wörtern erklären? der bekommt von mir drei kugeln eis (natürl. vom italiener 😉 )


  • Administrator

    1. Was hat das mit Standard C++ zu tun?
    2. Steht doch alles in der MySQL Dokumentation (sogar mit Beispiel!):
    http://dev.mysql.com/doc/refman/5.5/en/mysql-fetch-row.html
    3. Nullterminierung: Null im letzten Zeichen.
    Oder ein wenig verständlicher:
    Ein C String hat im letzten Zeichen den Wert 0 und ist dadurch nullterminiert. Dadurch kann man beliebig grosse Strings verwalten. Wenn man wirklich einmal die grösse wissen möchte, dann zählt man einfach so lange die Zeichen, bis das Zeichen mit dem Wert 0 kommt.
    http://en.wikipedia.org/wiki/C_string

    Grüssli



  • mpf ich bin ja auch blöd.. ich sollte in der while schleife auch erstmal die durchlaufenen werte in einer variable speichern...

    zu1.: jetzt ist das problem standard c++ 🙂
    zu2.: das beispiel hatte ich klar schon gesehen, war und ist aber in meinem fall ja nicht relevant
    zu3.: noch mehr zu lesen, hrrr 🙂

    while ( ( row = mysql_fetch_row(mysql_result)) != NULL ) {
    
            std::cout << "result: " << row[0] << std::endl;
    
            char test[10];
            int i;
            //for(i=0; i < 3; i++) {
            //    test[i] = row[0];
            //}
            //anstatt der for schleife ist es am einfachsten wenn ich
            strcat(test, row[0]); nutze...
    
        }
    
        std::cout << test[0] << std::endl; //not declared
    

    was hab ich hier übersehen dass die variable test nicht deklariert ist?


  • Administrator

    Ich weiss nicht, wo dein Problem liegt. Es steht alles in der Dokumentation. Du gehst über alle Reihen ( mysql_fetch_row ). In jeder Reihe steht eine IP und das in der ersten Kolonne. Die Anzahl Kolonnen kannst du herausbekommen mit mysql_num_fields . Mit mysql_fetch_lengths holst du die verschiedenen Längen der Daten in den Kolonnen. Was brauchst du noch?

    Grüssli



  • @edit von taurus:
    Die Variable Test wird innerhalb der while Schleife deklariert und am Ende des Blocks der Schleife zerstört.



  • so.. was meint ihr ? sieht gut aus oder?

    char* test[10];
        int i = 0;
        while ( ( row = mysql_fetch_row(mysql_result)) != NULL ) {
    
            std::cout << "result: " << row[0] << std::endl;
            test[i] = row[0];
        i++;
    
        }
        std::cout << test[0] << std::endl;[code]
    


  • so, danke euch allen für eure hilfe vor allem blub der mich da indirekt auf eine idee gebracht hat 😉

    noch was (grundlagen) ich kann ja problemlos
    char* test[num_rows - 1];
    schreiben?

    unsigned int i = 0;
        unsigned int num_rows;
    
        num_rows = mysql_num_rows(mysql_result);
        char* test[num_rows - 1];
        while ( ( row = mysql_fetch_row(mysql_result)) != NULL ) {
            test[i] = row[0];
            i++;
        }
    


  • Nein, kannst du nicht einfach so schreiben.

    1. new benutzen
    2. vector benutzen
    3. tr1::array<T> benutzen

    Sicher dass dir nur die Grundlagen in Sachen Gültigkeitsbereiche fehlen?



  • vektoren will ich ja grade vermeiden weil inet_addr char verlangt!

    ja mir fehlen noch mehr grundlagen als die gültigkeitsbereche (morgen gehts ab zur bücherei 🙂 )

    was ist denn 3) tr1::array<T> ??

    num_rows = mysql_num_rows(mysql_result) - 1;
        char* test[num_rows];
    

    sollte doch aber i.O. sein?

    bzw. ist an dem code generell was falsch? die datentypen passen doch.. und dem char array fütter ich dann jeweils einen wert zu.. passt doch?


  • Administrator

    Ausser das dein Code kein Standard C++ ist. Die grösse eines Arrays auf dem Stack muss zur Kompilezeit bekannt sein.
    Wenn du nun sagst, dass es bei dir kompiliert, dann verwendest du den GCC. Der unterstützt dies, ist aber eine Erweiterung von diesem Kompiler und kommt von C99.

    Im übrigen kann man auch einen std::vector mit inet_addr verwenden:

    std::vector<char> vec;
    vec.push_back('1');
    vec.push_back('2');
    vec.push_back('7');
    vec.push_back('.');
    vec.push_back('0');
    vec.push_back('.');
    vec.push_back('0');
    vec.push_back('.');
    vec.push_back('1');
    vec.push_back('\0');
    
    unsigned long value = inet_addr(&vec[0]);
    

    Aber ehrlich gesagt, scheint dein Problem hier ganz allgemein in der Sprache zu liegen. Alle deine bisherigen Versuche waren ziemlicher Unsinn und entsprechen auch nicht der MySQL Dokumentation. Da bringt es irgendwie recht wenig, dir probieren das zu erklären, wenn dir alle Grundlagen fehlen. 😉

    Zwei Fragen hätte ich an dich:
    1. Was willst du überhaupt gesamthaft machen?
    2. Wie bist du auf die Idee gekommen, dass du dies mal schnell hopp hopp ohne C++ Kenntnisse durchführen kannst?

    Grüssli



  • Die grösse eines Arrays auf dem Stack muss zur Kompilezeit bekannt sein.

    kann ja demnach nicht funktionieren.. weil erst im nachhinnein klar ist wieviele datensätze es gibt...

    zu1: von mehreren servern eine datei abrufen und den inhalt in eine datenbank speichern...
    zu2: letztens nach einer party dachte ich mir "learning by doing" 😉

    *ironie* ok das projekt ist etwas groß... aber mit einem guten buch kann ich den misteriösen schmarn den ich da programmiert hab ausbessern.. sicher nicht der beste weg, aber praktisch lernt man doch immer am besten...

    Frage:

    MYSQL

    Diese Struktur ist ein Handle für eine einzelne Datenbankverbindung. Sie wird für fast alle MySQL-Funktionen benutzt. Bitte versuchen Sie nicht, eine Kopie einer MYSQL-Struktur anzulegen. Es ist nicht garantiert, dass eine solche Kopie benutzbar ist.

    was ist hier mit Kopie gemeint?


  • Administrator

    taurus schrieb:

    Frage:

    MYSQL

    Diese Struktur ist ein Handle für eine einzelne Datenbankverbindung. Sie wird für fast alle MySQL-Funktionen benutzt. Bitte versuchen Sie nicht, eine Kopie einer MYSQL-Struktur anzulegen. Es ist nicht garantiert, dass eine solche Kopie benutzbar ist.

    was ist hier mit Kopie gemeint?

    Eine Kopie eben. Wenn du mysql_connect aufrufst, erhälst du einen Zeiger auf ein MYSQL Objekt. Du sollst also nicht probieren von diesem Objekt, auf welches der Zeiger zeigt, eine Kopie zu erstellen. Also:

    MYSQL* connection = mysql_connect(...);
    MYSQL copy = *connection; // Pfui!
    

    Grüssli



  • ach na dann ists mir recht 😉

    man sollte übrigens nicht versuchen mysql_error einfach so in die datenbank zu schreiben (eigentlich weiß ich das ja.. aber warum ich nicht gleich auf escapen gekommen bin weiß ich nicht ;-))

    willste mal den kompletten source code sehn und mir sagen ob a) ichs besser bleiben lassen soll oder b)c und c++ nicht mischen sollte und endlich grundlagen lernen muss?



  • noch ne kleinigkeit 😉

    std::cout << "Starte Abfrage " << i + 1;
    

    ist ja erlaubt?



  • taurus schrieb:

    noch ne kleinigkeit 😉

    std::cout << "Starte Abfrage " << i + 1;
    

    ist ja erlaubt?

    Jah.. Warum sollte das nicht erlaubt sein?


Anmelden zum Antworten