sqlite mingw, segfault beim versuch eine Tabelle zu erstellen
-
Guten Abend,
Ich hatte schon mal eine frage hier über dieses Problem gestellt, ich habe mich etwas mehr informiert:- Ich weiss das ich ein segfault bekomme (warum weiss ich nicht code blocks friert ab da)
- ich bekomme diesen fehler nur wenn ich ein object erstelle von meiner DbTools klasse
- ich erhalte diesen fehler auch nur wenn ich eine Tabelle erstelle und dannach ein insert machen will
nun das ist alles was ich weiss auf stack overflow hat man mir leider nicht weiter geholfen vermutlich weil man mein problem nicht verstanden hat.
ich werde hier meine main und die klasse DbTools hinzufügen, mit allen methoden die nicht wichtig sind rausgelassen.
Es ist etwas zu viel Code für eine Frage, tut mir wirklich leid ;-;
aber das wäre das minimum um es so per copy paste zum laufen zu bringen,
vieleicht kann ja jemand mir mehr sagen weil wie gesagt ich komme nicht weiter da
CB abstürtzt:::..Danke schonmal im vorraus
ich hoffe ich werde schlauer daraus da ich wirklich nicht weiter komme und wissen würde was ich falsch mache
main:
#include <iostream> #include <stdlib.h> #include <vector> #include "DbTools.h" using namespace std; int main() { if( remove( "MoneyBank.db" ) != 0 ) perror( "Error deleting file" ); else puts( "File successfully deleted" ); DbTools dbTools; // in init trit der segfault auf wenn insert auskommentiert wird läuft es sauber ab dbTools.Init(); vector<string> valuesPrdct = {"NAME", "PRICE"}; vector<string> dataPrdct = {"Test", "7.70"}; dbTools.Insert("Products", valuesPrdct, dataPrdct); system("pause"); return 0; }
DbTools Header:
//TODO: Need to Think how to include sqlite3 properly #include "sqlite3.h" class DbTools { public: DbTools(); virtual ~DbTools(); int Init(); int OpenDb(char *path); void CloseDb(); //NOTE need to think about Insert int Insert(std::string table,std::vector<std::string> values, std::vector<std::string> data); protected: private: sqlite3 *db; char **ERRmsg; int rc; // user should not create Tables! int CreateTable(std::string title, std::vector<std::string> attributes); static int CallBack(void *data, int argc, char **argv, char **azColName); static int SearchForChar(std::string text, char c); };
DbTools Cpp
using namespace std; //{ Constructor Destructor DbTools::DbTools() { } DbTools::~DbTools() { DbTools::rc = 0; DbTools::ERRmsg = 0; DbTools::db = nullptr; } //} //NOTE: init -> query's could lead to Sqlite Error int DbTools::Init() { vector<string> valuesPrdct = {"ID INTEGER PRIMARY KEY AUTOINCREMENT", "NAME VARCHAR NOT NULL", "PRICE INTEGER NOT NULL"}; vector<string> valuesByd = {"ID INTEGER PRIMARY KEY", "AMOUNT INTEGER NOT NULL", "DATE DATE", "FOREIGN KEY(ID) REFERENCES PRODUCTS(ID)"}; rc = OpenDb("MoneyBank.db"); //NOTE: create table does not work properly -> segfault rc += CreateTable("PRODUCTS", valuesPrdct); rc += CreateTable("BUYED", valuesByd); if(rc == 0) { return 0; }else{ return rc; } } // Create or Open a DataBase in Path int DbTools::OpenDb(char *path) { rc = sqlite3_open(path, &db); if(rc) { cout << "DataBase Cant be found" << endl; return 1; }else { cout << "DataBase found/created and Opened successfully" << endl; return 0; } } void DbTools::CloseDb() { sqlite3_close(db); } int DbTools::CreateTable(string title, vector<string> attributes) { //{###Look for inappropriate query's -> if there is a ';' there is maybe another query within### if(SearchForChar(title, ';')) { cout << "Inappropriate Character in CreateTable Title" << endl; return 2; } for (int i= 0; i < attributes.size(); i++) { if(SearchForChar(attributes[i], ';')) { cout << "Inappropriate Character in CreateTable attributes" << endl; return 2; } } //} //{###write query### //NOTE: It is not possible to give Titles which are case sensitive string query; query = "CREATE TABLE "; query += title; query += "("; for (int i= 0; i < attributes.size(); i++) { query += attributes[i]; if(i != attributes.size()-1) { query += ","; }else{ query += ");"; } } //} //{###Execute query### rc = sqlite3_exec(db, query.c_str(), 0, 0, ERRmsg); if(rc == SQLITE_OK) { cout << "Table " << title << " created" << endl; } else { cout << "could not create Table " << title << endl; return 1; } //} return 0; } //TODO: Test Insert int DbTools::Insert(string table,vector<string> values ,vector<string> data) { //{###Write query### string query = "INSERT INTO "; query += table; query += " ("; for (int i= 0; i < values.size(); i++) { query += values[i]; if(i != values.size()-1) { query += ","; }else{ query += ")"; } } query += " VALUES("; for (int i= 0; i < data.size(); i++) { query += data[i]; if(i != data.size()-1) { query += ","; }else{ query += ")"; } } query += ";"; //} //Execute query rc = sqlite3_exec(db, query.c_str(), 0, 0, ERRmsg); if(rc != 0) { return 1; } return 0; } int DbTools::SearchForChar(string text, char c) { if (text.find(c) != string::npos) { return 1; } return 0; }
-
Ich habs mir zugegeben gerade nicht angeschaut weil es doch ein bisschen viel ist, für "mal eben". Also geb ich dir mal zwei mögliche Vorgehensweisen.
- Hau alles mit breakpoints voll, bis du die exakte Zeile hast in der es abraucht.
- Lass mal gdb vom terminal aus laufen.Ich habe in letzter Zeit immer wieder schlechte Erfahrungen mit C::B und debuggen gemacht, wo C::B einfach abraucht, wo es das nicht sollte, teilweise sieht es sogar so aus als wär alles in Ordnung, obwohl das Programm über std::terminate beendet wurde.
- gdb mit programm starten, oder programm starten und dann gdb anheften.
- r eingeben zum ausführen
- warten bis zum segfault.
- schaun was der debugger zu sagen hat.
Außerdem noch ein paar Kommentare:
- char* als Parameter?
std::string hat ein Member c_str(), womit du ein char const* erhälst, der garantiert \0 terminiert ist und an C Funktionen übergeben werden kann.- wenn schon char const*
- wenn dann schon std::string const&
- oder vllt in C++17 string_view (vorsicht: nicht sicher für C interfaces, falls kein null terminator existiert im string_view)
- Übergebe Parameter immer per const& wenn du sie in der funktion nicht modifizierst (was fast nie der fall ist),
int DBTools::CreateTable(string const& title, /*..*/.)
(EDIT: Ich liebe die Formatierungen im neuen Forum <3)
-
Ok ich habs mir doch mal länger angeschaut.
Dein Fehler ist offensichtlich im letzten Parameter von sqlite3_exec.
Das hier ist die richtige Benutzung:
char* errorMessage = nullptr; rc = sqlite3_exec(db, query.c_str(), nullptr, nullptr, &errorMessage); if (errorMessage != nullptr) { std::string error{errorMessage}; sqlite3_free(errorMessage); // wichtig! sonst leakst das Programm throw std::runtime_error{error.c_str()}; } // Wenn du dich entscheidest eine exception zu werfen wie oben vorgeschlagen, dann wird das hier überflüssig, wenn du keine exception wirfst, vergiss trotzdem nicht sqlite3_free. if (rc != 0) return 1; else return 0;
- ERRmsg bitte nicht als member!
- Wenn du den callback von exec benutzen willst, kannst du
this
als 4. parameter vonsqlite3_exec
übergeben, dann kannst do vom callback aus wieder zu deiner DbTools klasse. - Bitte mach nicht all deine Tabellennamen und Tabellenmembernamen in caps.
Ich hoffe ich krieg ein dankbaren upvote von dir XD
-
Ich finde dein Design insgesamt etwas komisch. Viele **-Parameter etc und vor allem kein Raii und die DB wird auch nicht automatisch geschlossen, wenn dein DB-Objekt deleted wird. Und warum virtual? Sieht nicht so aus, als würde man davon erben wollen.
Vorschlag: schau dir doch mal fertige C++-Wrapper für sqlite an, z. B. https://github.com/SRombauts/SQLiteCpp/blob/master/README.md
-
@5cript auf jeden fall vielen dank XD du hast mir sehr viel geholfen