2016-04-28 65 views
0

我有一種情況,我們與sqlite3的連接沒有通過。這是我的隊友代碼,但他離開了球隊,現在我正在努力解決代碼中的問題,但我相當迷茫。該程序編譯,我只能用QtCreator中的調試工具找到問題的位置。調試器工具將我帶到sqlite_prepare_v2來解決問題。sqlite3,c + +連接,運行查詢,sqlite3_prepare_v2()

調試器輸出:(我張貼這一點,因爲它可能是有用的)

 nByte 84 size_t 
     query "SELECT username,password FROM users WHERE username='dilsizk' AND password='12345678'" std::string 
     return_matrix <not accessible> std::vector<std::vector<std::string>> 
     return_value 32745 int 
     this @0x7fe90ab23f5f DBHandler 
      columns_ -1282717696 int 
      db_connection_ 0x740000800003f7da sqlite3 * * 
      log @0x7fe90ab23f5f Log 
       count -1064971727 int 
      query_ 0x401f0fc35bd08908 sqlite3_stmt * * 
      return_matrix_ 0xc748eb7501046e83 std::vector<std::vector<std::string>> * 
     unusedSQL "12345678" char * 

該方法的代碼是:

//query must be nul-terminated (ending in \0) 
//if an error code is returned, method returns what it has processed to that point 
std::vector<std::vector<std::string>>* DBHandler::runQuery(std::string query) { 
    //get byte size of query 
    size_t nByte = std::strlen(query.c_str()); 
    //log 
    log << "DBHandler: Query size is " + std::to_string((int)nByte) +" bytes"; 
    //make junk variable for potential unused sql 
    const char **unusedSQL; 
    //prepare the statement 
    sqlite3_prepare_v2(*db_connection_,query.c_str(),(int)nByte,query_,unusedSQL); 
    //log 
    log << "DBHandler: Query formatted into prepared statement"; 
    //perform first step, grab return value 
    int return_value = sqlite3_step(*query_); 
    //log 
    log << "DBHandler: First evaluation step completed"; 
    //check if done, and if it is because of an error or that there is only 1 row 
    if(return_value != SQLITE_ROW) { 
     //log 
     log << "DBHandler: Query returns only 1 row"; 
     if(return_value != SQLITE_DONE) { 
      //log 
      log << "DBHandler: Error handling query, code 1"; 
      return (new std::vector<std::vector<std::string>>); 
     } 
    } 

還有更多的方法,但我不想發佈整個事情,因爲程序無法到達後的步驟

sqlite3_prepare_v2(*db_connection_,query.c_str(),(int)nByte,query_,unusedSQL); 

此外,讓我prov爲變量指定dbhandler.h頭文件。

#include <algorithm> 
#include <sqlite3.h> 
#include <vector> 
#include <cstring> 
#include "log.h" 

#include <iostream> 

/* Class to handle interaction with the local test database in the /db_tools directory. Run ./newDB.sh in that directory prior to use. */ 
class DBHandler { 

public: 
    /* Constructor to create DBHandler object. */ 
    /*! 
    * This object should ALWAYS be destroyed by its destructor when use is done. The constructor only opens a connection to the local database. 
    */ 
    DBHandler(); 
    /* Destructor to prevent memory leaks from this object. */ 
    /*! 
    * Important that this is called, as it is otherwise vulnerable to causing multiple memory leaks. 
    */ 
    ~DBHandler(); 
    /* Runs a query to the database and returns the output in a formatted vector. */ 
    /*! 
    * This method formats the query, passed as a string, into a prepared statement to be processed. 
    * \param query The query to the database. Must be nul-terminated (ending in \0) with no whitespace between the end of the query and the zero-terminator. 
    * \return Returns a vector, where each index holds a vector per column, whose 0 index is the column name and all following indices are entries in order of their row. 
    */ 
    std::vector<std::vector<std::string>>* runQuery(std::string query); 

private: 
    Log log; 
    sqlite3** db_connection_; /** Database connection object. **/ 
    sqlite3_stmt** query_; /** Prepared statement object. **/ 
    int columns_; /** Number of columns in the prepared statement after 1 step. **/ 
    std::vector<std::vector<std::string>>* return_matrix_; /** Pointer to the matrix containing the evaluation of the prepared statement. **/ 
    /* Fills the return matrix with the names of the columns in the prepared statement. */ 
    void fillColName(); 
    /* Fills each column vector in the return matrix with the entries from the most recent step of the prepared statement. */ 
    void fillRow(); 
}; 

我很抱歉有很多文字,但我認爲這些輸出會在嘗試解決問題時有用。

請讓我知道,如果有什麼我可以提供或如果我的問題是缺少的東西。我相當新的網站。試圖能夠提出格式良好的問題。

謝謝。

回答

0

根據documentationsqlite_prepare_v2的最後一個參數是指針的位置,它接收SQL語句的其餘部分(因爲prepare只編譯查詢中的第一個sql語句)。

您的代碼傳遞一個未初始化的變量作爲該參數,因此當sqlite_prepare_v2試圖更改指針的值時,它會覆蓋一些隨機內存。

使用這樣的事情,而不是:

const char *unusedSQL = NULL; 
//prepare the statement 
sqlite3_prepare_v2(*db_connection_,query.c_str(),(int)nByte,query_,&unusedSQL); 

另外要sqlite3_prepare_v2第四個參數應該是一個指向一個變量,會收到編譯聲明,你的代碼是通過_query這是一個成員變量你的班級,但你沒有顯示它是如何初始化的。我懷疑這有與unusedSQL相同的問題。

你應該申報改爲

sqlite3_stmt* query_ 

,並通過指針傳遞給query_參數:

const char *unusedSQL = NULL; 
query_ = NULL; 
//prepare the statement 
sqlite3_prepare_v2(*db_connection_,query.c_str(),(int)nByte, &query_, &unusedSQL); 

還要注意:sqlite3_prepare_v2有返回值 - 你應該檢查一下,看是否一切正常。

+0

是的,根據您的建議改變這些工作!我能夠弄清楚,但你解釋得比我能做得好得多。謝謝。 –