Problem mit Datenbank-Klasse (MySQL)



  • Hallo zusammen.
    Ich versuche momentan für ein Projekt eine Datenbank-Klasse zu schreiben mit dem MySQL-Connector.
    Da ich auf eigene Faust nicht sehr weit gekommen bin habe ich mir folgende Anleitung angeschaut und das dann für mich selber nochmal implementiert.
    http://docstore.mik.ua/orelly/linux/sql/ch13_02.htm

    Konkret sieht das also bei mir jetzt so aus..
    MySQLConnection.h

    #include <mysql/mysql.h>
    #include <string>
    #include <string.h>
    #include "MySQLRes.h"
    
    using namespace std;
    
    #ifndef MYSQLCONNECTION_H
    #define	MYSQLCONNECTION_H
    
    class MySQLConnection {
    public:
        MySQLConnection(const char* _server, const char* _user, const char* _password, const char* _database, const char* _prefix);
        MySQLConnection(const MySQLConnection& orig);
        virtual ~MySQLConnection();
        void close();
        int getAffectedRows();
        const char *getError();
        bool isConnected();
        MYSQL_RES *query(string _query);
        MySQLRes *execute();
        bool prepareStatement(string _statement);
        string bindParam(string _id, string _value);
    private:
        int affectedRows;
        MYSQL mysql;
        MYSQL *connection;
        string statement;
    };
    
    #endif	/* MYSQLCONNECTION_H */
    

    MySQLRes.h

    #include <mysql/mysql.h>
    #include "MySQLRow.h"
    
    #ifndef MYSQLRES_H
    #define	MYSQLRES_H
    
    class MySQLRes {
    public:
        MySQLRes(MYSQL_RES *_result);
        MySQLRes(const MySQLRes& orig);
        virtual ~MySQLRes();
        void close();
        MySQLRow *getCurrentRow();
        int getRowCount();
        bool next();
    private:
        int rowCount;
        MYSQL_RES *result;
        MySQLRow *currentRow;
    };
    
    #endif	/* MYSQLRES_H */
    

    MySQLRow.h

    #include <mysql/mysql.h>
    #include <stdio.h>
    
    #ifndef MYSQLROW_H
    #define	MYSQLROW_H
    
    class MySQLRow {
    public:
        MySQLRow(MYSQL_RES *_result, MYSQL_ROW _fields);
        MySQLRow(const MySQLRow& orig);
        virtual ~MySQLRow();
        char *getField(int _index);
        int getFieldCount();
        bool isClosed();
        void close();
    private:
        MYSQL_RES *result;
        MYSQL_ROW fields;
    };
    
    #endif	/* MYSQLROW_H */
    

    Ein Aufruf sieht bei mir momentan so aus:

    this->db.prepareStatement("SELECT ID FROM Music WHERE Filepath=':path'");
                        this->db.bindParam("path", temp);
                        MySQLRes res = this->db.execute();
                        if (res.getRowCount() == 1) {                        
                            //blabla
                        }
    

    Dabei ist temp ein Dateipfad und bindParam ersetzt lediglich den entsprechenden Parameter im String mit temp (dort wird dann das escapen und filtern der Eingaben gemacht).
    Wenn ich es so benutze bekomme ich den Fehler das eine Konvertierung in einen non-scalar mache. Soweit klar.. Wenn ich jetzt aber *res nehme, also nen Pointer, bekomme ich beim Aufruf von getRowCount() die Meldung das es sich dabei um einen non-class type handelt. An sich ja auch logisch..

    Allerdings weiß ich jetzt überhaupt nicht wie ich das Problem gelöst bekomme.
    Wenn gewünscht poste ich natürlich auch die .cpp's

    MfG phost



  • Schau Dir nochmal an, wie man Zeiger verwendet!
    Entweder ist res ein Zeiger, dann verwende Ihn auch so. Oder res ist ein Objekt, aber dann musst Du die Rückgabe von MySQLConnection::execute dereferenzieren.



  • Naja im Prinzip glaube ich schon verstanden zu haben wie ein Zeiger funktioniert, allerdings bekomme ich nicht mehr als einen Zeiger. Dazu nochmal folgender Code...

    MYSQL_RES *MySQLConnection::query(string _query) {
        MYSQL_RES *res;
        int state;
        if (!this->isConnected()) {
            throw "Not connected to Database.";
        }
        state = mysql_query(this->connection, _query.c_str());
        if (state < 0) {
            throw getError();
        }
        res = mysql_store_result(this->connection);
        if (res == (MYSQL_RES *) NULL) {
            int fieldCount = mysql_field_count(this->connection);
            if (fieldCount != 0) {
                throw getError();
            } else {
                affectedRows = mysql_affected_rows(this->connection);
            }
            return (MYSQL_RES *) NULL;
        }
        return res;
    }
    
    MySQLRes MySQLConnection::execute() {
        MYSQL_RES *res = this->query(this->statement);
        return new MySQLRes(res);
    }
    

    Und laut Doku ist mysql_store_result wie folgt definiert:

    MYSQL_RES *mysql_store_result(MYSQL *mysql)
    

    Das heißt ich müsste wohl irgendwie "unterwegs" diesen Zeiger umwandeln in ein Objekt, allerdings weiß ich wie gesagt nicht wie. Weil wenn ich execute() wie jetzt dereferenziere komme ich damit auch nicht weiter..



  • - Schau Dir nochmal an, wie man sein Problem beschreibt!
    - Schau Dir nochmal an, wie man Zeiger verwendet!
    - Schau Dir nochmal an, wie man MySQL mit C++ verwendet



  • Und zusätzlich:

    - kein using namespace in Header Dateien
    - kein string.h inkludieren
    - keine Bezeichner, die mit _ (Underscore) beginnen
    - Header Guards zu Beginn der Headerdatei
    - Rule of 3 (5) berücksichtigt? Es gibt einen Copy-Konstruktor, aber keinen Zuweisungsoperator

    Edit:
    Und warum überall ein virtueller Destruktor?



  • Die virtuellen Destruktoren hat mir Netbeans immer automatisch erstellt..

    Ich habe jetzt nochmal ein wenig rumprobiert und habe es jetzt so hinbekommen das es funktioniert, vorrausgesetzt ich bekomme ein Result zurück. Wenn das nicht der Fall ist schmiert mein Programm hier ab:

    MySQLRes *MySQLConnection::execute() {
        MYSQL_RES res = *this->query(this->statement);    
        return new MySQLRes(&res);
    }
    

    Genauer gesagt in der hier zweiten Zeile.

    query sieht so aus:

    MYSQL_RES *MySQLConnection::query(string query) {
        MYSQL_RES *res;
        int state;
        if (!this->isConnected()) {
            throw "Not connected to Database.";
        }
        state = mysql_query(this->connection, query.c_str());
        if (state < 0) {
            throw getError();
        }
        res = mysql_store_result(this->connection);
        if (res == (MYSQL_RES *) NULL) {
            int fieldCount = mysql_field_count(this->connection);
            if (fieldCount != 0) {
                throw getError();
            } else {
                affectedRows = mysql_affected_rows(this->connection);
            }
            return (MYSQL_RES *) NULL;
        }
        return res;
    }
    

    Mittels Debugger habe ich bereits festgestellt das mir korrekt wie es sein soll in der drittletzten Zeile die NULL zurückgegeben wird..

    Meine Frage jetzt: Wie gehe ich damit am besten um? Weil soweit ich das verstanden habe wird mir damit ein Nullpointer zurückgegeben und mit dem kann dann wohl nicht richtig weitergearbeitet werden? Weil Nullpointer dereferenziert ist wohl böse?
    Bin aber über mehr Nachhilfe was Pointer angeht dankbar wenn ich das falsch verstanden habe.. Die Teile verwirren mich immer noch sehr -.-"

    Mit Headerguards sind wohl die Abfragen gemeint die verhindern sollen das eine Header-Datei mehrmals eingebunden wird?? Auch hier hat mir Netbeans das bereits so vorgefertigt, habe mir da selber bisher noch wenig Gedanken drüber gemacht muss ich gestehen^^
    Und wofür bräuchte ich jetzt zwingend noch einen Zuweisungsoperator??

    MfG



  • Schau Dir nochmal an, wie man Zeiger verwendet!



  • Könntest du mir eventuell mal nen Link geben wo es deiner Meinung nach gut beschrieben ist?
    Weil offensichtlich waren die Quellen die ich gefunden habe ja nicht gut genug, sonst würdest du mir den Hinweis ja kaum geben^^



  • phost schrieb:

    Könntest du mir eventuell mal nen Link geben wo es deiner Meinung nach gut beschrieben ist?

    Mir ist keiner bekannt.

    Weil offensichtlich waren die Quellen die ich gefunden habe ja nicht gut genug, sonst würdest du mir den Hinweis ja kaum geben^^

    Ich sehe hier nirgendwo Zweifel an deinen Quellen.



  • Naja ich habe mir bereits einiges über Zeiger durchgelesen aber habe wohl immer noch einen Fehler drin den ich nicht entdecken. Und da du sagst es liegt daran wie ich die Zeiger verwende fände ich es schön zu wissen wo genau mein Fehler ist und worin dieser besteht.
    Weil "aus eigener Kraft" komme ich nicht weiter. Außer vllt sinnlos rumzuprobieren aber gelernt habe ich dabei dann ja auch nichts^^



  • - Schau Dir nochmal an, wie man sein Problem beschreibt!
    - Schau Dir nochmal an, wie man MySQL mit C++ verwendet

    Aber du bist ja schon seit Wochen völlig lernresistent. Wie dein Grundproblem zu lösen ist, wurde dir hier schon am 31.8. gesagt. Den MySql C++ Connector per MySql C Connector nach zubauen ist Schwachsinn.

    Vielleicht trollst du ja sowieso nur ...



  • Ja die Idee das ich mir das selber alles zusammenschreibe habe ich jetzt tatsächlich verworfen. Wollte das zu Lernzwecken versuchen aber gut, lass ich das halt.

    Bin jetzt auf den fertigen Connector umgeschwenkt und damit tuts jetzt alles so wie es soll.

    Und das "seit Wochen" kommt nur daher das ich selten Zeit habe mit C++ rumzuspielen, entsprechend langsam komme ich also voran.



  • Pro-Tipp:

    Du nimmst ab sofort soci und bist wahnsinnig glücklich mit dem super schönen Interface und freust dich, wenn du bei einem Datenbankwechsel nur an einer Stelle den Typ der Datenbank ändern musst 😉



  • Nein, wird er nicht. Nicht, weil SOCI nicht zu gebrauchen ist, sondern weil ihm Grundlagen fehlen. Das Problem des OT ist im Zusammenhang mit der mySQL C-API nur sichtbar geworden, der Schwenk auf den Connector hat das eigentliche Problem nicht gelöst, sondern nur auf unbestimmte Zeit verschoben.



  • Genau so schauts aus


Log in to reply