sqlite 为什么相同的SQL查询在C++程序中无效,但在BD浏览器中打印结果

vbkedwbf  于 2023-11-21  发布在  SQLite
关注(0)|答案(1)|浏览(185)

我有一个使用SQLite版本3.43.1的c程序(DB浏览器版本3.12.2,其中有SQLite版本3.35.5)。我创建一个表并在该表中插入数据。当我想读取表:SELECT NAME FROM "mytable"时,我得到一个错误代码1和错误消息no such table: mytable
注意事项:我看到很多以前的答案说“你需要指向数据库”。我正在从我写过的同一个数据库中查询,没有错误。我也使用DB浏览器(一旦我的程序断开连接),我使用相同的查询并查看我的数据。
我还在程序中使用了以下查询来查看表列表:SELECT * FROM sqlite_master WHERE name LIKE 'mytable'
怎么可能?我不知道该怎么办。
另请注意:我尝试了sqlite_exec和非 Package 的方法(sqlite_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上使用g
12.3.0(通过Windows WSL)编译sqlite3.h和sqlite3.c文件,这些文件是由来自sqlite网站的压缩sqlite-amalgamation-343100提供的。
等效编译命令:gcc -fPIC -lpthread -ldl -lm -c sqlite3.o -o code/sqlite-amalgamation-3430100/sqlite3.c
db.h

#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;
}

字符串
db.cpp

#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;
}

void 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 error 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);
}


main.cpp

// C Standard
#include <stdlib.h>
#include <stdio.h>

// Custom - Utils
#include "db.h"

// C++ Standard
#include <fstream>
#include <iostream>
#include <memory>
#include <string>
#include <vector>

void createTables(DB proj_db) {
  proj_db.write("CREATE TABLE mytable (\"ID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, NAME TEXT NOT NULL, VALUE TEXT\");");
  proj_db.write("CREATE TABLE myOtherTable (\"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\';"); // output is empty; doesn't see any tables to list; should at least list my table creations

  // 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终端:

rm -rf myproject.db # this is to ensure a new sqlite db is created
./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); successful; verified with DB browser after program is closed
./myprogram --db myproject --in data2.json # another set of writes (sometimes to another table); successful; verified with DB Browser
./myprogram --db myproject --out mystuff.csv # queries tables (SELECT NAME from mytable) <------ ERROR HERE, but DB Browser shows data and my schema


我的实际程序返回读取命令的值。只是不想让这个最小的程序复杂化。只要我能修复错误代码,我就能处理剩下的。

o2gm4chl

o2gm4chl1#

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\';");

字符串
对我来说是有效的,所以你的insert和select语句都是错误的。特别是你的DB::read方法试图读取两个列值,所以你需要一个select,它至少返回两个文本值。另外,你需要

if (ret_code == SQLITE_ROW) {...}


在DO循环中
(and在测试前删除现有数据库一次)

相关问题