slim-attributes 0.1 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README +7 -10
- data/ext/slim_attrib_ext.c +22 -43
- metadata +2 -2
data/README
CHANGED
@@ -13,10 +13,13 @@ Installation
|
|
13
13
|
|
14
14
|
You're going to need the mysql headers for this to work.
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
Try:
|
17
|
+
gem install slim-attributes -- --with-mysql-config
|
18
|
+
or:
|
19
|
+
gem install slim-attributes
|
20
|
+
|
21
|
+
then add this to environment.rb:
|
22
|
+
require 'slim_attributes'
|
20
23
|
|
21
24
|
|
22
25
|
Description
|
@@ -32,12 +35,6 @@ So this is an alternative implementation of all_hashes that returns a 'fake hash
|
|
32
35
|
|
33
36
|
The field contents are then instantiated into Ruby strings on demand - ruby strings are only made if you need them. Note that if you always look at all the columns when you fetch data from the database then this won't necessarily be faster that the unpatched mysql adapter. But it won't be much slower either, and we do expect that most times not all the columns from a result set are accessed.
|
34
37
|
|
35
|
-
Note that the 'fake hash' quacks like a hash in many ways, but not all ways. So @attributes in an ActiveRecord object may not behave as you are expecting it to, and it particularly won't work if you try to add a key to it that is not a column name in the result set.
|
36
|
-
|
37
|
-
@attributes["not a column name"] = "something"
|
38
|
-
=> RuntimeError: Key was not a column name from the result set
|
39
|
-
|
40
|
-
Hash has many methods that are not supported by the fake hash, but I found that the ones I have implemented have been sufficient for use in our Rails app. It should be fairly easy to implement most of the missing methods if needed, but I did not wish this patch to be larger than necessary.
|
41
38
|
|
42
39
|
===========
|
43
40
|
|
data/ext/slim_attrib_ext.c
CHANGED
@@ -25,12 +25,12 @@ static VALUE all_hashes(VALUE obj) {
|
|
25
25
|
MYSQL_RES *res = GetMysqlRes(obj);
|
26
26
|
MYSQL_FIELD *fields = mysql_fetch_fields(res);
|
27
27
|
MYSQL_ROW row;
|
28
|
-
VALUE all_hashes_ary, col_names_hsh,
|
28
|
+
VALUE all_hashes_ary, col_names_hsh, frh;
|
29
29
|
my_ulonglong nr = mysql_num_rows(res);
|
30
30
|
unsigned int nf = mysql_num_fields(res);
|
31
|
-
unsigned int i, j, s;
|
31
|
+
unsigned int i, j, s, len;
|
32
32
|
unsigned long *lengths;
|
33
|
-
char *
|
33
|
+
char *row_info_space, **pointers_space, *p;
|
34
34
|
|
35
35
|
/* hash of column names */
|
36
36
|
col_names_hsh = rb_hash_new();
|
@@ -40,64 +40,46 @@ static VALUE all_hashes(VALUE obj) {
|
|
40
40
|
|
41
41
|
/* array of result rows */
|
42
42
|
all_hashes_ary = rb_ary_new2(nr);
|
43
|
-
for (i=0; i<nr; i++) {
|
44
|
-
VALUE frh;
|
45
|
-
frh = rb_class_new_instance(0, NULL, cRowHash);
|
46
|
-
rb_iv_set(frh, "@field_indexes", col_names_hsh);
|
43
|
+
for (i=0; i < nr; i++) {
|
47
44
|
row = mysql_fetch_row(res); // get the row
|
48
|
-
|
49
|
-
row_ary = rb_ary_new();
|
50
|
-
rb_iv_set(frh, "@row", row_ary); // ready to hold fetched fields
|
51
|
-
|
52
45
|
lengths = mysql_fetch_lengths(res); // get lengths
|
53
46
|
for (s=j=0; j < nf; j++) s += lengths[j]; // s = total of lengths
|
54
|
-
|
55
|
-
pointers_space =
|
47
|
+
pointers_space = malloc((nf + 1) * sizeof(char *) + s); // storage for pointers to data followed by data
|
48
|
+
p = *pointers_space = (char *)(pointers_space + nf + 1); // pointer to first data item
|
56
49
|
row_info_space = calloc(nf, 1);
|
57
|
-
for (
|
58
|
-
|
59
|
-
char *p = row_space + s;
|
60
|
-
s += len;
|
61
|
-
pointers_space[j] = p;
|
50
|
+
for (j=0; j < nf; j++) {
|
51
|
+
len = (unsigned int)lengths[j];
|
62
52
|
if (!row[j]) row_info_space[j] = SLIM_IS_NULL;
|
63
53
|
else memcpy(p, row[j], len); // copy row data in
|
54
|
+
pointers_space[j + 1] = p += len;
|
64
55
|
}
|
65
|
-
|
56
|
+
frh = rb_class_new_instance(0, NULL, cRowHash);
|
66
57
|
rb_iv_set(frh, "@pointers", Data_Wrap_Struct(cClass, 0, free, pointers_space));
|
67
58
|
rb_iv_set(frh, "@row_info", Data_Wrap_Struct(cClass, 0, free, row_info_space));
|
68
|
-
rb_iv_set(frh, "@
|
59
|
+
rb_iv_set(frh, "@field_indexes", col_names_hsh);
|
60
|
+
rb_iv_set(frh, "@row", rb_ary_new()); // ready to hold fetched fields
|
69
61
|
rb_ary_store(all_hashes_ary, i, frh);
|
70
62
|
}
|
71
63
|
return all_hashes_ary;
|
72
64
|
}
|
73
65
|
|
74
66
|
static VALUE fetch_by_index(VALUE obj, VALUE index) {
|
75
|
-
VALUE row_ary,
|
76
|
-
char *
|
77
|
-
long col_number;
|
67
|
+
VALUE row_ary, contents;
|
68
|
+
char *row_info, **pointers, *start;
|
69
|
+
long col_number = FIX2LONG(index);
|
78
70
|
unsigned int length;
|
79
71
|
|
80
|
-
|
81
|
-
|
72
|
+
row_info = GetCharPtr(rb_iv_get(obj, "@row_info")) + col_number;
|
73
|
+
if (*row_info == SLIM_IS_NULL) return Qnil; // return nil if null from db
|
82
74
|
row_ary = rb_iv_get(obj, "@row");
|
83
|
-
if (
|
84
|
-
else {
|
85
|
-
row_info = GetCharPtr(row_info_obj);
|
86
|
-
if (row_info[col_number] == SLIM_IS_SET) return rb_ary_entry(row_ary, col_number); // was set already, return array entry
|
87
|
-
}
|
88
|
-
|
89
|
-
if (row_info[col_number] == SLIM_IS_NULL) { // return nil if null from db
|
90
|
-
rb_ary_store(row_ary, col_number, Qnil);
|
91
|
-
row_info[col_number] = SLIM_IS_SET;
|
92
|
-
return Qnil;
|
93
|
-
}
|
75
|
+
if (*row_info == SLIM_IS_SET) return rb_ary_entry(row_ary, col_number); // was set already, return array entry
|
94
76
|
|
95
77
|
pointers = GetCharStarPtr(rb_iv_get(obj, "@pointers"));
|
96
78
|
start = pointers[col_number];
|
97
79
|
length = pointers[col_number + 1] - start;
|
98
80
|
contents = rb_tainted_str_new(start, length);
|
99
81
|
rb_ary_store(row_ary, col_number, contents);
|
100
|
-
row_info
|
82
|
+
*row_info = SLIM_IS_SET;
|
101
83
|
return contents;
|
102
84
|
}
|
103
85
|
|
@@ -112,7 +94,6 @@ static VALUE slim_fetch(VALUE obj, VALUE name) {
|
|
112
94
|
|
113
95
|
static VALUE set_element(VALUE obj, VALUE name, VALUE val) {
|
114
96
|
VALUE real_hash, hash_lookup;
|
115
|
-
VALUE row_ary, row_info_obj;
|
116
97
|
long col_number;
|
117
98
|
|
118
99
|
real_hash = rb_iv_get(obj, "@real_hash");
|
@@ -120,11 +101,9 @@ static VALUE set_element(VALUE obj, VALUE name, VALUE val) {
|
|
120
101
|
|
121
102
|
hash_lookup = rb_hash_aref(rb_iv_get(obj, "@field_indexes"), name);
|
122
103
|
if (NIL_P(hash_lookup)) return rb_funcall(rb_funcall(obj, rb_intern("to_hash"), 0), rb_intern("[]="), 2, name, val);
|
123
|
-
row_ary = rb_iv_get(obj, "@row");
|
124
104
|
col_number = FIX2LONG(hash_lookup);
|
125
|
-
rb_ary_store(
|
126
|
-
|
127
|
-
if (!NIL_P(row_info_obj)) GetCharPtr(row_info_obj)[col_number] = SLIM_IS_SET;
|
105
|
+
rb_ary_store(rb_iv_get(obj, "@row"), col_number, val);
|
106
|
+
GetCharPtr(rb_iv_get(obj, "@row_info"))[col_number] = SLIM_IS_SET;
|
128
107
|
return val;
|
129
108
|
}
|
130
109
|
|
@@ -135,7 +114,7 @@ void Init_slim_attrib_ext() {
|
|
135
114
|
rb_define_method(c, "all_hashes", (VALUE(*)(ANYARGS))all_hashes, 0);
|
136
115
|
cRowHash = rb_const_get_at(c, rb_intern("RowHash"));
|
137
116
|
cClass = rb_define_class("CObjects", cRowHash);
|
138
|
-
|
117
|
+
rb_define_private_method(cRowHash, "fetch_by_index", (VALUE(*)(ANYARGS))fetch_by_index, 1);
|
139
118
|
rb_define_method(cRowHash, "[]", (VALUE(*)(ANYARGS))slim_fetch, 1);
|
140
119
|
rb_define_method(cRowHash, "[]=", (VALUE(*)(ANYARGS))set_element, 2);
|
141
120
|
}
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
|
|
3
3
|
specification_version: 1
|
4
4
|
name: slim-attributes
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: "0.
|
7
|
-
date: 2008-04-
|
6
|
+
version: "0.2"
|
7
|
+
date: 2008-04-09 00:00:00 +03:00
|
8
8
|
summary: Slim attributes boosts speed in Rails/Mysql ActiveRecord Models by avoiding instantiating Hashes for each result row, and lazily instantiating attributes as needed
|
9
9
|
require_paths:
|
10
10
|
- lib
|