【问题标题】:SQLite3 - Taking function parameters as valuesSQLite3 - 以函数参数为值
【发布时间】:2021-01-12 01:32:19
【问题描述】:

我正在尝试使用 sqlite3 数据库创建一个类,其方法应在用户将文件添加到应用程序时将数据插入表中,但它没有按预期工作,

    void Database::InsertSample(int Favorite, std::string Filename,
                                std::string SamplePack, int Channels, int Length,
                                int SampleRate, int Bitrate, std::string Comment,
                                std::string Path)
    {
        try
        {
            rc = sqlite3_open("Samples.db", &DB);
    
        sql = "INSERT INTO SAMPLES (FAVORITE, FILENAME, SAMPLEPACK, CHANNELS, \
                                    LENGTH, SAMPLERATE, BITRATE, BITSPERSAMPLE, PATH) \
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);";
    
        rc = sqlite3_prepare_v2(DB, sql.c_str(), 0, &stmt, 0);   // create the prepared statement
    
        rc = sqlite3_bind_int(stmt, 1, Favorite);
    
        rc = sqlite3_bind_text(stmt, 2, Filename.c_str(), Filename.size(), SQLITE_STATIC);
    
        rc = sqlite3_bind_text(stmt, 3, SamplePack.c_str(), SamplePack.size(), SQLITE_STATIC);
    
        rc = sqlite3_bind_int(stmt, 4, Channels);
    
        rc = sqlite3_bind_text(stmt, 5, Filename.c_str(), Filename.size(), SQLITE_STATIC);
    
        rc = sqlite3_bind_int(stmt, 6, Length);
    
        rc = sqlite3_bind_int(stmt, 7, SampleRate);
    
        rc = sqlite3_bind_int(stmt, 8, Bitrate);
    
        rc = sqlite3_bind_text(stmt, 9, Comment.c_str(), Comment.size(), SQLITE_STATIC);
    
        rc = sqlite3_bind_text(stmt, 10, Path.c_str(), Path.size(), SQLITE_STATIC);
    
        rc = sqlite3_step(stmt);
    
        rc = sqlite3_exec(DB, Sample.c_str(), NULL, 0, &ErrorMessage);
    
            if (rc != SQLITE_OK)
            {
                std::cerr << "Error! Cannot insert data into table." << std::endl;
                sqlite3_free(ErrorMessage);
            }
            else
            {
                std::cout << "Data inserted successfully." << std::endl;
            }
    
            sqlite3_close(DB);
        }
        catch (const std::exception &exception)
        {
            std::cerr << exception.what();
        }
    }

但这失败了,抛出错误语句“错误!无法将数据插入表中。”。我在这里做错了吗?

我在另一个类中使用这个函数,

void Browser::OnClickDirCtrl(wxCommandEvent& event)
{
    TagLib::FileRef File (DirCtrl->GetFilePath());
    TagLib::String Artist = File.tag()->artist();
    TagLib::String Album = File.tag()->album();
    TagLib::String Genre = File.tag()->genre();
    TagLib::String Title = File.tag()->title();
    TagLib::String Comment = File.tag()->comment();
    int Bitrate = File.audioProperties()->bitrate();
    int Channels = File.audioProperties()->channels();
    int Length = File.audioProperties()->lengthInMilliseconds();
    int LengthSec = File.audioProperties()->lengthInSeconds();
    int SampleRate = File.audioProperties()->sampleRate();

    wxVector<wxVariant> Data;
    Data.clear();
    Data.push_back(false);
    Data.push_back(TagLibTowx(Title));
    Data.push_back(TagLibTowx(Artist));
    Data.push_back(wxString::Format("%d",Channels));
    Data.push_back(wxString::Format("%d",LengthSec));
    Data.push_back(wxString::Format("%d",SampleRate));
    Data.push_back(wxString::Format("%d",Bitrate));
    Data.push_back(TagLibTowx(Comment));

    SampleListView->AppendItem(Data);

    db.InsertSample(0, Title.to8Bit(), Artist.to8Bit(), Channels, Length, SampleRate, Bitrate, Comment.to8Bit(), DirCtrl->GetFilePath().ToStdString());
}

这只是应该将文件添加到数据库的函数的一部分。如您所见,我将文件的路径存储在数据库中,这是项目所需的重要数据。

/---------/

编辑:添加一个简短的示例,

main.cpp

#include "testdb.hpp"

int main()
{
    Database db;

    db.InsertData("Hello, World!");
    return 0;
}

testdb.hpp

#include <sqlite3.h>
#include <string>

class Database
{
    public:
        Database();
        ~Database();

    public:
        sqlite3* DB;
        int rc;
        char* ErrorMessage;
        std::string Test;
        std::string sql;

        sqlite3_stmt* stmt;

    public:
        void InsertData(std::string Path);
};

testdb.cpp

#include <exception>
#include <iostream>
#include <string>

#include "testdb.hpp"

Database::Database()
{
    /* Create SQL statement */
    Test = "CREATE TABLE TEST("
        "TEST           TEXT    NOT NULL);";

    try
    {
        rc = sqlite3_open("Test.db", &DB);
        rc = sqlite3_exec(DB, Test.c_str(), NULL, 0, &ErrorMessage);

        if (rc != SQLITE_OK)
        {
            std::cerr << "Error! Cannot create table." << std::endl;
            sqlite3_free(ErrorMessage);
        }
        else
        {
            std::cout << "Table created successfuly." << std::endl;
        }

        sqlite3_close(DB);
    }
    catch (const std::exception &exception)
    {
        std::cerr << exception.what();
    }
}

void Database::InsertData(std::string Test)
{
    try
    {
        rc = sqlite3_open("Test.db", &DB);

    sql = "INSERT INTO TEST (PATH) VALUES (?);";

    rc = sqlite3_prepare_v2(DB, sql.c_str(), 10, &stmt, 0);   // create the prepared statement
    // error handling goes here

    rc = sqlite3_bind_text(stmt, 10, Test.c_str(), Test.size(), SQLITE_STATIC);
    // error handling goes here

    rc = sqlite3_step(stmt);
    // error handling goes here

    rc = sqlite3_finalize(stmt);

        if (rc != SQLITE_OK)
        {
            std::cerr << "Error! Cannot insert data into table." << std::endl;
            sqlite3_free(ErrorMessage);
        }
        else if (rc == SQLITE_BUSY)
        {
            std::cout << "BUSY" << std::endl;
        }
        else if (rc == SQLITE_DONE)
        {
            std::cout << "DONE" << std::endl;
        }
        else if (rc == SQLITE_ERROR)
        {
            std::cout << "ERROR" << std::endl;
        }
        else if (rc == SQLITE_MISUSE)
        {
            std::cout << "MISUSE" << std::endl;
        }
        else
        {
            std::cout << "Data inserted successfully." << ErrorMessage << std::endl;
        }

        sqlite3_close(DB);
    }
    catch (const std::exception &exception)
    {
        std::cerr << exception.what();
    }
}

Database::~Database(){}

使用g++ main.cpp testdb.cpp -l sqlite3 -o db编译。

这里发生了同样的事情,它说数据已插入,但sqlitebrowser 中的数据库显示为空。

【问题讨论】:

  • Edit 你的问题包括整个错误信息。
  • 另外,我建议创建一个更简单的示例,我们可以在这里讨论。尝试对只有一列的表执行类似操作。如果你能让它工作,那么你可以从那里添加它。如果您遇到类似的错误,那么您可以编辑您的问题以显示较小的代码,这使我们更容易看到发生了什么。
  • 提示:打开一次数据库连接并在程序的整个生命周期中重复使用它,而不是每次您要插入数据时。效率更高。您也可以保存和重复使用准备好的语句。
  • @Code-Apprentice 编辑了帖子,添加了简短示例,带有文件名。
  • @apoorv569 您的简短示例是否会导致与原始示例相同的错误?

标签: c++ sqlite


【解决方案1】:

您有一个sqlite3_step,后跟sqlite3_exec,这可能不是您想要的。这当然不好。您必须调用sqlite3_resetsqlite3_finalize 来完成准备好的语句。如果您从sqlite3_step 获得一个,它还将提供一个特定的错误代码,以便更好地描述错误。

查看`sqlite3_step'的这个解释

【讨论】:

  • 我尝试同时使用sqlite3_finalizesqlite3_reset,我收到“数据插入成功”的消息。但是当我尝试在sqlitebrowser 中查看数据库时,它显示数据库为空。我还添加了SQLITE_BUSYSQLITE_DONESQLITE_ERRORSQLITE_MISUSE 错误代码,但我什么也没得到。
  • 您确定查看的是同一个“Test.db”文件吗?运行成功插入时时间戳是否会发生变化?
  • 我仔细检查过,当我第一次运行程序时,它说表已创建并成功插入数据,但再次运行不会更改时间戳,但它说无法创建表。因为它已经创建但数据插入成功,消息后面有这些奇怪的字符��
  • 奇怪的字符来自ErrorMessage,没有初始化。如果时间戳没有改变,那么您正在查看错误的文件。您可以使用CREATE TABLE IF NOT EXISTS创建表,以避免创建表时出错。
  • 应该是正确的文件,我在其他地方创建了一个不同的文件夹,其中只有我在上面发布的 3 个文件,没有别的,在运行创建 Test.db 的程序后。
猜你喜欢
  • 1970-01-01
  • 2018-10-02
  • 2021-12-15
  • 1970-01-01
  • 2015-07-02
  • 2015-03-20
  • 1970-01-01
  • 2018-07-06
  • 2019-09-11
相关资源
最近更新 更多