GDBMを使ってみる2

GDBMを使ってみる1 - 日進月歩の続き.
今回はgdbmのデータベースに対してデータの挿入と読み込みについて考えていく.

まずデータベースとのやり取りにはdatum構造体を用いる.
定義は以下.

typedef struct {
char *dptr;
int dsize;
} datum;
keyとvalue共にこの構造体を用いてやりとりが行われる.

  • データの挿入

次にデータの挿入を考えていく.
データの挿入は以下の関数を通して行う.

int gdbm_store (
GDBM FILE dbf,
datum key,
datum content,
int flag )
引数dbfデータを挿入するデータベースを指定.
key, contentは挿入データのkeyとkeyに結びつけるvalueの値をdatum構造体を用いてそれぞれ指定する.
flagの値にはGDBM_REPLACEまたはGDBM_INSERTを指定する.
既にKey値が重複するデータがあった場合の動作が異なり,
GDBM_REPLACEを指定したときは上書きを行い,一方GDBM_INSERTを指定した場合には上書きは行わずエラーを返す.

また関数の戻り値は正常時には'0',GDBM_INSERTによるエラーの場合は'1',それ以外は'-1'を返す.

  • データの検索

次に,データベースから特定のkeyを元にデータを読み出すことを行う.
これは以下の関数で可能

datum gdbm_fetch (GDBM FILE dbf , datum key )
引数のdbfは検索対象のオープン済みのデータベースを指定.
keyには検索を行うキーの値を格納する.
検索を行い一致するデータご見つかった場合にはキーに対応するデータを戻り値として返す.
一方,データが存在しない場合には戻り値のdatum構造体のメンバーdptrにNULLがセットされる.

  • データの確認

指定したキーがデータベース内に存在するかの確認が以下の関数で行える.

int gdbm_exists (GDBM FILE dbf , datum key )
引数の対応はgdbm_fetch関数と同じ.
キーに対応するデータが存在する場合は'1'を,存在しないは'0'を,それぞれ戻り値として返す.

  • データの削除

データベースに格納されているデータの削除は以下の関数で行う.

int gdbm_delete (GDBM FILE dbf , datum key )
こちらも引数の対応はgdbm_fetch関数と同じである.
キーに一致するデータがある場合には削除し,'0'を戻り値として返す.
また一致するデータが存在しない場合や,その他のエラーは戻り値として'-1'を返す.

今回も最後にサンプルコードを記載.

Linuxプログラミング―例題で学ぶUNIXプログラミング環境のすべて

Linuxプログラミング―例題で学ぶUNIXプログラミング環境のすべて

のpp299-302の簡単なdbmの読み込みのサンプルソースをgdbm用に変更したものを記載する.
#include
#include
#include
#include
#include
#include

#define TEST_DB_FILE "dbm1_test"
#define ITEMS_USED 3
#define BLOCK_SIZE (4096)

struct test_data{
char misc_chars[15];
int any_integer;
char more_chars[21];
};

int main(){
struct test_data items_to_store[ITEMS_USED];
struct test_data item_retrieved;

char key_to_use[20];
int i, result;

datum key_datum;
datum data_datum;

GDBM_FILE dbm_ptr;

dbm_ptr = gdbm_open(TEST_DB_FILE, BLOCK_SIZE, GDBM_WRCREAT, 0666, NULL);
if(!dbm_ptr){
fprintf(stderr, "Failed to open database\n");
exit(EXIT_FAILURE);
}

memset(items_to_store, '\0', sizeof(items_to_store));
strcpy(items_to_store[0].misc_chars, "First!");
items_to_store[0].any_integer = 47;
strcpy(items_to_store[0].more_chars, "foo");

strcpy(items_to_store[1].misc_chars, "bar");
items_to_store[1].any_integer = 13;
strcpy(items_to_store[1].more_chars, "unlucky?");

strcpy(items_to_store[2].misc_chars, "Third");
items_to_store[2].any_integer = 3;
strcpy(items_to_store[2].more_chars, "baz");

for(i = 0; i < ITEMS_USED; i++){
sprintf(key_to_use, "%c%c%d",
items_to_store[i].misc_chars[0],
items_to_store[i].more_chars[0],
items_to_store[i].any_integer);
key_datum.dptr = (void *)key_to_use;
key_datum.dsize = strlen(key_to_use);
data_datum.dptr = (void *)&items_to_store[i];
data_datum.dsize = sizeof(struct test_data);

result = gdbm_store(dbm_ptr, key_datum, data_datum, GDBM_REPLACE);
if(result != 0){
fprintf(stderr, "gdbm_store failed on key %s", key_to_use);
exit(2);
}
}

sprintf(key_to_use, "bu%d", 13);
key_datum.dptr = key_to_use;
key_datum.dsize = strlen(key_to_use);

data_datum = gdbm_fetch(dbm_ptr, key_datum);
if(data_datum.dptr){
printf("Data retrieved\n");
memcpy(&item_retrieved, data_datum.dptr, data_datum.dsize);
printf("Retrieved tem - %s %d %s\n",
item_retrieved.misc_chars,
item_retrieved.any_integer,
item_retrieved.more_chars);
}
else{
printf("No data found for key %s\n", key_to_use);
}
gdbm_close(dbm_ptr);
exit(EXIT_SUCCESS);
}