C++ sqlite3_exec() 回调函数说明

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31146713/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 13:52:02  来源:igfitidea点击:

sqlite3_exec() Callback function Clarification

c++sqlitecallback

提问by Slvrfn

I am having trouble understanding the use of the callback function in a SQLite3 database.

我无法理解在 SQLite3 数据库中使用回调函数。

I understand it is used to traverse SELECT statements with multiple records. But I do not understand how it does that or how to make my own usefulcallback. I have read through TutorialsPointseveral times to try to understand, but that is just not doing it for me.

我知道它用于遍历具有多条记录的 SELECT 语句。但我不明白它是如何做到的,也不明白如何制作我自己有用的回调。我已经多次通读 TutorialsPoint以试图理解,但这对我来说并不适合。

When I use their example and debug in Visual Studio to see how the argument arrays are populated and traversed i get lost. Also VS only shows the current slot in the array, not the entire array itself.

当我使用他们的示例并在 Visual Studio 中调试以查看如何填充和遍历参数数组时,我迷路了。此外,VS 仅显示阵列中的当前插槽,而不是整个阵列本身。

If you need any clarification please let me know as I am here to learn!

如果您需要任何说明,请告诉我,因为我是来学习的!

I am asking for someone to explain how the callback is used. Maybe some examples of how others have used it. Just an explanation of what this one is doing even:

我要求有人解释如何使用回调。也许是其他人如何使用它的一些例子。只是对这个人在做什么的一个解释:

static int callback(void *data, int argc, char **argv, char **azColName){
   int i;
   fprintf(stderr, "%s: ", (const char*)data);
   for(i=0; i<argc; i++){
      printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
   }
   printf("\n");
   return 0;
}

回答by Sean Bright

Let's assume you have a very simple table called Userthat looks something like this:

假设您有一个非常简单的表User,如下所示:

╔════╦══════════╗
║ ID ║ Name     ║
╟────╫──────────╢
║ 1  ║ Slvrfn   ║
║ 2  ║ Sean     ║
║ 3  ║ Drew     ║
║ 4  ║ mah      ║
╚════╩══════════╝

And you call sqlite3_execlike this (the arguments are described in detail in the documentation):

你这样调用sqlite3_exec(参数在文档中有详细描述):

/* Error handling omitted for brevity */
sqlite3_exec(db, "SELECT * FROM User", my_special_callback, NULL, NULL);

SQLite will execute the passed SQL statement and for every result row that it finds it will call my_special_callback. So with our example Usertable, my_special_callbackwill be called 4 times. So let's create my_special_callback:

SQLite 将执行传递的 SQL 语句,并为它找到的每个结果行调用my_special_callback. 所以对于我们的示例User表,my_special_callback将被调用 4 次。所以让我们创建my_special_callback

/*
 * Arguments:
 *
 *   unused - Ignored in this case, see the documentation for sqlite3_exec
 *    count - The number of columns in the result set
 *     data - The row's data
 *  columns - The column names
 */
static int my_special_callback(void *unused, int count, char **data, char **columns)
{
    int idx;

    printf("There are %d column(s)\n", count);

    for (idx = 0; idx < count; idx++) {
        printf("The data in column \"%s\" is: %s\n", columns[idx], data[idx]);
    }

    printf("\n");

    return 0;
}

Given our example table and data, the output will look like this:

给定我们的示例表和数据,输出将如下所示:

There are 2 column(s)
The data in column "ID" is: 1
The data in column "Name" is: Slvrfn

There are 2 column(s)
The data in column "ID" is: 2
The data in column "Name" is: Sean

There are 2 column(s)
The data in column "ID" is: 3
The data in column "Name" is: Drew

There are 2 column(s)
The data in column "ID" is: 4
The data in column "Name" is: mah

Now to how to make this useful, that is where the 4th argument to sqlite3_execcomes in. From the documentation:

现在如何使它有用,这就是第 4 个参数的sqlite3_exec用武之地。来自文档:

The 4th argument to sqlite3_exec() is relayed through to the 1st argument of each callback invocation.

sqlite3_exec() 的第四个参数传递到每个回调调用的第一个参数。

So let's say that we want to run our SQL and build a linked list of the names of all of our users. The first thing we need to do is change how we are calling sqlite3_exec:

因此,假设我们要运行 SQL 并构建所有用户姓名的链表。我们需要做的第一件事是改变我们的调用方式sqlite3_exec

/* Create my fictional linked list */
struct my_linked_list *head = my_linked_list_alloc();

/*
 * Pass a pointer to my list as the 4th argument to sqlite3_exec. Error
 * handling omitted for brevity
 */
sqlite3_exec(db, "SELECT * FROM User", my_special_callback, head, NULL);

/* My list is now built, I can do stuff with it... */
my_linked_list_traverse(head, /* ... Stuff ... */);

And modify my_special_callbackto use it

并修改my_special_callback使用它

/*
 * Arguments:
 *
 *     list - Pointer to a linked list of names
 *    count - The number of columns in the result set
 *     data - The row's data
 *  columns - The column names
 */
static int my_special_callback(void *list, int count, char **data, char **columns)
{
    struct my_linked_list *head = list;

    /*
     * We know that the value from the Name column is in the second slot
     * of the data array.
     */
    my_linked_list_append(head, data[1]);

    return 0;
}

Now, if you were to use the callbackyou included in your question, you would call it like this:

现在,如果您要使用callback问题中包含的您,您可以这样称呼它:

/*
 * Pass the table name as the 4th argument to sqlite3_exec. Error
 * handling omitted for brevity
 */
sqlite3_exec(db, "SELECT * FROM User", callback, "User", NULL);

The output would be:

输出将是:

User: 
ID = 1
Name = Slvrfn

User: 
ID = 2
Name = Sean

... etc ...

(Except the User:part would be printed to stderr instead of stdout)

(除了User:部分将打印到 stderr 而不是 stdout)

Hopefully this helps clear things up for you. Let me know if there is still something that you don't understand.

希望这有助于为您解决问题。如果您还有不明白的地方,请告诉我。

回答by CL.

That tutorial is horrible, because it does not use anything but sqlite3_exec().

该教程很糟糕,因为它除了sqlite3_exec().

In the general case, the onlyuseful way to use sqlite3_exec()is to replace it with sqlite3_prepare_v2()/sqlite3_step()/sqlite3_column_*()/sqlite3_finalize()calls so that you can read the data in the same place where you actually need to handle it:

在一般情况下,唯一有用的使用方法sqlite3_exec()是将其替换为sqlite3_prepare_v2()/ sqlite3_step()/ sqlite3_column_*()/ sqlite3_finalize()调用,以便您可以在实际需要处理的同一个地方读取数据它:

sqlite3_stmt *stmt;
const char *sql = "SELECT ID, Name FROM User";
int rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
if (rc != SQLITE_OK) {
    print("error: ", sqlite3_errmsg(db));
    return;
}
while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
    int id           = sqlite3_column_int (stmt, 0);
    const char *name = sqlite3_column_text(stmt, 1);
    // ...
}
if (rc != SQLITE_DONE) {
    print("error: ", sqlite3_errmsg(db));
}
sqlite3_finalize(stmt);