/*
* call-seq:
* update(key, old_value, new_value, option={})
*
* レコードを追加する場合は old_value に nil を指定する。
* レコードを削除する場合は new_value に nil を指定する。
* レコードを更新する場合は old_value, new_value の両方を指定する。
*
* 有効な option:
* :section [Integer] :: セクション番号
*
* === Argument
* key [String/Integer] :: インデックス値
* old_value [String/Senna::Values] :: 古いレコード
* new_value [String/Senna::Values] :: 新しいレコード
*
* === Exception
* RuntimeError :: インデックスがクローズ済み
* RuntimeError :: key のサイズがインデックスファイルのものとあっていない
* TypeError :: open() で key_size に Integer が指定されているのに、key が整数でない
* TypeError :: old_value, new_value が String でも Senna::Values でもない
*/
static VALUE index_update(int argc, VALUE *argv, VALUE obj)
{
VALUE key, oldv, newv, opt, section;
struct index_data *data;
sen_rc rc;
char *_key;
long n;
VALUE skey;
int key_size;
VALUE key_type;
sen_values *_oldv=NULL, *_newv=NULL;
unsigned int _section=1;
rb_scan_args(argc, argv, "31", &key, &oldv, &newv, &opt);
Data_Get_Struct(obj, struct index_data, data);
if (data->closed)
rb_raise(rb_eRuntimeError, "already closed");
key_size = NUM2INT(rb_iv_get(obj, "key_size"));
key_type = rb_iv_get(obj, "key_type");
if (!NIL_P(key_type)) {
if (!rb_obj_is_kind_of(key, key_type))
rb_raise(rb_eTypeError, "wrong argument type %s (expected %s)", rb_obj_classname(key), rb_class_name(key_type));
}
if (key_size == 0) {
skey = StringValue(key);
_key = RSTRING_PTR(skey);
} else {
switch(TYPE(key)) {
case T_FIXNUM:
case T_BIGNUM:
if (key_size != sizeof(n))
rb_raise(rb_eRuntimeError, "invalid key_size: %d != %d", key_size, sizeof(n));
n = NUM2LONG(key);
_key = (char *)&n;
break;
default:
skey = StringValue(key);
if (key_size != RSTRING_LEN(skey))
rb_raise(rb_eRuntimeError, "invalid key_size: %d != %d", key_size, RSTRING_LEN(skey));
_key = RSTRING_PTR(skey);
break;
}
}
if (!NIL_P(oldv)) {
if (TYPE(oldv) == T_STRING) {
VALUE str = oldv;
oldv = values_new(cSennaValues);
values_add(oldv, str, INT2FIX(0));
} else {
if (!rb_obj_is_kind_of(oldv, cSennaValues))
rb_raise(rb_eTypeError, "wrong argument type %s (expected Senna::Values)", rb_obj_classname(oldv));
}
Data_Get_Struct(oldv, sen_values, _oldv);
}
if (!NIL_P(newv)) {
if (TYPE(newv) == T_STRING) {
VALUE str = newv;
newv = values_new(cSennaValues);
values_add(newv, str, INT2FIX(0));
} else {
if (!rb_obj_is_kind_of(newv, cSennaValues))
rb_raise(rb_eTypeError, "wrong argument type %s (expected Senna::Values)", rb_obj_classname(newv));
}
Data_Get_Struct(newv, sen_values, _newv);
}
if (!NIL_P(opt)) {
Check_Type(opt, T_HASH);
section = rb_hash_aref(opt, ID2SYM(rb_intern("section")));
_section = NIL_P(section) ? 1 : NUM2UINT(section);
}
rc = sen_index_update(data->indexp, _key, _section, _oldv, _newv);
if (rc != sen_success)
senna_error(rc, "cannot update: key=%s", _key);
return obj;
}