C+中sqlite3回调函数的正确使用+; 我有以下C++代码,用于与SqLITE3一起进行测试。 它是一个名为customer的类,声明了一个回调函数。只要sqlite3\u exec()从SQLite数据库返回结果(记录),就会调用此回调函数

C+中sqlite3回调函数的正确使用+; 我有以下C++代码,用于与SqLITE3一起进行测试。 它是一个名为customer的类,声明了一个回调函数。只要sqlite3\u exec()从SQLite数据库返回结果(记录),就会调用此回调函数,c++,sqlite,C++,Sqlite,我不喜欢这种构造,因为处理结果的源代码位于类外的回调函数中,而不是由调用sqlite3_exec()的类方法处理的结果 我可以使用全局变量,在回调函数从SQL查询结果中提取完值后,这些变量将在类方法中使用。但是,如果有多条记录,并且回调函数被调用多次,该怎么办呢。然后,我需要使用数组,除非我确保我将只得到一个结果 我是否需要忘记回调函数,而深入研究SQLite API的调用 或者我需要去一个C++包装器,我想那里没有回调机制,结果被传递回类方法本身? // customer #include "

我不喜欢这种构造,因为处理结果的源代码位于类外的回调函数中,而不是由调用
sqlite3_exec()
的类方法处理的结果

我可以使用全局变量,在回调函数从SQL查询结果中提取完值后,这些变量将在类方法中使用。但是,如果有多条记录,并且回调函数被调用多次,该怎么办呢。然后,我需要使用数组,除非我确保我将只得到一个结果

我是否需要忘记回调函数,而深入研究SQLite API的调用

<>或者我需要去一个C++包装器,我想那里没有回调机制,结果被传递回类方法本身?

// customer
#include "Customer\customer.h"
//## begin module%50E6CCB50119.additionalDeclarations preserve=yes
static int callback(void *NotUsed, int argc, char **argv, char **azColName)
{
  int i;
  char* columnName;
  char* columnValueString;
  short int columnValueShortInt = 0;
  int columnValueInt = 0;

  cout << "begin of callback function\n";

  for(i=0; i<argc; i++)
  {
    columnName = azColName[i];
    if (strcmp(columnName, "FirstName")==0 || strcmp(columnName, "LastName")==0)
    {
      columnValueString = argv[i];
      cout << "columnName = " << columnName << "; value = " << columnValueString <<"\n";
    }
    else
    {
      if(strcmp(columnName, "Age")==0)
      {
        stringstream(argv[i]) >> columnValueShortInt;
        cout << "columnName = " << columnName << "; value = " << columnValueShortInt <<"\n";
      }
      else // strcmp(columnName, "Id")==0)
      {
        stringstream(argv[i]) >> columnValueInt;
        cout << "columnName = " << columnName << "; value = " << columnValueInt <<"\n";
      }
    }
  }
  cout << "end of call back function \n";
  return 0;
}

//## end module%50E6CCB50119.additionalDeclarations


// Class customer

customer::customer ()
  //## begin customer::customer%50F969EE01E4.hasinit preserve=no
  //## end customer::customer%50F969EE01E4.hasinit
  //## begin customer::customer%50F969EE01E4.initialization preserve=yes
  //## end customer::customer%50F969EE01E4.initialization
{
  //## begin customer::customer%50F969EE01E4.body preserve=yes
  customerId = 0;
  zErrMsg = 0;

  customerDataBaseRc = sqlite3_open("customerdb", &customerDataBase);
  if(customerDataBaseRc)
  {
    fprintf(stderr, "Can't open database %s\n", sqlite3_errmsg(customerDataBase));
    sqlite3_close(customerDataBase);
  }

  const char * pSQL[6];
  const char * sqlStatement;

  pSQL[0] = "create table customerTable (Id int, FirstName varchar(30), LastName varchar(30), Age smallint)";

  // execute all the sql statements
  for(int i = 0; i < 1; i++)
  {
    customerDataBaseRc = sqlite3_exec(customerDataBase, pSQL[i], callback, 0, &zErrMsg);

    if( customerDataBaseRc !=SQLITE_OK )
    {
      fprintf(stderr, "SQL error: %s\n", zErrMsg);
      sqlite3_free(zErrMsg);
      break; // break the loop if error occur
    }
  }
  //## end customer::customer%50F969EE01E4.body
}


customer::~customer ()
{
  //## begin customer::~customer%50F93279003E.body preserve=yes
  const char *pSQL[6];

  // Remove all data in customerTable
  pSQL[0] = "delete from customerTable";

  // Drop the table from database
  pSQL[1] = "drop table customerTable";

  // execute all the sql statements
  for(int i = 0; i < 2; i++)
  {
    customerDataBaseRc = sqlite3_exec(customerDataBase, pSQL[i], callback, 0, &zErrMsg);
    if( customerDataBaseRc !=SQLITE_OK )
    {
      fprintf(stderr, "SQL error: %s\n", zErrMsg);
      sqlite3_free(zErrMsg);
      break; // break the loop if error occur
    }
  }
  cout << "destructor";
  //## end customer::~customer%50F93279003E.body
}



//## Other Operations (implementation)
unsigned int customer::createCustomer (char  iCustomerFirstName[20], char  iCustomerLastName[20], unsigned short iCustomerAge)
{
  //## begin customer::createCustomer%50EBFFA3036B.body preserve=yes
  const char *sqlStatement;

  string result;          // string which will contain the result

  ostringstream convert;   // stream used for the conversion

  convert << "insert into customerTable (Id, FirstName, LastName, Age) values (" << customerId << ", '" << iCustomerFirstName << "', '" << iCustomerLastName << "', " << iCustomerAge << ")";
  result = convert.str(); // set 'Result' to the contents of the stream

  sqlStatement = result.c_str();

  // Execute sql statement
  customerDataBaseRc = sqlite3_exec(customerDataBase, sqlStatement, callback, 0, &zErrMsg);
  // Check for errors
  if(customerDataBaseRc !=SQLITE_OK )
  {
    fprintf(stderr, "SQL error: %s\n", zErrMsg);
    sqlite3_free(zErrMsg);
  }

  return customerId++;
  //## end customer::createCustomer%50EBFFA3036B.body
}

char * customer::getCustomer (unsigned int iCustomerId)
{
  //## begin customer::getCustomer%50ED3D700186.body preserve=yes
  const char *sqlStatement;

  char *tmp ="blabla";

  string result;          // string which will contain the result

  ostringstream convert;   // stream used for the conversion

  convert << "select * from customerTable where Id = " << iCustomerId;
  result = convert.str(); // set 'Result' to the contents of the stream

  sqlStatement = result.c_str();

  // Execute the sql statement
  customerDataBaseRc = sqlite3_exec(customerDataBase, sqlStatement, callback, 0, &zErrMsg);
  // Check for errors
  if(customerDataBaseRc !=SQLITE_OK )
  {
    fprintf(stderr, "SQL error: %s\n", zErrMsg);
    sqlite3_free(zErrMsg);
  }

  return tmp;
  //## end customer::getCustomer%50ED3D700186.body
}

// Additional Declarations
  //## begin customer%50E6CCB50119.declarations preserve=yes
  //## end customer%50E6CCB50119.declarations

//## begin module%50E6CCB50119.epilog preserve=yes
//## end module%50E6CCB50119.epilog
//客户
#包括“Customer\Customer.h”
//##开始模块%50E6CCB50119。附加声明=是
静态int回调(void*NotUsed,int argc,char**argv,char**azColName)
{
int i;
字符*列名称;
char*columnValueString;
short int columnValueShortInt=0;
int columnValueInt=0;

cout在这种情况下,人们通常会利用
void*
(您称之为
NotUsed
)回调参数——当你安装回调时定义的参数。对于C++,你通常会将参数设置为<代码>这个指向你感兴趣对象的指针,并且你会在你的类中(如有必要)在你的类中做出回调(A<代码>外部)C++“函数”,< <代码>朋友>代码>。 这看起来像这样:

class customer
{
    ...
public:
    int callback(int argc, char **argv, char **azColName);
};

static int c_callback(void *param, int argc, char **argv, char **azColName)
{
    customer* cust = reinterpret_cast<customer*>(param);
    return cust->callback(argc, argv, azColName);
}

char* customer::getCustomer(int id)
{
    ...
    rc = sqlite3_exec(db, sql, c_callback, this, &errMsg);
    ...
}

int customer::callback(int argc, char **argv, char **azColName)
{
    ...
}
void one_customer::readFromDB(sqlite3* db, int id)
{
    sqlite3_stmt *stmt;
    int rc = sqlite3_prepare_v2(db, "SELECT FirstName, LastName, Age"
                                    " FROM customerTable"
                                    " WHERE Id = ?", -1, &stmt, NULL);
    if (rc != SQLITE_OK)
        throw string(sqlite3_errmsg(db));

    rc = sqlite3_bind_int(stmt, 1, id);    // Using parameters ("?") is not
    if (rc != SQLITE_OK) {                 // really necessary, but recommended
        string errmsg(sqlite3_errmsg(db)); // (especially for strings) to avoid
        sqlite3_finalize(stmt);            // formatting problems and SQL
        throw errmsg;                      // injection attacks.
    }

    rc = sqlite3_step(stmt);
    if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
        string errmsg(sqlite3_errmsg(db));
        sqlite3_finalize(stmt);
        throw errmsg;
    }
    if (rc == SQLITE_DONE) {
        sqlite3_finalize(stmt);
        throw string("customer not found");
    }

    this->id         = id;
    this->first_name = string(sqlite3_column_text(stmt, 0));
    this->last_name  = string(sqlite3_column_text(stmt, 1));
    this->age        =        sqlite3_column_int(stmt, 2);

    sqlite3_finalize(stmt);
}
class客户
{
...
公众:
int回调(int argc,char**argv,char**azColName);
};
静态int c_回调(void*param,int argc,char**argv,char**azColName)
{
客户*cust=重新解释铸件(参数);
返回客户->回调(argc、argv、azColName);
}
char*customer::getCustomer(int-id)
{
...
rc=sqlite3_exec(db、sql、c_回调、this和errMsg);
...
}
int customer::回调(int argc,char**argv,char**azColName)
{
...
}
使用的缺点是,必须将某些值从字符串转换回数字,并且需要为所有结果记录分配内存(这可能导致读取大型表时出现问题)。 此外,回调始终是一个单独的函数(即使它在同一个类中)

对于您的示例查询,使用//API如下所示:

class customer
{
    ...
public:
    int callback(int argc, char **argv, char **azColName);
};

static int c_callback(void *param, int argc, char **argv, char **azColName)
{
    customer* cust = reinterpret_cast<customer*>(param);
    return cust->callback(argc, argv, azColName);
}

char* customer::getCustomer(int id)
{
    ...
    rc = sqlite3_exec(db, sql, c_callback, this, &errMsg);
    ...
}

int customer::callback(int argc, char **argv, char **azColName)
{
    ...
}
void one_customer::readFromDB(sqlite3* db, int id)
{
    sqlite3_stmt *stmt;
    int rc = sqlite3_prepare_v2(db, "SELECT FirstName, LastName, Age"
                                    " FROM customerTable"
                                    " WHERE Id = ?", -1, &stmt, NULL);
    if (rc != SQLITE_OK)
        throw string(sqlite3_errmsg(db));

    rc = sqlite3_bind_int(stmt, 1, id);    // Using parameters ("?") is not
    if (rc != SQLITE_OK) {                 // really necessary, but recommended
        string errmsg(sqlite3_errmsg(db)); // (especially for strings) to avoid
        sqlite3_finalize(stmt);            // formatting problems and SQL
        throw errmsg;                      // injection attacks.
    }

    rc = sqlite3_step(stmt);
    if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
        string errmsg(sqlite3_errmsg(db));
        sqlite3_finalize(stmt);
        throw errmsg;
    }
    if (rc == SQLITE_DONE) {
        sqlite3_finalize(stmt);
        throw string("customer not found");
    }

    this->id         = id;
    this->first_name = string(sqlite3_column_text(stmt, 0));
    this->last_name  = string(sqlite3_column_text(stmt, 1));
    this->age        =        sqlite3_column_int(stmt, 2);

    sqlite3_finalize(stmt);
}

(此代码通过错误代码发送<代码>字符串来处理错误。)/P>这是我当前的C++知识,而不是经验,必须对这一点进行处理。如果我通过这个指针,调用调用函数就可以填充类实例(对象)的属性。然后在sqlite3_exec调用完成后处理方法本身中的值?是的。您需要将传入的

void*
转换为对象指针类型,可能使用类似于
MyClass*object=(MyClass*)的内容NotUsed;
。从那时起,您可以访问有关对象的所有公共内容;如果您想访问私有(或受保护)内容,则需要(在类中)声明
回调()
是一个friend函数。您可以在google搜索中轻松找到friend函数的示例。谢谢,我将尝试实现您的建议,我已经研究了上面给出的示例。因此,看起来c_回调函数正在将sql查询的结果传递给类方法回调,然后可以在其中提取查询结果e place,即填充this pointer对象属性。然后在getCustomer中可以进行进一步的处理,对吗?通常,您会对每个
sqlite3_exec
调用使用一个单独的回调。这真的是最小的代码示例吗?不太可能,我想,我是这个论坛的新手,下次会尝试最小化代码,谢谢您的提示.人们给出如此有用和详细的解决方案的速度给我留下了深刻的印象,非常感谢。