我有一个使用 SQLite 版本 3.43.1 的 C++ 程序。 (DB 浏览器版本 3.12.2,其中 SQLite 版本 3.35.5)。我创建一个表并在该表中插入数据。当我想阅读表格时:
SELECT NAME FROM "mytable"
,我收到错误代码 1 和错误消息 no such table: mytable
。
注意:我看到很多以前的答案都说“你需要指向数据库”。我正在从我写入的同一个数据库中查询,没有错误。我还使用数据库浏览器(一旦我的程序断开连接),并且我使用相同的精确查询并查看我的数据。
我还在程序中使用了以下查询来查看表列表:
SELECT * FROM sqlite_master WHERE name LIKE 'mytable'
。
这怎么可能?我不知道如何继续。
另请注意:我尝试了 sqlite_exec 和非包装方法(prepare_v2、step、sqlite3_column_text)。此时,我不知道使用回调或 step+column_text 之间的更改有何不同。
数据库的创建是使用常规的 sqlite3_open 完成的。除了文件路径之外没有任何参数。创建表使用默认的
CREATE TABLE mytable (ID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, NAME TEXT NOT NULL, VAL TEXT);
。没有别的了。
我正在 Ubuntu 12.3.0(通过 Windows WSL)上使用 g++ 12.3.0 在 sqlite3.h 和 sqlite3.c 文件上进行编译,该文件由 sqlite 网站压缩的 sqlite-amalgamation-343100 提供。
等效编译命令:
gcc -fPIC -lpthread -ldl -lm -c sqlite3.o -o code/sqlite-amalgamation-3430100/sqlite3.c
#pragma once
// Third-Party
#include <sqlite3.h>
// C++ Standard
#include <filesystem>
#include <iostream>
#include <sstream>
#include <string>
#include <tuple>
#include <vector>
class DB {
public:
void setFilepath(std::filesystem::path);
std::filesystem::path getFilepath();
void connect();
void close();
void write(std::string);
void read(std::string);
private:
sqlite3* db;
std::filesystem::path db_path;
#include "db.h"
static int callback(void* list, int cols, char** dat, char** colname) {
std::cout << "callback called" << std::endl;
for (int i = 0; i < cols; i++) {
printf("%s = %s\n", colname[i], dat[i] ? dat[i] : "NULL");
std::cout << colname[i] << " = " << dat[i] << std::endl;
}
printf("\n");
return 0;
}
void DB::setFilepath(std::filesystem::path fp) {
std::string msg = "DB set filepath " + fp.string();
spdlog::info(msg);
if (fp.extension() != ".db") {
fp.replace_extension(".db");
}
db_path = fp;
return;
}
std::filesystem::path DB::getFilepath() {
return db_path;
}
void DB::connect() {
int ret_code = sqlite3_open(db_path.string().c_str(), &db);
//const char* zVfs = "";
//int ret_code = sqlite3_open_v2(db_path.string().c_str(), &db, 0, zVfs);
if (ret_code) {
std::string msg1 = "DB return code error ";
std::string msg2 = sqlite3_errmsg(db);
spdlog::error(msg1 + msg2);
exit(0);
}
}
void DB::close() {
sqlite3_close(db);
}
void DB::write(std::string query) {
connect();
int ret_code;
char* pzErrMsg = 0;
ret_code = sqlite3_exec(db, sql_str.c_str(), callback, pArg, &pzErrMsg);
if (ret_code != SQLITE_OK) {
spdlog::error("Execution error");
sqlite3_free(pzErrMsg);
}
close();
return;
}
voiid DB::read(std::string sql_str) {
int ret_code = 0;
sqlite3_stmt* stmt;
char* zErrMsg = 0;
connect();
ret_code = sqlite3_prepare_v2(db, sql_str.c_str(), -1, &stmt, nullptr);
std::cout << "ret code: " << ret_code << std::endl;
// I receive the erorr HERE
// #########################################################
// exe fail
// no such table: mytable <--------------- HERE
// #########################################################
if (ret_code != SQLITE_OK) {
std::cout << "exec fail" << std::endl;
std::cerr << sqlite3_errmsg(db) << '\n';
sqlite3_free(zErrMsg);
exit(1);
}
do {
ret_code = sqlite3_step(stmt);
// #########################################################
// # PLEASE DO NOT WORRY ABOUT THIS RIGHT NOW #
// # THIS IS NOT WHERE THE ERROR OCCURS #
// #########################################################
std::cout << "ret code loop: " << ret_code << std::endl;
std::cout << sqlite3_column_text(stmt, 0) << ":";
std::cout << sqlite3_column_text(stmt, 1) << std::endl;
} while (ret_code == SQLITE_ROW);
if (ret_code != SQLITE_DONE) { // 101
std::cout << "ret_code not done" << std::endl;
std::cerr << sqlite3_errmsg(db) << '\n';
}
// close
sqlite3_finalize(stmt);
sqlite3_close(db);
}
void createTables(DB proj_db) {
proj_db.write("CREATE TABLE mytable (\"ID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, NAME TEXT NOT NULL, VALUE TEXT\");");
}
void writeDatafromFile(json file, DB proj_db) {
// read data
...
// write to DB
proj_db.write("INSERT INTO mytable (NAME,VALUE) \"abc\",\"123\"");
}
void readDatabase(DB proj_db) {
proj_db.read("SELECT NAME FROM \"mytable\";"); //fail
proj_db.read("SELECT * FROM sqlite_master WHERE name LIKE \'mytable\';"); // works! but only lists the tables that exist. not the data inside the table (just like DB Browser)
// write to csv
...
}
int main(int argc, char const* argv[]) {
DB proj_db;
proj_db = DB();
std::filesystem::path db_fp; // obtained from arguments, same directory is fine. ends with .db. example: ./mydatabase.db
proj_db.setFilepath(db_fp);
if (arguments.new()) createTables();
if (arguments.inputFileExists()) writeDatafromFile();
if (arguments.outputFlagExists()) readDatabase();
return 0;
}
bash 终端:
./myprogram --db myproject --new # I create a blank sql db file called myproject.db; creates empty tables (mytable, myOthertable, etc)
./myprogram --db myproject --in data.json # I write data parsed from a file (equivalent to ~2-3 INSERT mytable sql commands)
./myprogram --db myproject --in data2.json # another set of writes (sometimes to another table)
./myprogram --db myproject --out mystuff.csv # queries tables (SELECT NAME from mytable) <------ ERROR HERE, but DB Browser shows data and my schema
我的实际程序返回读取命令的值。只是不想让这个最小的程序复杂化。只要我能修复错误代码,剩下的我就可以处理。
proj_db.write("CREATE TABLE IF NOT EXISTS mytable (ID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, NAME TEXT NOT NULL, VALUE TEXT);");
proj_db.write("INSERT INTO mytable (NAME,VALUE) VALUES ('abc','123')");
proj_db.read("SELECT NAME, VALUE FROM mytable;");
proj_db.read("SELECT * FROM sqlite_master WHERE name LIKE \'mytable\';");
对我有用,所以你的插入和选择语句都是错误的。特别是您的 DB::read 方法尝试读取两个列值,因此您需要一个
select
来返回至少两个文本值。另外你还需要
if (ret_code == SQLITE_ROW) {...}
在 DO 循环中
(并在测试前删除现有数据库一次)