ext/slim_attrib_ext.c in slim-attributes-0.6.6 vs ext/slim_attrib_ext.c in slim-attributes-0.7.1
- old
+ new
@@ -16,11 +16,12 @@
#define GetMysqlRes(obj) (Check_Type(obj, T_DATA), ((struct mysql_res*)DATA_PTR(obj))->res)
#define GetCharPtr(obj) (Check_Type(obj, T_DATA), (char*)DATA_PTR(obj))
#define GetCharStarPtr(obj) (Check_Type(obj, T_DATA), (char**)DATA_PTR(obj))
VALUE cRowHash, cClass;
-ID pointers_id, row_info_id, field_indexes_id, real_hash_id, to_hash_id;
+ID pointers_id, row_info_id, field_indexes_id, real_hash_id, to_hash_id, sq_parens_id,
+ sq_parens_equal_id, has_key_id;
#define MAX_CACHED_COLUMN_IDS 40
ID column_ids[MAX_CACHED_COLUMN_IDS];
// from mysql/ruby
@@ -28,12 +29,12 @@
MYSQL_RES* res;
char freed;
};
// row info
-#define SLIM_IS_NULL (char)0x01
-#define SLIM_IS_SET (char)0x02
+#define SLIM_IS_NULL 0x01
+#define SLIM_IS_SET 0x02
#define GET_COL_IV_ID(str, cnum) (cnum < MAX_CACHED_COLUMN_IDS ? column_ids[cnum] : (sprintf(str, "@col_%ld", cnum), rb_intern(str)))
#define REAL_HASH_EXISTS NIL_P(field_indexes = rb_ivar_get(obj, field_indexes_id))
@@ -101,11 +102,11 @@
char *row_info, **pointers, *start, col_name[16];
ID col_id;
long col_number = FIX2LONG(index);
unsigned int length;
row_info = GetCharPtr(rb_ivar_get(obj, row_info_id)) + col_number; // flags for this column
- if (*row_info == SLIM_IS_NULL) return Qnil; // return nil if null from db
+ if (*row_info & SLIM_IS_NULL) return Qnil; // return nil if null from db
col_id = GET_COL_IV_ID(col_name, col_number);
if (*row_info == SLIM_IS_SET) return rb_ivar_get(obj, col_id); // was made to a string already
pointers = GetCharStarPtr(rb_ivar_get(obj, pointers_id)); // find the data and make ruby string
start = pointers[col_number];
length = pointers[col_number + 1] - start;
@@ -116,16 +117,20 @@
}
// This is the [] method of the row data object.
// It checks for a real hash, but if none exists it will call fetch_by_index
static VALUE slim_fetch(VALUE obj, VALUE name) {
- VALUE field_indexes, hash_lookup;
+ VALUE field_indexes, hash_lookup, real_hash;
- if (REAL_HASH_EXISTS) return rb_hash_aref(rb_ivar_get(obj, real_hash_id), name);
+ if (REAL_HASH_EXISTS) return rb_funcall(rb_ivar_get(obj, real_hash_id), sq_parens_id, 1, name);
hash_lookup = rb_hash_aref(field_indexes, name);
- if (NIL_P(hash_lookup)) return Qnil;
+ if (NIL_P(hash_lookup)) {
+ real_hash = rb_ivar_get(obj, real_hash_id);
+ if (NIL_P(real_hash)) return Qnil;
+ return rb_funcall(real_hash, sq_parens_id, 1, name);
+ }
return fetch_by_index(obj, hash_lookup);
}
// This is the []= method of the row data object.
// It either operates on the real hash if it exists, or sets the appropriate
@@ -134,14 +139,14 @@
VALUE field_indexes, hash_lookup;
long col_number;
char col_name[16];
ID col_id;
- if (REAL_HASH_EXISTS) return rb_hash_aset(rb_ivar_get(obj, real_hash_id), name, val);
+ if (REAL_HASH_EXISTS) return rb_funcall(rb_ivar_get(obj, real_hash_id), sq_parens_equal_id, 2, name, val);
hash_lookup = rb_hash_aref(field_indexes, name);
- if (NIL_P(hash_lookup)) return rb_hash_aset(rb_funcall(obj, to_hash_id, 0), name, val);
+ if (NIL_P(hash_lookup)) return rb_funcall(rb_funcall(obj, to_hash_id, 0), sq_parens_equal_id, 2, name, val);
col_number = FIX2LONG(hash_lookup);
col_id = GET_COL_IV_ID(col_name, col_number);
rb_ivar_set(obj, col_id, val);
GetCharPtr(rb_ivar_get(obj, row_info_id))[col_number] = SLIM_IS_SET;
return val;
@@ -182,19 +187,24 @@
// This is the has_key? method of the row data object.
// Calls to model property methods in AR cause a call to has_key?, so it
// is implemented here in C for speed.
static VALUE has_key(VALUE obj, VALUE name) {
- VALUE field_indexes;
+ VALUE field_indexes, real_hash;
#ifdef RHASH_TBL
if (REAL_HASH_EXISTS) return (st_lookup(RHASH_TBL(rb_ivar_get(obj, real_hash_id)), name, 0) ? Qtrue : Qfalse);
- else return (st_lookup(RHASH_TBL(field_indexes), name, 0) ? Qtrue : Qfalse);
+ else if (st_lookup(RHASH_TBL(field_indexes), name, 0)) return Qtrue;
#else
if (REAL_HASH_EXISTS) return (st_lookup(RHASH(rb_ivar_get(obj, real_hash_id))->tbl, name, 0) ? Qtrue : Qfalse);
- else return (st_lookup(RHASH(field_indexes)->tbl, name, 0) ? Qtrue : Qfalse);
+ else if (st_lookup(RHASH(field_indexes)->tbl, name, 0)) return Qtrue;
#endif
+ else {
+ real_hash = rb_ivar_get(obj, real_hash_id);
+ if (NIL_P(real_hash)) return Qfalse;
+ return rb_funcall(real_hash, has_key_id, 1, name);
+ }
}
void Init_slim_attrib_ext() {
int i;
char col_name[16];
@@ -208,16 +218,21 @@
// set up methods
rb_define_private_method(cRowHash, "fetch_by_index", (VALUE(*)(ANYARGS))fetch_by_index, 1);
rb_define_method(cRowHash, "[]", (VALUE(*)(ANYARGS))slim_fetch, 1);
rb_define_method(cRowHash, "[]=", (VALUE(*)(ANYARGS))set_element, 2);
rb_define_method(cRowHash, "dup", (VALUE(*)(ANYARGS))slim_dup, 0);
- rb_define_method(cRowHash, "has_key?", (VALUE(*)(ANYARGS))has_key, 1);
+ rb_define_method(cRowHash, "has_key?", (VALUE(*)(ANYARGS))has_key, 1);
+ rb_define_method(cRowHash, "accessed_keys", (VALUE(*)(ANYARGS))accessed_keys, 0);
+
// set up some symbols that we will need
pointers_id = rb_intern("@pointers");
row_info_id = rb_intern("@row_info");
field_indexes_id = rb_intern("@field_indexes");
real_hash_id = rb_intern("@real_hash");
to_hash_id = rb_intern("to_hash");
+ sq_parens_id = rb_intern("[]");
+ sq_parens_equal_id = rb_intern("[]=");
+ has_key_id = rb_intern("has_key?");
for(i=0; i < MAX_CACHED_COLUMN_IDS; i++) {
sprintf(col_name, "@col_%d", i);
column_ids[i] = rb_intern(col_name);
}
}