sqlite3_exec() Callback function Clarification

时间:2015-06-30 19:23:10

标签: c++ sqlite callback

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

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 useful callback. I have read through TutorialsPoint several times to try to understand, but that is just not doing it for me.

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.

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

2 个答案:

答案 0 :(得分:43)

假设您有一个非常简单的表User,看起来像这样:

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

你这样调用sqlite3_exec(参数详细描述in the documentation):

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

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

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

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

现在,如何使这个有用,这就是sqlite3_exec的第四个参数的来源。来自文档:

  

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 ... */);

修改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;
}

现在,如果你要使用问题中包含的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);

输出结果为:

User: 
ID = 1
Name = Slvrfn

User: 
ID = 2
Name = Sean

... etc ...

User:部分将被打印到stderr而不是stdout)

希望这有助于为您解决问题。如果还有一些你不理解的东西,请告诉我。

答案 1 :(得分:26)

该教程非常糟糕,因为它除sqlite3_exec()之外不使用任何其他内容。

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

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);