web-dev-qa-db-ja.com

sqlite3_exec()コールバック関数の明確化

SQLite3データベースでのコールバック関数の使用を理解できません。

複数のレコードを持つSELECTステートメントをトラバースするために使用されることを理解しています。しかし、私はそれがそれをどのように行うか、または独自の有用なコールバックを作成する方法を理解していません。私は TutorialsPoint を何度も読み通して理解しようとしましたが、それは私のためにそれをしていません。

それらの例を使用してVisual Studioでデバッグし、引数配列がどのように生成され、トラバースされるかを確認すると、失われます。また、VSはアレイ全体ではなく、アレイ内の現在のスロットのみを表示します。

明確化が必要な場合は、私が学ぶためにここにいるのでお知らせください!

コールバックがどのように使用されるかを説明してくれる人を求めています。たぶん他の人がどのようにそれを使用したかのいくつかの例。これが何をしているのかの説明だけでも:

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

次のようなUserという非常に単純なテーブルがあるとします。

╔====╦==========╗
║ID║名前║
╟────╫──────── ───╢
║1║Slvrfn║
║2║Sean║
║3║Drew rew 
║4║mah║
╚ ====╩==========╝

そして、sqlite3_execを次のように呼び出します(引数の詳細は ドキュメントで )。

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

サンプルのテーブルとデータを考えると、出力は次のようになります。

 2つの列があります
列「ID」のデータは次のとおりです。1
列「Name」のデータは次のとおりです:Slvrfn 
 
 2つの列があります。
列「ID」のデータは次のとおりです:2 
列「Name」のデータは次のとおりです。Sean
 
そこ2列です。
列「ID」のデータは次のとおりです。3
列「名前」のデータは次のとおりです。Drew 
 
 2列あります。 (s)
列「ID」のデータは次のとおりです。4
列「Name」のデータは次のとおりです。mah

これをどのように便利にするか、それがsqlite3_execの4番目の引数の出番です。ドキュメントから:

Sqlite3_exec()の4番目の引数は、各コールバック呼び出しの1番目の引数に中継されます。

したがって、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);

出力は次のようになります。

ユーザー:
 ID = 1 
 Name = Slvrfn 
 
ユーザー:
 ID = 2 
 Name =ショーン
 
 ...など... 

User:部分はstdoutではなくstderrに出力されます)

うまくいけば、これはあなたのために物事をクリアするのに役立ちます。まだ分​​からないことがあるかどうか教えてください。

46
Sean Bright

sqlite3_exec()以外は使用しないため、このチュートリアルは恐ろしいものです。

一般的な場合、onlysqlite3_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);
27
CL.