سؤال

I'm trying to code a function that creates a zSQL database from a file of commands, using SQLite. The code of my function is as follows :

bool createDatabaseFromFile(Database& db, std::istream &commandFile, const char* dbName, std::ostream* err, bool multilineQueries)
{
    Statement stmt;
    std::string lineStr;
    std::string queryStr;

    bool end = false;

    if (!dbName)        // if the adress of the database isn't given, we get it from the first line of the command file
    {
        std::getline(commandFile, lineStr);
        dbName = lineStr.c_str();
    }

    bool noError = db.open(dbName, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, err); // if the database didn't open, the following loops aren't used

    while (std::getline(commandFile, lineStr) && (!end) && noError) // adds all lines of the file until either the end of the file or the keyword "#END"
    {
            if (lineStr.substr(0,4) == "#END")
            end = true;

            else if (lineStr.substr(0,2) != "//")  // skips the commented lines
            queryStr += lineStr;

            if (!multilineQueries)                  // if all lines are considered as a single query
            queryStr += ";";
    }

    std::string::size_type start_query = 0;
    std::string::size_type end_query;
    std::string query;

    while (start_query != std::string::npos && !noError)    //continue until all queries of the string are executed or there is an error
    {
        end_query = queryStr.find_first_of(';', start_query);
        query = queryStr.substr(start_query, end_query);

        if (db.prepare(query.c_str(), lineStr.size(), stmt))    // returns true if sql3_prepare didn't return an error
        {
            noError = stmt.makeAllSteps();
        }

        else
        noError = false;

        start_query = end_query;

        if (start_query != std::string::npos)
        start_query ++;                             // else the "cursors" stay on the same ';' over and over
    }


    return noError;
}

The Stmt class is basically a wrapper around sqlite3_stmt. When it's destroyed at the end of the code, it calls sqlite3_finalize, which causes a segfault for a reason I can't understand. What's the issue ?

The call stack of the error is this :

sqlite3_finalize(pStmt=0x3)
sql3::Statement::erase(this=0x28f9e0)
sql3::Statement::~Statement(this=0x28f9e0, __in_chrg=<optimized out>) 
sql3::createDatabaseFromFile(db=..., commandFile=..., dbName=0x51e057 "Ressources\\DatabaseFile.txt", err=0x533cc0, multilineQueries=true)

Here is the destructor's code :

void sql3::Statement::erase()
{
    if (p_stmt)
    testCode(sqlite3_finalize(p_stmt), USING_INCORRECT_STATEMENT, nullptr, std::cerr);
        //testCode is a const function, so the above is equivalent to :

    if (p_stmt)
    sqlite3_finalize(p_stmt);

    p_stmt = nullptr;
}

sql3::Statement::~Statement()
{
    erase();
}

Also, not sure what this mean, but I don't have any error if I call Statement::erase() just after Statement::makeAllSteps(). EDIT : apparently, it means that the while (start_query != std::string::npos && !noError) loop is skipped for some reason.

EDIT 2 : found it, it's because of !noError. I'll post an answer when I'm allowed.

هل كانت مفيدة؟

المحلول

DEAR PEOPLE OF THE FUTURE, HERE'S WHAT I FIGURED OUT SO FAR :

There were two problems in my code. The first one is that line :

while (start_query != std::string::npos && !noError)

Which should have been

while (start_query != std::string::npos && noError)

(in the first one, noError starts being true, which means the loop is skipped)

The second, more general problem in my project, is in the sql3::Statement constructor : I forgot to include a line to set the sqlite3_stmt pointer to nullptr.

Basically, the only way a call to finalize can return a segfault is if the pointer was not initialized either to nullptr or with the initializing functions.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top