extralite 1.27 → 2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -20,7 +20,8 @@
20
20
  #define SAFE(f) (VALUE (*)(VALUE))(f)
21
21
 
22
22
  extern VALUE cDatabase;
23
- extern VALUE cPreparedStatement;
23
+ extern VALUE cQuery;
24
+ extern VALUE cIterator;
24
25
 
25
26
  extern VALUE cError;
26
27
  extern VALUE cSQLError;
@@ -33,32 +34,64 @@ extern ID ID_new;
33
34
  extern ID ID_strip;
34
35
  extern ID ID_to_s;
35
36
 
37
+ extern VALUE SYM_hash;
38
+ extern VALUE SYM_ary;
39
+ extern VALUE SYM_single_column;
40
+
36
41
  typedef struct {
37
42
  sqlite3 *sqlite3_db;
38
- VALUE trace_block;
43
+ VALUE trace_block;
39
44
  } Database_t;
40
45
 
41
46
  typedef struct {
42
- VALUE db;
43
- VALUE sql;
44
- Database_t *db_struct;
45
- sqlite3 *sqlite3_db;
46
- sqlite3_stmt *stmt;
47
- } PreparedStatement_t;
47
+ VALUE db;
48
+ VALUE sql;
49
+ Database_t *db_struct;
50
+ sqlite3 *sqlite3_db;
51
+ sqlite3_stmt *stmt;
52
+ int eof;
53
+ int closed;
54
+ } Query_t;
55
+
56
+ enum iterator_mode {
57
+ ITERATOR_HASH,
58
+ ITERATOR_ARY,
59
+ ITERATOR_SINGLE_COLUMN
60
+ };
48
61
 
49
62
  typedef struct {
50
- VALUE self;
51
- sqlite3 *sqlite3_db;
52
- sqlite3_stmt *stmt;
53
- VALUE params;
63
+ VALUE query;
64
+ enum iterator_mode mode;
65
+ } Iterator_t;
66
+
67
+ enum query_mode {
68
+ QUERY_YIELD,
69
+ QUERY_MULTI_ROW,
70
+ QUERY_SINGLE_ROW
71
+ };
72
+
73
+ typedef struct {
74
+ VALUE self;
75
+ sqlite3 *sqlite3_db;
76
+ sqlite3_stmt *stmt;
77
+ VALUE params;
78
+ enum query_mode mode;
79
+ int max_rows;
80
+ int eof;
54
81
  } query_ctx;
55
82
 
56
83
  typedef struct {
57
- VALUE dst;
58
- VALUE src;
59
- sqlite3_backup *p;
84
+ VALUE dst;
85
+ VALUE src;
86
+ sqlite3_backup *p;
60
87
  } backup_t;
61
88
 
89
+ #define TUPLE_MAX_EMBEDDED_VALUES 20
90
+ #define ALL_ROWS -1
91
+ #define SINGLE_ROW -2
92
+ #define QUERY_MODE(default) (rb_block_given_p() ? QUERY_YIELD : default)
93
+ #define MULTI_ROW_P(mode) (mode == QUERY_MULTI_ROW)
94
+
62
95
  VALUE safe_execute_multi(query_ctx *ctx);
63
96
  VALUE safe_query_ary(query_ctx *ctx);
64
97
  VALUE safe_query_columns(query_ctx *ctx);
@@ -67,11 +100,23 @@ VALUE safe_query_single_column(query_ctx *ctx);
67
100
  VALUE safe_query_single_row(query_ctx *ctx);
68
101
  VALUE safe_query_single_value(query_ctx *ctx);
69
102
 
103
+ VALUE Query_each_hash(VALUE self);
104
+ VALUE Query_each_ary(VALUE self);
105
+ VALUE Query_each_single_column(VALUE self);
106
+
107
+ VALUE Query_next_hash(int argc, VALUE *argv, VALUE self);
108
+ VALUE Query_next_ary(int argc, VALUE *argv, VALUE self);
109
+ VALUE Query_next_single_column(int argc, VALUE *argv, VALUE self);
110
+
111
+ VALUE Query_to_a_hash(VALUE self);
112
+ VALUE Query_to_a_ary(VALUE self);
113
+ VALUE Query_to_a_single_column(VALUE self);
114
+
70
115
  void prepare_single_stmt(sqlite3 *db, sqlite3_stmt **stmt, VALUE sql);
71
116
  void prepare_multi_stmt(sqlite3 *db, sqlite3_stmt **stmt, VALUE sql);
72
117
  void bind_all_parameters(sqlite3_stmt *stmt, int argc, VALUE *argv);
73
118
  void bind_all_parameters_from_object(sqlite3_stmt *stmt, VALUE obj);
74
- int stmt_iterate(sqlite3_stmt *stmt, sqlite3 *db);
119
+ int stmt_iterate(query_ctx *ctx);
75
120
  VALUE cleanup_stmt(query_ctx *ctx);
76
121
 
77
122
  sqlite3 *Database_sqlite3_db(VALUE self);
@@ -1,7 +1,9 @@
1
1
  void Init_ExtraliteDatabase();
2
- void Init_ExtralitePreparedStatement();
2
+ void Init_ExtraliteQuery();
3
+ void Init_ExtraliteIterator();
3
4
 
4
5
  void Init_extralite_ext(void) {
5
6
  Init_ExtraliteDatabase();
6
- Init_ExtralitePreparedStatement();
7
+ Init_ExtraliteQuery();
8
+ Init_ExtraliteIterator();
7
9
  }
@@ -0,0 +1,180 @@
1
+ #include <stdio.h>
2
+ #include "extralite.h"
3
+
4
+ /*
5
+ * Document-class: Extralite::Iterator
6
+ *
7
+ * This class implements an iterator used to iterate through query results.
8
+ */
9
+
10
+ VALUE cIterator;
11
+
12
+ VALUE SYM_hash;
13
+ VALUE SYM_ary;
14
+ VALUE SYM_single_column;
15
+
16
+ static size_t Iterator_size(const void *ptr) {
17
+ return sizeof(Iterator_t);
18
+ }
19
+
20
+ static void Iterator_mark(void *ptr) {
21
+ Iterator_t *iterator = ptr;
22
+ rb_gc_mark(iterator->query);
23
+ }
24
+
25
+ static const rb_data_type_t Iterator_type = {
26
+ "Iterator",
27
+ {Iterator_mark, free, Iterator_size,},
28
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
29
+ };
30
+
31
+ static VALUE Iterator_allocate(VALUE klass) {
32
+ Iterator_t *iterator = ALLOC(Iterator_t);
33
+ iterator->query = Qnil;
34
+ return TypedData_Wrap_Struct(klass, &Iterator_type, iterator);
35
+ }
36
+
37
+ static inline Iterator_t *value_to_iterator(VALUE obj) {
38
+ Iterator_t *iterator;
39
+ TypedData_Get_Struct((obj), Iterator_t, &Iterator_type, (iterator));
40
+ return iterator;
41
+ }
42
+
43
+ static inline enum iterator_mode symbol_to_mode(VALUE sym) {
44
+ if (sym == SYM_hash) return ITERATOR_HASH;
45
+ if (sym == SYM_ary) return ITERATOR_ARY;
46
+ if (sym == SYM_single_column) return ITERATOR_SINGLE_COLUMN;
47
+
48
+ rb_raise(cError, "Invalid iterator mode");
49
+ }
50
+
51
+ /* Initializes an iterator using the given query object and iteration mode. The
52
+ * iteration mode is one of: `:hash`, `:ary`, or `:single_column`. An iterator
53
+ * is normally returned from one of the methods `Query#each`/`Query#each_hash`,
54
+ * `Query#each_ary` or `Query#each_single_column` when called without a block:
55
+ *
56
+ * iterator = query.each
57
+ * ...
58
+ *
59
+ * @param query [Extralite::Query] associated query
60
+ * @param mode [Symbol] iteration mode
61
+ * @return [void]
62
+ */
63
+ VALUE Iterator_initialize(VALUE self, VALUE query, VALUE mode) {
64
+ Iterator_t *iterator = value_to_iterator(self);
65
+
66
+ iterator->query = query;
67
+ iterator->mode = symbol_to_mode(mode);
68
+
69
+ return Qnil;
70
+ }
71
+
72
+ typedef VALUE (*each_method)(VALUE);
73
+
74
+ inline each_method mode_to_each_method(enum iterator_mode mode) {
75
+ switch (mode) {
76
+ case ITERATOR_ARY:
77
+ return Query_each_ary;
78
+ case ITERATOR_SINGLE_COLUMN:
79
+ return Query_each_single_column;
80
+ default:
81
+ return Query_each_hash;
82
+ }
83
+ }
84
+
85
+ /* Iterates through the associated query's result set using the iteration mode
86
+ * set when initialized. Each row would be passed to the given block according
87
+ * to the iteration mode, i.e. as a hash, an array, or a single value. In
88
+ * `:single column` mode an error will be raised if the result sets contains
89
+ * more than one columns.
90
+ *
91
+ * @return [Extralite::Iterator] self
92
+ */
93
+ VALUE Iterator_each(VALUE self) {
94
+ if (rb_block_given_p()) {
95
+ Iterator_t *iterator = value_to_iterator(self);
96
+ each_method method = mode_to_each_method(iterator->mode);
97
+ method(iterator->query);
98
+ }
99
+
100
+ return self;
101
+ }
102
+
103
+ typedef VALUE (*next_method)(int, VALUE *, VALUE);
104
+
105
+ inline next_method mode_to_next_method(enum iterator_mode mode) {
106
+ switch (mode) {
107
+ case ITERATOR_ARY:
108
+ return Query_next_ary;
109
+ case ITERATOR_SINGLE_COLUMN:
110
+ return Query_next_single_column;
111
+ default:
112
+ return Query_next_hash;
113
+ }
114
+ }
115
+
116
+ /* Returns the next 1 or more rows from the associated query's result set
117
+ * according to the iteration mode, i.e. as a hash, an array or a single value.
118
+ *
119
+ * If no row count is given, a single row is returned. If a row count is given,
120
+ * an array containing up to the `row_count` rows is returned. If `row_count` is
121
+ * -1, all rows are returned. If the end of the result set has been reached,
122
+ * `nil` is returned.
123
+ *
124
+ * If a block is given, rows are passed to the block and self is returned.
125
+ *
126
+ * @overload next()
127
+ * @return [Hash, Array, Object, Extralite::Iterator] next row or self if block is given
128
+ * @overload next(row_count)
129
+ * @param row_count [Integer] maximum row count or -1 for all rows
130
+ * @return [Array, Extralite::Iterator] next rows or self if block is given
131
+ */
132
+ VALUE Iterator_next(int argc, VALUE *argv, VALUE self) {
133
+ Iterator_t *iterator = value_to_iterator(self);
134
+ next_method method = mode_to_next_method(iterator->mode);
135
+ VALUE result = method(argc, argv, iterator->query);
136
+
137
+ return rb_block_given_p() ? self : result;
138
+ }
139
+
140
+ typedef VALUE (*to_a_method)(VALUE);
141
+
142
+ inline to_a_method mode_to_to_a_method(enum iterator_mode mode) {
143
+ switch (mode) {
144
+ case ITERATOR_ARY:
145
+ return Query_to_a_ary;
146
+ case ITERATOR_SINGLE_COLUMN:
147
+ return Query_to_a_single_column;
148
+ default:
149
+ return Query_to_a_hash;
150
+ }
151
+ }
152
+
153
+ /* Returns all rows from the associated query's result set according to the
154
+ * iteration mode, i.e. as a hash, an array or a single value.
155
+ *
156
+ * @return [Array] array of query result set rows
157
+ */
158
+ VALUE Iterator_to_a(VALUE self) {
159
+ Iterator_t *iterator = value_to_iterator(self);
160
+ to_a_method method = mode_to_to_a_method(iterator->mode);
161
+ return method(iterator->query);
162
+ }
163
+
164
+ void Init_ExtraliteIterator(void) {
165
+ VALUE mExtralite = rb_define_module("Extralite");
166
+
167
+ cIterator = rb_define_class_under(mExtralite, "Iterator", rb_cObject);
168
+ rb_define_alloc_func(cIterator, Iterator_allocate);
169
+
170
+ rb_include_module(cIterator, rb_mEnumerable);
171
+
172
+ rb_define_method(cIterator, "initialize", Iterator_initialize, 2);
173
+ rb_define_method(cIterator, "each", Iterator_each, 0);
174
+ rb_define_method(cIterator, "next", Iterator_next, -1);
175
+ rb_define_method(cIterator, "to_a", Iterator_to_a, 0);
176
+
177
+ SYM_hash = ID2SYM(rb_intern("hash"));
178
+ SYM_ary = ID2SYM(rb_intern("ary"));
179
+ SYM_single_column = ID2SYM(rb_intern("single_column"));
180
+ }