extralite 1.12 → 1.13

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,385 @@
1
+ #include <stdio.h>
2
+ #include "extralite.h"
3
+
4
+ VALUE cDatabase;
5
+ VALUE cError;
6
+ VALUE cSQLError;
7
+ VALUE cBusyError;
8
+
9
+ ID ID_KEYS;
10
+ ID ID_NEW;
11
+ ID ID_STRIP;
12
+ ID ID_TO_S;
13
+
14
+ static size_t Database_size(const void *ptr) {
15
+ return sizeof(Database_t);
16
+ }
17
+
18
+ static void Database_free(void *ptr) {
19
+ Database_t *db = ptr;
20
+ if (db->sqlite3_db) sqlite3_close(db->sqlite3_db);
21
+ free(ptr);
22
+ }
23
+
24
+ static const rb_data_type_t Database_type = {
25
+ "Database",
26
+ {0, Database_free, Database_size,},
27
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
28
+ };
29
+
30
+ static VALUE Database_allocate(VALUE klass) {
31
+ Database_t *db = ALLOC(Database_t);
32
+ db->sqlite3_db = 0;
33
+ return TypedData_Wrap_Struct(klass, &Database_type, db);
34
+ }
35
+
36
+ #define GetDatabase(obj, database) \
37
+ TypedData_Get_Struct((obj), Database_t, &Database_type, (database))
38
+
39
+ // make sure the database is open
40
+ #define GetOpenDatabase(obj, database) { \
41
+ TypedData_Get_Struct((obj), Database_t, &Database_type, (database)); \
42
+ if (!(database)->sqlite3_db) { \
43
+ rb_raise(cError, "Database is closed"); \
44
+ } \
45
+ }
46
+
47
+ sqlite3 *Database_sqlite3_db(VALUE self) {
48
+ Database_t *db;
49
+ GetDatabase(self, db);
50
+ return db->sqlite3_db;
51
+ }
52
+
53
+ /* call-seq:
54
+ * Extralite.sqlite3_version -> version
55
+ *
56
+ * Returns the sqlite3 version used by Extralite.
57
+ */
58
+
59
+ VALUE Extralite_sqlite3_version(VALUE self) {
60
+ return rb_str_new_cstr(sqlite3_version);
61
+ }
62
+
63
+ /* call-seq:
64
+ * db.initialize(path)
65
+ *
66
+ * Initializes a new SQLite database with the given path.
67
+ */
68
+
69
+ VALUE Database_initialize(VALUE self, VALUE path) {
70
+ int rc;
71
+ Database_t *db;
72
+ GetDatabase(self, db);
73
+
74
+ rc = sqlite3_open(StringValueCStr(path), &db->sqlite3_db);
75
+ if (rc) {
76
+ sqlite3_close(db->sqlite3_db);
77
+ rb_raise(cError, "%s", sqlite3_errmsg(db->sqlite3_db));
78
+ }
79
+
80
+ rc = sqlite3_enable_load_extension(db->sqlite3_db, 1);
81
+ if (rc) {
82
+ sqlite3_close(db->sqlite3_db);
83
+ rb_raise(cError, "%s", sqlite3_errmsg(db->sqlite3_db));
84
+ }
85
+
86
+ return Qnil;
87
+ }
88
+
89
+ /* call-seq:
90
+ * db.close -> db
91
+ *
92
+ * Closes the database.
93
+ */
94
+ VALUE Database_close(VALUE self) {
95
+ int rc;
96
+ Database_t *db;
97
+ GetDatabase(self, db);
98
+
99
+ rc = sqlite3_close(db->sqlite3_db);
100
+ if (rc) {
101
+ rb_raise(cError, "%s", sqlite3_errmsg(db->sqlite3_db));
102
+ }
103
+
104
+ db->sqlite3_db = 0;
105
+ return self;
106
+ }
107
+
108
+ /* call-seq:
109
+ * db.closed? -> bool
110
+ *
111
+ * Returns true if the database is closed.
112
+ *
113
+ * @return [bool] is database closed
114
+ */
115
+ VALUE Database_closed_p(VALUE self) {
116
+ Database_t *db;
117
+ GetDatabase(self, db);
118
+
119
+ return db->sqlite3_db ? Qfalse : Qtrue;
120
+ }
121
+
122
+ static inline VALUE Database_perform_query(int argc, VALUE *argv, VALUE self, VALUE (*call)(query_ctx *)) {
123
+ Database_t *db;
124
+ sqlite3_stmt *stmt;
125
+ VALUE sql;
126
+
127
+ // extract query from args
128
+ rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
129
+ sql = rb_funcall(argv[0], ID_STRIP, 0);
130
+ if (RSTRING_LEN(sql) == 0) return Qnil;
131
+
132
+ // prepare query ctx
133
+ GetOpenDatabase(self, db);
134
+ prepare_multi_stmt(db->sqlite3_db, &stmt, sql);
135
+ bind_all_parameters(stmt, argc - 1, argv + 1);
136
+ query_ctx ctx = { self, db->sqlite3_db, stmt };
137
+
138
+ return rb_ensure(SAFE(call), (VALUE)&ctx, SAFE(cleanup_stmt), (VALUE)&ctx);
139
+ }
140
+
141
+ /* call-seq:
142
+ * db.query(sql, *parameters, &block) -> [...]
143
+ * db.query_hash(sql, *parameters, &block) -> [...]
144
+ *
145
+ * Runs a query returning rows as hashes (with symbol keys). If a block is
146
+ * given, it will be called for each row. Otherwise, an array containing all
147
+ * rows is returned.
148
+ *
149
+ * Query parameters to be bound to placeholders in the query can be specified as
150
+ * a list of values or as a hash mapping parameter names to values. When
151
+ * parameters are given as a least, the query should specify parameters using
152
+ * `?`:
153
+ *
154
+ * db.query('select * from foo where x = ?', 42)
155
+ *
156
+ * Named placeholders are specified using `:`. The placeholder values are
157
+ * specified using a hash, where keys are either strings are symbols. String
158
+ * keys can include or omit the `:` prefix. The following are equivalent:
159
+ *
160
+ * db.query('select * from foo where x = :bar', bar: 42)
161
+ * db.query('select * from foo where x = :bar', 'bar' => 42)
162
+ * db.query('select * from foo where x = :bar', ':bar' => 42)
163
+ */
164
+ VALUE Database_query_hash(int argc, VALUE *argv, VALUE self) {
165
+ return Database_perform_query(argc, argv, self, safe_query_hash);
166
+ }
167
+
168
+ /* call-seq:
169
+ * db.query_ary(sql, *parameters, &block) -> [...]
170
+ *
171
+ * Runs a query returning rows as arrays. If a block is given, it will be called
172
+ * for each row. Otherwise, an array containing all rows is returned.
173
+ *
174
+ * Query parameters to be bound to placeholders in the query can be specified as
175
+ * a list of values or as a hash mapping parameter names to values. When
176
+ * parameters are given as a least, the query should specify parameters using
177
+ * `?`:
178
+ *
179
+ * db.query_ary('select * from foo where x = ?', 42)
180
+ *
181
+ * Named placeholders are specified using `:`. The placeholder values are
182
+ * specified using a hash, where keys are either strings are symbols. String
183
+ * keys can include or omit the `:` prefix. The following are equivalent:
184
+ *
185
+ * db.query_ary('select * from foo where x = :bar', bar: 42)
186
+ * db.query_ary('select * from foo where x = :bar', 'bar' => 42)
187
+ * db.query_ary('select * from foo where x = :bar', ':bar' => 42)
188
+ */
189
+ VALUE Database_query_ary(int argc, VALUE *argv, VALUE self) {
190
+ return Database_perform_query(argc, argv, self, safe_query_ary);
191
+ }
192
+
193
+ /* call-seq:
194
+ * db.query_single_row(sql, *parameters) -> {...}
195
+ *
196
+ * Runs a query returning a single row as a hash.
197
+ *
198
+ * Query parameters to be bound to placeholders in the query can be specified as
199
+ * a list of values or as a hash mapping parameter names to values. When
200
+ * parameters are given as a least, the query should specify parameters using
201
+ * `?`:
202
+ *
203
+ * db.query_single_row('select * from foo where x = ?', 42)
204
+ *
205
+ * Named placeholders are specified using `:`. The placeholder values are
206
+ * specified using a hash, where keys are either strings are symbols. String
207
+ * keys can include or omit the `:` prefix. The following are equivalent:
208
+ *
209
+ * db.query_single_row('select * from foo where x = :bar', bar: 42)
210
+ * db.query_single_row('select * from foo where x = :bar', 'bar' => 42)
211
+ * db.query_single_row('select * from foo where x = :bar', ':bar' => 42)
212
+ */
213
+ VALUE Database_query_single_row(int argc, VALUE *argv, VALUE self) {
214
+ return Database_perform_query(argc, argv, self, safe_query_single_row);
215
+ }
216
+
217
+ /* call-seq:
218
+ * db.query_single_column(sql, *parameters, &block) -> [...]
219
+ *
220
+ * Runs a query returning single column values. If a block is given, it will be called
221
+ * for each value. Otherwise, an array containing all values is returned.
222
+ *
223
+ * Query parameters to be bound to placeholders in the query can be specified as
224
+ * a list of values or as a hash mapping parameter names to values. When
225
+ * parameters are given as a least, the query should specify parameters using
226
+ * `?`:
227
+ *
228
+ * db.query_single_column('select x from foo where x = ?', 42)
229
+ *
230
+ * Named placeholders are specified using `:`. The placeholder values are
231
+ * specified using a hash, where keys are either strings are symbols. String
232
+ * keys can include or omit the `:` prefix. The following are equivalent:
233
+ *
234
+ * db.query_single_column('select x from foo where x = :bar', bar: 42)
235
+ * db.query_single_column('select x from foo where x = :bar', 'bar' => 42)
236
+ * db.query_single_column('select x from foo where x = :bar', ':bar' => 42)
237
+ */
238
+ VALUE Database_query_single_column(int argc, VALUE *argv, VALUE self) {
239
+ return Database_perform_query(argc, argv, self, safe_query_single_column);
240
+ }
241
+
242
+ /* call-seq:
243
+ * db.query_single_value(sql, *parameters) -> value
244
+ *
245
+ * Runs a query returning a single value from the first row.
246
+ *
247
+ * Query parameters to be bound to placeholders in the query can be specified as
248
+ * a list of values or as a hash mapping parameter names to values. When
249
+ * parameters are given as a least, the query should specify parameters using
250
+ * `?`:
251
+ *
252
+ * db.query_single_value('select x from foo where x = ?', 42)
253
+ *
254
+ * Named placeholders are specified using `:`. The placeholder values are
255
+ * specified using a hash, where keys are either strings are symbols. String
256
+ * keys can include or omit the `:` prefix. The following are equivalent:
257
+ *
258
+ * db.query_single_value('select x from foo where x = :bar', bar: 42)
259
+ * db.query_single_value('select x from foo where x = :bar', 'bar' => 42)
260
+ * db.query_single_value('select x from foo where x = :bar', ':bar' => 42)
261
+ */
262
+ VALUE Database_query_single_value(int argc, VALUE *argv, VALUE self) {
263
+ return Database_perform_query(argc, argv, self, safe_query_single_value);
264
+ }
265
+
266
+ /* call-seq:
267
+ * db.last_insert_rowid -> int
268
+ *
269
+ * Returns the rowid of the last inserted row.
270
+ */
271
+ VALUE Database_last_insert_rowid(VALUE self) {
272
+ Database_t *db;
273
+ GetOpenDatabase(self, db);
274
+
275
+ return INT2NUM(sqlite3_last_insert_rowid(db->sqlite3_db));
276
+ }
277
+
278
+ /* call-seq:
279
+ * db.changes -> int
280
+ *
281
+ * Returns the number of changes made to the database by the last operation.
282
+ */
283
+ VALUE Database_changes(VALUE self) {
284
+ Database_t *db;
285
+ GetOpenDatabase(self, db);
286
+
287
+ return INT2NUM(sqlite3_changes(db->sqlite3_db));
288
+ }
289
+
290
+ /* call-seq:
291
+ * db.filename -> string
292
+ *
293
+ * Returns the database filename.
294
+ */
295
+ VALUE Database_filename(int argc, VALUE *argv, VALUE self) {
296
+ const char *db_name;
297
+ const char *filename;
298
+ Database_t *db;
299
+ GetOpenDatabase(self, db);
300
+
301
+ rb_check_arity(argc, 0, 1);
302
+ db_name = (argc == 1) ? StringValueCStr(argv[0]) : "main";
303
+ filename = sqlite3_db_filename(db->sqlite3_db, db_name);
304
+ return filename ? rb_str_new_cstr(filename) : Qnil;
305
+ }
306
+
307
+ /* call-seq:
308
+ * db.transaction_active? -> bool
309
+ *
310
+ * Returns true if a transaction is currently in progress.
311
+ */
312
+ VALUE Database_transaction_active_p(VALUE self) {
313
+ Database_t *db;
314
+ GetOpenDatabase(self, db);
315
+
316
+ return sqlite3_get_autocommit(db->sqlite3_db) ? Qfalse : Qtrue;
317
+ }
318
+
319
+ /* call-seq:
320
+ * db.load_extension(path) -> db
321
+ *
322
+ * Loads an extension with the given path.
323
+ */
324
+ VALUE Database_load_extension(VALUE self, VALUE path) {
325
+ Database_t *db;
326
+ GetOpenDatabase(self, db);
327
+ char *err_msg;
328
+
329
+ int rc = sqlite3_load_extension(db->sqlite3_db, RSTRING_PTR(path), 0, &err_msg);
330
+ if (rc != SQLITE_OK) {
331
+ VALUE error = rb_exc_new2(cError, err_msg);
332
+ sqlite3_free(err_msg);
333
+ rb_exc_raise(error);
334
+ }
335
+
336
+ return self;
337
+ }
338
+
339
+ /* call-seq:
340
+ * db.prepare(sql) -> Extralite::PreparedStatement
341
+ *
342
+ * Creates a prepared statement with the given SQL query.
343
+ */
344
+ VALUE Database_prepare(VALUE self, VALUE sql) {
345
+ return rb_funcall(cPreparedStatement, ID_NEW, 2, self, sql);
346
+ }
347
+
348
+ void Init_ExtraliteDatabase() {
349
+ VALUE mExtralite = rb_define_module("Extralite");
350
+ rb_define_singleton_method(mExtralite, "sqlite3_version", Extralite_sqlite3_version, 0);
351
+
352
+ cDatabase = rb_define_class_under(mExtralite, "Database", rb_cObject);
353
+ rb_define_alloc_func(cDatabase, Database_allocate);
354
+
355
+ rb_define_method(cDatabase, "initialize", Database_initialize, 1);
356
+ rb_define_method(cDatabase, "close", Database_close, 0);
357
+ rb_define_method(cDatabase, "closed?", Database_closed_p, 0);
358
+
359
+ rb_define_method(cDatabase, "query", Database_query_hash, -1);
360
+ rb_define_method(cDatabase, "query_hash", Database_query_hash, -1);
361
+ rb_define_method(cDatabase, "query_ary", Database_query_ary, -1);
362
+ rb_define_method(cDatabase, "query_single_row", Database_query_single_row, -1);
363
+ rb_define_method(cDatabase, "query_single_column", Database_query_single_column, -1);
364
+ rb_define_method(cDatabase, "query_single_value", Database_query_single_value, -1);
365
+
366
+ rb_define_method(cDatabase, "last_insert_rowid", Database_last_insert_rowid, 0);
367
+ rb_define_method(cDatabase, "changes", Database_changes, 0);
368
+ rb_define_method(cDatabase, "filename", Database_filename, -1);
369
+ rb_define_method(cDatabase, "transaction_active?", Database_transaction_active_p, 0);
370
+ rb_define_method(cDatabase, "load_extension", Database_load_extension, 1);
371
+
372
+ rb_define_method(cDatabase, "prepare", Database_prepare, 1);
373
+
374
+ cError = rb_define_class_under(mExtralite, "Error", rb_eRuntimeError);
375
+ cSQLError = rb_define_class_under(mExtralite, "SQLError", cError);
376
+ cBusyError = rb_define_class_under(mExtralite, "BusyError", cError);
377
+ rb_gc_register_mark_object(cError);
378
+ rb_gc_register_mark_object(cSQLError);
379
+ rb_gc_register_mark_object(cBusyError);
380
+
381
+ ID_KEYS = rb_intern("keys");
382
+ ID_NEW = rb_intern("new");
383
+ ID_STRIP = rb_intern("strip");
384
+ ID_TO_S = rb_intern("to_s");
385
+ }
@@ -0,0 +1,59 @@
1
+ #ifndef EXTRALITE_H
2
+ #define EXTRALITE_H
3
+
4
+ #include "ruby.h"
5
+ #include "ruby/thread.h"
6
+ #include <sqlite3.h>
7
+
8
+ // debug utility
9
+ #define INSPECT(str, obj) { \
10
+ printf(str); \
11
+ VALUE s = rb_funcall(obj, rb_intern("inspect"), 0); \
12
+ printf(": %s\n", StringValueCStr(s)); \
13
+ }
14
+
15
+ #define SAFE(f) (VALUE (*)(VALUE))(f)
16
+
17
+ extern VALUE cDatabase;
18
+ extern VALUE cPreparedStatement;
19
+
20
+ extern VALUE cError;
21
+ extern VALUE cSQLError;
22
+ extern VALUE cBusyError;
23
+
24
+ extern ID ID_KEYS;
25
+ extern ID ID_NEW;
26
+ extern ID ID_STRIP;
27
+ extern ID ID_TO_S;
28
+
29
+ typedef struct {
30
+ sqlite3 *sqlite3_db;
31
+ } Database_t;
32
+
33
+ typedef struct {
34
+ VALUE db;
35
+ VALUE sql;
36
+ sqlite3 *sqlite3_db;
37
+ sqlite3_stmt *stmt;
38
+ } PreparedStatement_t;
39
+
40
+ typedef struct {
41
+ VALUE self;
42
+ sqlite3 *sqlite3_db;
43
+ sqlite3_stmt *stmt;
44
+ } query_ctx;
45
+
46
+ VALUE safe_query_ary(query_ctx *ctx);
47
+ VALUE safe_query_hash(query_ctx *ctx);
48
+ VALUE safe_query_single_column(query_ctx *ctx);
49
+ VALUE safe_query_single_row(query_ctx *ctx);
50
+ VALUE safe_query_single_value(query_ctx *ctx);
51
+
52
+ void prepare_single_stmt(sqlite3 *db, sqlite3_stmt **stmt, VALUE sql);
53
+ void prepare_multi_stmt(sqlite3 *db, sqlite3_stmt **stmt, VALUE sql);
54
+ void bind_all_parameters(sqlite3_stmt *stmt, int argc, VALUE *argv);
55
+ VALUE cleanup_stmt(query_ctx *ctx);
56
+
57
+ sqlite3 *Database_sqlite3_db(VALUE self);
58
+
59
+ #endif /* EXTRALITE_H */
@@ -1,5 +1,7 @@
1
- void Init_Extralite();
1
+ void Init_ExtraliteDatabase();
2
+ void Init_ExtralitePreparedStatement();
2
3
 
3
4
  void Init_extralite_ext() {
4
- Init_Extralite();
5
+ Init_ExtraliteDatabase();
6
+ Init_ExtralitePreparedStatement();
5
7
  }
@@ -0,0 +1,238 @@
1
+ #include <stdio.h>
2
+ #include "extralite.h"
3
+
4
+ VALUE cPreparedStatement;
5
+
6
+ static size_t PreparedStatement_size(const void *ptr) {
7
+ return sizeof(PreparedStatement_t);
8
+ }
9
+
10
+ static void PreparedStatement_mark(void *ptr) {
11
+ PreparedStatement_t *stmt = ptr;
12
+ rb_gc_mark(stmt->db);
13
+ rb_gc_mark(stmt->sql);
14
+ }
15
+
16
+ static void PreparedStatement_free(void *ptr) {
17
+ PreparedStatement_t *stmt = ptr;
18
+ if (stmt->stmt) sqlite3_finalize(stmt->stmt);
19
+ free(ptr);
20
+ }
21
+
22
+ static const rb_data_type_t PreparedStatement_type = {
23
+ "Database",
24
+ {PreparedStatement_mark, PreparedStatement_free, PreparedStatement_size,},
25
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
26
+ };
27
+
28
+ static VALUE PreparedStatement_allocate(VALUE klass) {
29
+ PreparedStatement_t *stmt = ALLOC(PreparedStatement_t);
30
+ stmt->db = Qnil;
31
+ stmt->sqlite3_db = NULL;
32
+ stmt->stmt = NULL;
33
+ return TypedData_Wrap_Struct(klass, &PreparedStatement_type, stmt);
34
+ }
35
+
36
+ #define GetPreparedStatement(obj, stmt) \
37
+ TypedData_Get_Struct((obj), PreparedStatement_t, &PreparedStatement_type, (stmt))
38
+
39
+ /* call-seq: initialize(db, sql)
40
+ *
41
+ * Initializes a new SQLite prepared statement with the given path.
42
+ */
43
+ VALUE PreparedStatement_initialize(VALUE self, VALUE db, VALUE sql) {
44
+ // int rc;
45
+ PreparedStatement_t *stmt;
46
+ GetPreparedStatement(self, stmt);
47
+
48
+ sql = rb_funcall(sql, ID_STRIP, 0);
49
+ if (!RSTRING_LEN(sql))
50
+ rb_raise(cError, "Cannot prepare an empty SQL query");
51
+
52
+ stmt->db = db;
53
+ stmt->sqlite3_db = Database_sqlite3_db(db);
54
+ stmt->sql = sql;
55
+
56
+ // TODO: setup stmt
57
+ prepare_single_stmt(stmt->sqlite3_db, &stmt->stmt, sql);
58
+
59
+ return Qnil;
60
+ }
61
+
62
+ static inline VALUE PreparedStatement_perform_query(int argc, VALUE *argv, VALUE self, VALUE (*call)(query_ctx *)) {
63
+ PreparedStatement_t *stmt;
64
+ GetPreparedStatement(self, stmt);
65
+
66
+ sqlite3_reset(stmt->stmt);
67
+ sqlite3_clear_bindings(stmt->stmt);
68
+ bind_all_parameters(stmt->stmt, argc, argv);
69
+ query_ctx ctx = { self, stmt->sqlite3_db, stmt->stmt };
70
+ return call(&ctx);
71
+ }
72
+
73
+ /* call-seq:
74
+ * query(sql, *parameters, &block) -> [...]
75
+ * query_hash(sql, *parameters, &block) -> [...]
76
+ *
77
+ * Runs a query returning rows as hashes (with symbol keys). If a block is
78
+ * given, it will be called for each row. Otherwise, an array containing all
79
+ * rows is returned.
80
+ *
81
+ * Query parameters to be bound to placeholders in the query can be specified as
82
+ * a list of values or as a hash mapping parameter names to values. When
83
+ * parameters are given as a least, the query should specify parameters using
84
+ * `?`:
85
+ *
86
+ * db.query('select * from foo where x = ?', 42)
87
+ *
88
+ * Named placeholders are specified using `:`. The placeholder values are
89
+ * specified using a hash, where keys are either strings are symbols. String
90
+ * keys can include or omit the `:` prefix. The following are equivalent:
91
+ *
92
+ * db.query('select * from foo where x = :bar', bar: 42)
93
+ * db.query('select * from foo where x = :bar', 'bar' => 42)
94
+ * db.query('select * from foo where x = :bar', ':bar' => 42)
95
+ */
96
+ VALUE PreparedStatement_query_hash(int argc, VALUE *argv, VALUE self) {
97
+ return PreparedStatement_perform_query(argc, argv, self, safe_query_hash);
98
+ }
99
+
100
+ /* call-seq:
101
+ * stmt.query_ary(sql, *parameters, &block) -> [...]
102
+ *
103
+ * Runs a query returning rows as arrays. If a block is given, it will be called
104
+ * for each row. Otherwise, an array containing all rows is returned.
105
+ *
106
+ * Query parameters to be bound to placeholders in the query can be specified as
107
+ * a list of values or as a hash mapping parameter names to values. When
108
+ * parameters are given as a least, the query should specify parameters using
109
+ * `?`:
110
+ *
111
+ * db.query_ary('select * from foo where x = ?', 42)
112
+ *
113
+ * Named placeholders are specified using `:`. The placeholder values are
114
+ * specified using a hash, where keys are either strings are symbols. String
115
+ * keys can include or omit the `:` prefix. The following are equivalent:
116
+ *
117
+ * db.query_ary('select * from foo where x = :bar', bar: 42)
118
+ * db.query_ary('select * from foo where x = :bar', 'bar' => 42)
119
+ * db.query_ary('select * from foo where x = :bar', ':bar' => 42)
120
+ */
121
+ VALUE PreparedStatement_query_ary(int argc, VALUE *argv, VALUE self) {
122
+ return PreparedStatement_perform_query(argc, argv, self, safe_query_ary);
123
+ }
124
+
125
+ /* call-seq:
126
+ * stmt.query_single_row(sql, *parameters) -> {...}
127
+ *
128
+ * Runs a query returning a single row as a hash.
129
+ *
130
+ * Query parameters to be bound to placeholders in the query can be specified as
131
+ * a list of values or as a hash mapping parameter names to values. When
132
+ * parameters are given as a least, the query should specify parameters using
133
+ * `?`:
134
+ *
135
+ * db.query_single_row('select * from foo where x = ?', 42)
136
+ *
137
+ * Named placeholders are specified using `:`. The placeholder values are
138
+ * specified using a hash, where keys are either strings are symbols. String
139
+ * keys can include or omit the `:` prefix. The following are equivalent:
140
+ *
141
+ * db.query_single_row('select * from foo where x = :bar', bar: 42)
142
+ * db.query_single_row('select * from foo where x = :bar', 'bar' => 42)
143
+ * db.query_single_row('select * from foo where x = :bar', ':bar' => 42)
144
+ */
145
+ VALUE PreparedStatement_query_single_row(int argc, VALUE *argv, VALUE self) {
146
+ return PreparedStatement_perform_query(argc, argv, self, safe_query_single_row);
147
+ }
148
+
149
+ /* call-seq:
150
+ * stmt.query_single_column(sql, *parameters, &block) -> [...]
151
+ *
152
+ * Runs a query returning single column values. If a block is given, it will be called
153
+ * for each value. Otherwise, an array containing all values is returned.
154
+ *
155
+ * Query parameters to be bound to placeholders in the query can be specified as
156
+ * a list of values or as a hash mapping parameter names to values. When
157
+ * parameters are given as a least, the query should specify parameters using
158
+ * `?`:
159
+ *
160
+ * db.query_single_column('select x from foo where x = ?', 42)
161
+ *
162
+ * Named placeholders are specified using `:`. The placeholder values are
163
+ * specified using a hash, where keys are either strings are symbols. String
164
+ * keys can include or omit the `:` prefix. The following are equivalent:
165
+ *
166
+ * db.query_single_column('select x from foo where x = :bar', bar: 42)
167
+ * db.query_single_column('select x from foo where x = :bar', 'bar' => 42)
168
+ * db.query_single_column('select x from foo where x = :bar', ':bar' => 42)
169
+ */
170
+ VALUE PreparedStatement_query_single_column(int argc, VALUE *argv, VALUE self) {
171
+ return PreparedStatement_perform_query(argc, argv, self, safe_query_single_column);
172
+ }
173
+
174
+ /* call-seq:
175
+ * stmt.query_single_value(sql, *parameters) -> value
176
+ *
177
+ * Runs a query returning a single value from the first row.
178
+ *
179
+ * Query parameters to be bound to placeholders in the query can be specified as
180
+ * a list of values or as a hash mapping parameter names to values. When
181
+ * parameters are given as a least, the query should specify parameters using
182
+ * `?`:
183
+ *
184
+ * db.query_single_value('select x from foo where x = ?', 42)
185
+ *
186
+ * Named placeholders are specified using `:`. The placeholder values are
187
+ * specified using a hash, where keys are either strings are symbols. String
188
+ * keys can include or omit the `:` prefix. The following are equivalent:
189
+ *
190
+ * db.query_single_value('select x from foo where x = :bar', bar: 42)
191
+ * db.query_single_value('select x from foo where x = :bar', 'bar' => 42)
192
+ * db.query_single_value('select x from foo where x = :bar', ':bar' => 42)
193
+ */
194
+ VALUE PreparedStatement_query_single_value(int argc, VALUE *argv, VALUE self) {
195
+ return PreparedStatement_perform_query(argc, argv, self, safe_query_single_value);
196
+ }
197
+
198
+ /* call-seq:
199
+ * stmt.database -> database
200
+ * stmt.db -> database
201
+ *
202
+ * Returns the database associated with the prepared statement.
203
+ */
204
+ VALUE PreparedStatement_database(VALUE self) {
205
+ PreparedStatement_t *stmt;
206
+ GetPreparedStatement(self, stmt);
207
+ return stmt->db;
208
+ }
209
+
210
+ /* call-seq:
211
+ * stmt.sql -> sql
212
+ *
213
+ * Returns the SQL query used for the prepared statement.
214
+ */
215
+ VALUE PreparedStatement_sql(VALUE self) {
216
+ PreparedStatement_t *stmt;
217
+ GetPreparedStatement(self, stmt);
218
+ return stmt->sql;
219
+ }
220
+
221
+ void Init_ExtralitePreparedStatement() {
222
+ VALUE mExtralite = rb_define_module("Extralite");
223
+
224
+ cPreparedStatement = rb_define_class_under(mExtralite, "PreparedStatement", rb_cObject);
225
+ rb_define_alloc_func(cPreparedStatement, PreparedStatement_allocate);
226
+
227
+ rb_define_method(cPreparedStatement, "initialize", PreparedStatement_initialize, 2);
228
+ rb_define_method(cPreparedStatement, "database", PreparedStatement_database, 0);
229
+ rb_define_method(cPreparedStatement, "db", PreparedStatement_database, 0);
230
+ rb_define_method(cPreparedStatement, "sql", PreparedStatement_sql, 0);
231
+
232
+ rb_define_method(cPreparedStatement, "query", PreparedStatement_query_hash, -1);
233
+ rb_define_method(cPreparedStatement, "query_hash", PreparedStatement_query_hash, -1);
234
+ rb_define_method(cPreparedStatement, "query_ary", PreparedStatement_query_ary, -1);
235
+ rb_define_method(cPreparedStatement, "query_single_row", PreparedStatement_query_single_row, -1);
236
+ rb_define_method(cPreparedStatement, "query_single_column", PreparedStatement_query_single_column, -1);
237
+ rb_define_method(cPreparedStatement, "query_single_value", PreparedStatement_query_single_value, -1);
238
+ }