【问题标题】:SQLite in C. sqlite3_exec: parameter set in callback function prints incomplete data when called in main()C.sqlite3_exec 中的 SQLite:回调函数中设置的参数在 main() 中调用时打印不完整的数据
【发布时间】:2015-02-04 13:48:41
【问题描述】:

我正在努力实现一些非常基本的目标。但不幸的是,我无法得到预期的结果。

我有一个名为 emp_info的 sqlite 表,在以下字段中有 9 条员工记录:

SR_NO[0]、NAME[1]、AGE[2]、SEX[3]、ADDRESS[4]、EMPID[5]、CARDID[6] 和 SALARY[7]

要根据 sql 查询访问表并获取员工记录,我在 C 中有以下程序:

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

static int callback(void *param, int argc, char *argv[], char **azColName){
    int i=0;

    if(argc == 0) return 0;
    char **res = (char **)param;
    *res = (char *)realloc(*res, sizeof(*res));

  //for(i=0; i<argc; i++){
  //printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");

    strcpy(*res, argv[1], sizeof(*res));
    printf("%s\n", *res);
 // }
return 0;
}

int main(int argc, char* argv[])
{
sqlite3 *db;
char *zErrMsg = 0;
int rc;
char *sql;
char *param;

rc = sqlite3_open("/DBsqlite3/foreign_key.db", &db);

    if( rc )
    {
       fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
       exit(0);
    }
    else
    {
       fprintf(stderr, "\nOpened database successfully\n\n");
    }

sql="select * from emp_info;"

rc = sqlite3_exec(db, sql, callback, &param, &zErrMsg);

    if( rc != SQLITE_OK )
    {
      fprintf(stderr, "SQL error: %s\n", zErrMsg);
      sqlite3_free(zErrMsg);
    }
    else
    {
       fprintf(stdout, "Operation done successfully\n\n");
       printf("the value of data is %s \n\n", param);
    }


free(param);
sqlite3_close(db);
return 0;
}

输出如下: ` 成功打开数据库

AAA
BBB
CCC
DDD
EEE 
FFF
GGG
HHH
III
Operation done successfully

the value of data is III

我希望所有的 AAA、BBB、CCC、.... 都将存储在 param 中并被打印出来。但这并没有发生。 param 只取最后一条记录。

为什么会这样?我怀疑 strcpy() 造成了问题。

请帮忙。

除此之外,我真正的目标是让所有有效的员工记录(根据 sql 查询)存储在 param 中,它应该显示所有字段(SR_NO[0]、NAME [1]、年龄[2]、性别[3]、地址[4]、EMPID[5]、CARDID[6] 和 SALARY[7])。例如,如果我向 sql

提供以下查询
sql="SELECT * FROM emp_info WHERE AGE>40";

那么 param 应该显示如下结果

7           GGG         41          MALE        G1G2G3G4    307         7777GGG     77777     

8           HHH         42          FEMALE      H1H2H3H4    308         8888HHH     88888

9           III         43          FEMALE      I1I2I3I4    309         9999IIII    99999

而不仅仅是一个专栏。我怎样才能做到这一点?

提前谢谢你。

【问题讨论】:

标签: c sqlite callback


【解决方案1】:

处理 CL 提出的建议。我开始在基于光标的 API 上编写代码。我得到了想要的输出。

#include <iostream>
#include <sqlite3.h>
#include <stdlib.h>
#include <list>
#include <iterator>
#include <algorithm>

using namespace std;

class sqliteDB
{

private:
  int rc;
  sqlite3 *db;
  char *zErrMsg;
  const char *sql;
  sqlite3_stmt * stmt;
  list<string> answer;


public:

//================================XX=====================================//
  bool connectDB()
  {

      rc = sqlite3_open("/DBsqlite3/foreign_key.db", &db);
      if( rc )
      {
        cerr << "Can't open database: " << sqlite3_errmsg(db) << endl;
        sqlite3_close(db);
        exit(1);
      }
      else
      {
            std::cout<<"\n\nDatabase opened successfully\n\n";
      }
   }

//===============================XX=====================================//

  void allEmp()
  {
     int AGE;

     //Preparing the statement
     rc=sqlite3_prepare(db,"SELECT * FROM emp_info WHERE AGE>40;", -1, &stmt, NULL ); 
     if (rc != SQLITE_OK){
     throw string(sqlite3_errmsg(db));
     }
     else{
     cout<<"\n\nThe statement was prepared successfully\n\n";
     }

    // Creating List Container //
    cout << "\n\nList answer was created successfully\n\n";
    while(sqlite3_step(stmt) == SQLITE_ROW) {
    cout << "Rows" << endl;

    int column = sqlite3_column_count(stmt);

       for(int i = 0; i < column; i++)
       {
          cout << "Columns" << endl;
          answer.push_back(string((const char *) sqlite3_column_text(stmt, i)));
       }
     }

    sqlite3_finalize(stmt);

    cout << "\n\nDatabase was closed successfully\n\n";

 }

//==============================XX=====================================//

 void printList(){
    int s = answer.size();
    for( list<std::string>::const_iterator it = answer.begin(); it != answer.end(); it++)
      cout << it->c_str() << endl;
  } 


//===================================XX===============================//    

};


int main()
{
  sqliteDB object1;
  object1.connectDB();
  object1.allEmp();
  object1.printList();
  cout << "\n\nAll the statement were executed properly\n\n";

 return 0;
}

//========================END OF CODE===========================//

输出如下

 Database opened successfully



 The statement was prepared successfully



 List answer was created successfully

 Rows
 Columns
 Columns
 Columns
 Columns
 Columns
 Columns
 Columns
 Columns
 Columns
 Columns
 Columns
 Columns


 Rows
 Columns
 Columns
 Columns
 Columns
 Columns
 Columns
 Columns
 Columns
 Columns
 Columns
 Columns
 Columns


 Rows
 Columns
 Columns
 Columns
 Columns
 Columns
 Columns
 Columns
 Columns
 Columns
 Columns
 Columns
 Columns

 Database was closed successfully

 7
 GGG
 41
 MALE
 G1G2G3G4
 307
 7777GGG
 77777
 9833446677
 abi@gmail.com
 07:08:1947
 NONE
 8
 HHH
 42
 FEMALE
 H1H2H3H4
 308
 8888HHH
 88888
 9833446688
 abj@gmail.com
 08:09:1947
 NONE
 9
 III
 43
 FEMALE
 I1I2I3I4
 309
 9999IIII
 99999
 9833446699
 abk@gmail.com
 09:10:1947
 NONE


 All the statement were executed properly

我遇到的主要问题是“

谢谢你。

【讨论】:

    【解决方案2】:

    我不是这方面的专家,但简单的谷歌搜索显示,sqlite3_exec() 的语法是

    int sqlite3_exec(
      sqlite3*,                                  /* An open database */
      const char *sql,                           /* SQL to be evaluated */
      int (*callback)(void*,int,char**,char**),  /* Callback function */
      void *,                                    /* 1st argument to callback */
      char **errmsg                              /* Error msg written here */
    );
    

    注意第4个参数,应该是void *

    根据您对变量和调用约定的定义,

    char *param;
    

    rc = sqlite3_exec(db, sql, callback, &param, &zErrMsg);
    

    你弄错了第四个参数。您可能希望将其重写为

    rc = sqlite3_exec(db, sql, callback, (void *)param, &zErrMsg);
    

    注意:[如果sqlite3_exec() 尚未处理] 您可能需要先将内存分配给param,然后再传递给sqlite3_exec()。此外,您可能希望对其进行一些健全性和有效性检查,而不是直接将 argv 传递给回调。

    【讨论】:

      【解决方案3】:

      您从an answer 获取代码,目标是读取单个结果行。 strcpy 会覆盖 same 变量的先前值。

      您应该使用cursor-based API,并在循环中调用sqlite3_step

      ...
      while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
          my_object *o = new ...;
          o->set_field(sqlite3_column_xxx(stmt, 1);
          ...
          my_list.add(o);
      }
      ...
      

      【讨论】:

      • 非常感谢。您的意见最有帮助
      猜你喜欢
      • 1970-01-01
      • 2011-01-05
      • 1970-01-01
      • 2019-08-07
      • 2021-06-11
      • 1970-01-01
      • 2023-03-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多