てきとうなさいと べぇたばん

SQLite3をCでいじる

versionを表示するコードを書く

CからSQLiteをいじる

思うところがあって、SQLiteをCからいじるということをやってみた。

環境

  • WSL上のUbuntu 14.06(サポート切れ)
  • WSL上のUbuntu 16.04

これほど古いと、SQLiteのバージョンは3.8.2になるが、使える関数がなかったりする。

インストール

build-essentialとかはインストールしてある。

$ sudo apt install libsqlite3-dev

コード

SQLiteのバージョンを表示するコード

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

int main(void) {
    printf("SQLite3 lib number version: %d\n", sqlite3_libversion_number());
    printf("SQLite3 version: %s\n", sqlite3_version);
    return 0;
}

これをコンパイルする

$ gcc -Wall -o ver_sqlite3 ver_sqlite3.c -lsqlite3

実行

$ ./ver_sqlite3
SQLite3 lib number version: 3011000
SQLite3 version: 3.11.0

memoryに接続する

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

int main(void) {
    sqlite3 *db;
    sqlite3_stmt *res;

    int rc = sqlite3_open(":memory:", &db);

    if (rc != SQLITE_OK) {
        fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db));
        sqlite3_close(db);
        return 1;
    }

    // sqlite3_prepare_v3 が使えるのは 3.20.0 から
    // https://sqlite.org/changes.html#version_3_20_0
    rc = sqlite3_prepare_v2(db, "SELECT SQLITE_VERSION();", -1, &res, 0);

    if (rc != SQLITE_OK) {
        fprintf(stderr, "Failed to fetch data: %s\n", sqlite3_errmsg(db));
        sqlite3_close(db);
        return 1;
    }

    rc = sqlite3_step(res);
    if (rc == SQLITE_ROW) {
        printf("%s\n", sqlite3_column_text(res, 0));
    }

    sqlite3_finalize(res);
    sqlite3_close(db);

    return 0;
}

Carsというテーブルで色々する

Carsというテーブルに対して、まずSELECTで一行取得、Suzukiというnameの行があったらDELETEしてCarsのidのMAXを取得してからCarsにSuzukiというnameの行をINSERTする

簡単に言うと、実行するたびにSuzukiという行が追加されているが、ダブらない。

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

int main(void) {
    sqlite3 *db;
    sqlite3_stmt *res;

    // open
    int rc = sqlite3_open("test.db", &db);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db));
        sqlite3_close(db);
        return 1;
    }

    char *sql = "SELECT id, name FROM Cars WHERE id = ?";
    rc = sqlite3_prepare_v2(db, sql, -1, &res, 0);
    if (rc == SQLITE_OK) {
        sqlite3_bind_int(res, 1, 3);
    } else {
        fprintf(stderr, "Failed to execute statement: %s\n", sqlite3_errmsg(db));
    }

    int step = sqlite3_step(res);
    if (step == SQLITE_ROW) {
        printf("%s: ", sqlite3_column_text(res, 0));
        printf("%s\n", sqlite3_column_text(res, 1));
    }
    sqlite3_finalize(res);

    char *car_name = "Suzuki";

    // delete suzuki
    char *del = "DELETE FROM Cars WHERE name = ?;";
    rc = sqlite3_prepare_v2(db, del, -1, &res, 0);
    if (rc == SQLITE_OK) {
        sqlite3_bind_text(res, 1, car_name, strlen(car_name), SQLITE_TRANSIENT);
    } else {
        fprintf(stderr, "Faild to execute statement: %s\n", sqlite3_errmsg(db));
    }
    rc = sqlite3_step(res);
    if (rc != SQLITE_DONE) {
        fprintf(stderr, "execution failed: %s", sqlite3_errmsg(db));
    } else {
        printf("Delete completed\n");
    }

    // get max id
    char *last_row_sql = "SELECT MAX(id) FROM Cars;";
    rc = sqlite3_prepare_v2(db, last_row_sql, -1, &res, 0);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "Failed to execute statement: %s\n", sqlite3_errmsg(db));
        sqlite3_finalize(res);
        sqlite3_close(db);
        return 1;
    }

    int last_row_id = 0;
    step = sqlite3_step(res);
    if (step == SQLITE_ROW) {
        last_row_id = sqlite3_column_int(res, 0);
        printf("last_row_id: %d\n", last_row_id);
    }
    sqlite3_finalize(res);

    // insert suzuki
    char *ins = "INSERT INTO Cars(id, name, price) VALUES(?, ?, ?);";
    rc = sqlite3_prepare_v2(db, ins, -1, &res, 0);
    if (rc == SQLITE_OK) {
        sqlite3_bind_int(res, 1, last_row_id + 1);
        sqlite3_bind_text(res, 2, car_name, strlen(car_name), SQLITE_TRANSIENT);
        sqlite3_bind_int(res, 3, 29000);
    } else {
        fprintf(stderr, "Faild to execute statement: %s\n", sqlite3_errmsg(db));
    }

    rc = sqlite3_step(res);

    if (rc != SQLITE_DONE) {
        printf("execution failed: %s", sqlite3_errmsg(db));
    } else {
        printf("execution completed: %d\n", (int)sqlite3_last_insert_rowid(db));
    }

    sqlite3_finalize(res);
    sqlite3_close(db);
    return 0;
}

参考