sqlite3 1.7.3-aarch64-linux → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +363 -1
- data/CONTRIBUTING.md +33 -7
- data/FAQ.md +52 -84
- data/INSTALLATION.md +21 -13
- data/LICENSE +18 -22
- data/README.md +97 -9
- data/dependencies.yml +10 -11
- data/ext/sqlite3/aggregator.c +143 -146
- data/ext/sqlite3/aggregator.h +2 -4
- data/ext/sqlite3/backup.c +74 -65
- data/ext/sqlite3/backup.h +2 -2
- data/ext/sqlite3/database.c +623 -495
- data/ext/sqlite3/database.h +13 -4
- data/ext/sqlite3/exception.c +116 -92
- data/ext/sqlite3/exception.h +5 -1
- data/ext/sqlite3/extconf.rb +36 -24
- data/ext/sqlite3/sqlite3.c +176 -115
- data/ext/sqlite3/sqlite3_ruby.h +2 -2
- data/ext/sqlite3/statement.c +588 -300
- data/ext/sqlite3/statement.h +4 -3
- data/ext/sqlite3/timespec.h +20 -0
- data/lib/sqlite3/constants.rb +195 -47
- data/lib/sqlite3/database.rb +224 -187
- data/lib/sqlite3/errors.rb +54 -1
- data/lib/sqlite3/fork_safety.rb +66 -0
- data/lib/sqlite3/pragmas.rb +194 -141
- data/lib/sqlite3/resultset.rb +14 -97
- data/lib/sqlite3/statement.rb +58 -13
- data/lib/sqlite3/value.rb +17 -20
- data/lib/sqlite3/version.rb +2 -21
- data/lib/sqlite3/version_info.rb +17 -0
- data/lib/sqlite3.rb +8 -4
- data/ports/archives/sqlite-autoconf-3510100.tar.gz +0 -0
- metadata +28 -45
- data/API_CHANGES.md +0 -49
- data/ChangeLog.cvs +0 -88
- data/Gemfile +0 -10
- data/LICENSE-DEPENDENCIES +0 -20
- data/lib/sqlite3/3.0/sqlite3_native.so +0 -0
- data/lib/sqlite3/3.1/sqlite3_native.so +0 -0
- data/lib/sqlite3/3.2/sqlite3_native.so +0 -0
- data/lib/sqlite3/3.3/sqlite3_native.so +0 -0
- data/lib/sqlite3/translator.rb +0 -117
- data/test/helper.rb +0 -27
- data/test/test_backup.rb +0 -33
- data/test/test_collation.rb +0 -82
- data/test/test_database.rb +0 -668
- data/test/test_database_flags.rb +0 -95
- data/test/test_database_readonly.rb +0 -36
- data/test/test_database_readwrite.rb +0 -41
- data/test/test_deprecated.rb +0 -49
- data/test/test_encoding.rb +0 -165
- data/test/test_integration.rb +0 -507
- data/test/test_integration_aggregate.rb +0 -336
- data/test/test_integration_open_close.rb +0 -30
- data/test/test_integration_pending.rb +0 -115
- data/test/test_integration_resultset.rb +0 -142
- data/test/test_integration_statement.rb +0 -194
- data/test/test_pragmas.rb +0 -22
- data/test/test_result_set.rb +0 -47
- data/test/test_sqlite3.rb +0 -30
- data/test/test_statement.rb +0 -290
- data/test/test_statement_execute.rb +0 -39
data/ext/sqlite3/statement.c
CHANGED
|
@@ -1,81 +1,87 @@
|
|
|
1
1
|
#include <sqlite3_ruby.h>
|
|
2
2
|
|
|
3
3
|
#define REQUIRE_OPEN_STMT(_ctxt) \
|
|
4
|
-
if(!_ctxt->st) \
|
|
4
|
+
if (!_ctxt->st) \
|
|
5
5
|
rb_raise(rb_path2class("SQLite3::Exception"), "cannot use a closed statement");
|
|
6
6
|
|
|
7
|
+
#define REQUIRE_LIVE_DB(_ctxt) \
|
|
8
|
+
if (_ctxt->db->flags & SQLITE3_RB_DATABASE_DISCARDED) \
|
|
9
|
+
rb_raise(rb_path2class("SQLite3::Exception"), "cannot use a statement associated with a discarded database");
|
|
10
|
+
|
|
7
11
|
VALUE cSqlite3Statement;
|
|
8
12
|
|
|
9
|
-
static
|
|
13
|
+
static void
|
|
14
|
+
statement_deallocate(void *data)
|
|
15
|
+
{
|
|
16
|
+
sqlite3StmtRubyPtr s = (sqlite3StmtRubyPtr)data;
|
|
17
|
+
|
|
18
|
+
if (s->st) {
|
|
19
|
+
sqlite3_finalize(s->st);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
xfree(data);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static size_t
|
|
26
|
+
statement_memsize(const void *data)
|
|
10
27
|
{
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
28
|
+
const sqlite3StmtRubyPtr s = (const sqlite3StmtRubyPtr)data;
|
|
29
|
+
// NB: can't account for s->st because the type is incomplete.
|
|
30
|
+
return sizeof(*s);
|
|
14
31
|
}
|
|
15
32
|
|
|
16
33
|
static const rb_data_type_t statement_type = {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
34
|
+
"SQLite3::Backup",
|
|
35
|
+
{
|
|
36
|
+
NULL,
|
|
37
|
+
statement_deallocate,
|
|
38
|
+
statement_memsize,
|
|
39
|
+
},
|
|
40
|
+
0,
|
|
41
|
+
0,
|
|
42
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
|
|
26
43
|
};
|
|
27
44
|
|
|
28
|
-
static VALUE
|
|
45
|
+
static VALUE
|
|
46
|
+
allocate(VALUE klass)
|
|
29
47
|
{
|
|
30
|
-
|
|
31
|
-
|
|
48
|
+
sqlite3StmtRubyPtr ctx;
|
|
49
|
+
return TypedData_Make_Struct(klass, sqlite3StmtRuby, &statement_type, ctx);
|
|
32
50
|
}
|
|
33
51
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
* Create a new statement attached to the given Database instance, and which
|
|
37
|
-
* encapsulates the given SQL text. If the text contains more than one
|
|
38
|
-
* statement (i.e., separated by semicolons), then the #remainder property
|
|
39
|
-
* will be set to the trailing text.
|
|
40
|
-
*/
|
|
41
|
-
static VALUE initialize(VALUE self, VALUE db, VALUE sql)
|
|
52
|
+
static VALUE
|
|
53
|
+
prepare(VALUE self, VALUE db, VALUE sql)
|
|
42
54
|
{
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
StringValue(sql);
|
|
55
|
+
sqlite3RubyPtr db_ctx = sqlite3_database_unwrap(db);
|
|
56
|
+
sqlite3StmtRubyPtr ctx;
|
|
57
|
+
const char *tail = NULL;
|
|
58
|
+
int status;
|
|
49
59
|
|
|
50
|
-
|
|
60
|
+
StringValue(sql);
|
|
51
61
|
|
|
52
|
-
|
|
53
|
-
rb_raise(rb_eArgError, "prepare called on a closed database");
|
|
62
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
|
54
63
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
64
|
+
/* Dereferencing a pointer to the database struct will be faster than accessing it through the
|
|
65
|
+
* instance variable @connection. The struct pointer is guaranteed to be live because instance
|
|
66
|
+
* variable will keep it from being GCed. */
|
|
67
|
+
ctx->db = db_ctx;
|
|
58
68
|
|
|
59
69
|
#ifdef HAVE_SQLITE3_PREPARE_V2
|
|
60
|
-
|
|
70
|
+
status = sqlite3_prepare_v2(
|
|
61
71
|
#else
|
|
62
|
-
|
|
72
|
+
status = sqlite3_prepare(
|
|
63
73
|
#endif
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
74
|
+
db_ctx->db,
|
|
75
|
+
(const char *)StringValuePtr(sql),
|
|
76
|
+
(int)RSTRING_LEN(sql),
|
|
77
|
+
&ctx->st,
|
|
78
|
+
&tail
|
|
79
|
+
);
|
|
70
80
|
|
|
71
|
-
|
|
81
|
+
CHECK_PREPARE(db_ctx->db, status, StringValuePtr(sql));
|
|
82
|
+
timespecclear(&db_ctx->stmt_deadline);
|
|
72
83
|
|
|
73
|
-
|
|
74
|
-
rb_iv_set(self, "@remainder", rb_str_new2(tail));
|
|
75
|
-
rb_iv_set(self, "@columns", Qnil);
|
|
76
|
-
rb_iv_set(self, "@types", Qnil);
|
|
77
|
-
|
|
78
|
-
return self;
|
|
84
|
+
return rb_utf8_str_new_cstr(tail);
|
|
79
85
|
}
|
|
80
86
|
|
|
81
87
|
/* call-seq: stmt.close
|
|
@@ -83,122 +89,125 @@ static VALUE initialize(VALUE self, VALUE db, VALUE sql)
|
|
|
83
89
|
* Closes the statement by finalizing the underlying statement
|
|
84
90
|
* handle. The statement must not be used after being closed.
|
|
85
91
|
*/
|
|
86
|
-
static VALUE
|
|
92
|
+
static VALUE
|
|
93
|
+
sqlite3_rb_close(VALUE self)
|
|
87
94
|
{
|
|
88
|
-
|
|
95
|
+
sqlite3StmtRubyPtr ctx;
|
|
89
96
|
|
|
90
|
-
|
|
97
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
|
91
98
|
|
|
92
|
-
|
|
99
|
+
REQUIRE_OPEN_STMT(ctx);
|
|
93
100
|
|
|
94
|
-
|
|
95
|
-
|
|
101
|
+
sqlite3_finalize(ctx->st);
|
|
102
|
+
ctx->st = NULL;
|
|
96
103
|
|
|
97
|
-
|
|
104
|
+
return self;
|
|
98
105
|
}
|
|
99
106
|
|
|
100
107
|
/* call-seq: stmt.closed?
|
|
101
108
|
*
|
|
102
109
|
* Returns true if the statement has been closed.
|
|
103
110
|
*/
|
|
104
|
-
static VALUE
|
|
111
|
+
static VALUE
|
|
112
|
+
closed_p(VALUE self)
|
|
105
113
|
{
|
|
106
|
-
|
|
107
|
-
|
|
114
|
+
sqlite3StmtRubyPtr ctx;
|
|
115
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
|
108
116
|
|
|
109
|
-
|
|
117
|
+
if (!ctx->st) { return Qtrue; }
|
|
110
118
|
|
|
111
|
-
|
|
119
|
+
return Qfalse;
|
|
112
120
|
}
|
|
113
121
|
|
|
114
|
-
static VALUE
|
|
122
|
+
static VALUE
|
|
123
|
+
step(VALUE self)
|
|
115
124
|
{
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
}
|
|
125
|
+
sqlite3StmtRubyPtr ctx;
|
|
126
|
+
sqlite3_stmt *stmt;
|
|
127
|
+
int value, length;
|
|
128
|
+
VALUE list;
|
|
129
|
+
rb_encoding *internal_encoding;
|
|
130
|
+
|
|
131
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
|
132
|
+
|
|
133
|
+
REQUIRE_LIVE_DB(ctx);
|
|
134
|
+
REQUIRE_OPEN_STMT(ctx);
|
|
135
|
+
|
|
136
|
+
if (ctx->done_p) { return Qnil; }
|
|
137
|
+
|
|
138
|
+
internal_encoding = rb_default_internal_encoding();
|
|
139
|
+
|
|
140
|
+
stmt = ctx->st;
|
|
141
|
+
|
|
142
|
+
value = sqlite3_step(stmt);
|
|
143
|
+
if (rb_errinfo() != Qnil) {
|
|
144
|
+
/* some user defined function was invoked as a callback during step and
|
|
145
|
+
* it raised an exception that has been suppressed until step returns.
|
|
146
|
+
* Now re-raise it. */
|
|
147
|
+
VALUE exception = rb_errinfo();
|
|
148
|
+
rb_set_errinfo(Qnil);
|
|
149
|
+
rb_exc_raise(exception);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
length = sqlite3_column_count(stmt);
|
|
153
|
+
list = rb_ary_new2((long)length);
|
|
154
|
+
|
|
155
|
+
switch (value) {
|
|
156
|
+
case SQLITE_ROW: {
|
|
157
|
+
int i;
|
|
158
|
+
for (i = 0; i < length; i++) {
|
|
159
|
+
VALUE val;
|
|
160
|
+
|
|
161
|
+
switch (sqlite3_column_type(stmt, i)) {
|
|
162
|
+
case SQLITE_INTEGER:
|
|
163
|
+
val = LL2NUM(sqlite3_column_int64(stmt, i));
|
|
164
|
+
break;
|
|
165
|
+
case SQLITE_FLOAT:
|
|
166
|
+
val = rb_float_new(sqlite3_column_double(stmt, i));
|
|
167
|
+
break;
|
|
168
|
+
case SQLITE_TEXT: {
|
|
169
|
+
val = rb_utf8_str_new(
|
|
170
|
+
(const char *)sqlite3_column_text(stmt, i),
|
|
171
|
+
(long)sqlite3_column_bytes(stmt, i)
|
|
172
|
+
);
|
|
173
|
+
if (internal_encoding) {
|
|
174
|
+
val = rb_str_export_to_enc(val, internal_encoding);
|
|
175
|
+
}
|
|
176
|
+
rb_obj_freeze(val);
|
|
177
|
+
}
|
|
178
|
+
break;
|
|
179
|
+
case SQLITE_BLOB: {
|
|
180
|
+
val = rb_str_new(
|
|
181
|
+
(const char *)sqlite3_column_blob(stmt, i),
|
|
182
|
+
(long)sqlite3_column_bytes(stmt, i)
|
|
183
|
+
);
|
|
184
|
+
rb_obj_freeze(val);
|
|
185
|
+
}
|
|
186
|
+
break;
|
|
187
|
+
case SQLITE_NULL:
|
|
188
|
+
val = Qnil;
|
|
189
|
+
break;
|
|
190
|
+
default:
|
|
191
|
+
rb_raise(rb_eRuntimeError, "bad type");
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
rb_ary_store(list, (long)i, val);
|
|
195
|
+
}
|
|
188
196
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
197
|
+
break;
|
|
198
|
+
case SQLITE_DONE:
|
|
199
|
+
ctx->done_p = 1;
|
|
200
|
+
return Qnil;
|
|
201
|
+
break;
|
|
202
|
+
default:
|
|
203
|
+
sqlite3_reset(stmt);
|
|
204
|
+
ctx->done_p = 0;
|
|
205
|
+
CHECK(sqlite3_db_handle(ctx->st), value);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
rb_obj_freeze(list);
|
|
209
|
+
|
|
210
|
+
return list;
|
|
202
211
|
}
|
|
203
212
|
|
|
204
213
|
/* call-seq: stmt.bind_param(key, value)
|
|
@@ -209,91 +218,95 @@ static VALUE step(VALUE self)
|
|
|
209
218
|
*
|
|
210
219
|
* See also #bind_params.
|
|
211
220
|
*/
|
|
212
|
-
static VALUE
|
|
221
|
+
static VALUE
|
|
222
|
+
bind_param(VALUE self, VALUE key, VALUE value)
|
|
213
223
|
{
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
224
|
+
sqlite3StmtRubyPtr ctx;
|
|
225
|
+
int status;
|
|
226
|
+
int index;
|
|
227
|
+
|
|
228
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
|
229
|
+
|
|
230
|
+
REQUIRE_LIVE_DB(ctx);
|
|
231
|
+
REQUIRE_OPEN_STMT(ctx);
|
|
232
|
+
|
|
233
|
+
switch (TYPE(key)) {
|
|
234
|
+
case T_SYMBOL:
|
|
235
|
+
key = rb_funcall(key, rb_intern("to_s"), 0);
|
|
236
|
+
case T_STRING:
|
|
237
|
+
if (RSTRING_PTR(key)[0] != ':') { key = rb_str_plus(rb_str_new2(":"), key); }
|
|
238
|
+
index = sqlite3_bind_parameter_index(ctx->st, StringValuePtr(key));
|
|
239
|
+
break;
|
|
240
|
+
default:
|
|
241
|
+
index = (int)NUM2INT(key);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (index == 0) {
|
|
245
|
+
rb_raise(rb_path2class("SQLite3::Exception"), "no such bind parameter");
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
switch (TYPE(value)) {
|
|
249
|
+
case T_STRING:
|
|
250
|
+
if (CLASS_OF(value) == cSqlite3Blob
|
|
251
|
+
|| rb_enc_get_index(value) == rb_ascii8bit_encindex()
|
|
252
|
+
) {
|
|
253
|
+
status = sqlite3_bind_blob(
|
|
254
|
+
ctx->st,
|
|
255
|
+
index,
|
|
256
|
+
(const char *)StringValuePtr(value),
|
|
257
|
+
(int)RSTRING_LEN(value),
|
|
258
|
+
SQLITE_TRANSIENT
|
|
259
|
+
);
|
|
260
|
+
} else {
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
if (UTF16_LE_P(value) || UTF16_BE_P(value)) {
|
|
264
|
+
status = sqlite3_bind_text16(
|
|
265
|
+
ctx->st,
|
|
266
|
+
index,
|
|
267
|
+
(const char *)StringValuePtr(value),
|
|
268
|
+
(int)RSTRING_LEN(value),
|
|
269
|
+
SQLITE_TRANSIENT
|
|
270
|
+
);
|
|
271
|
+
} else {
|
|
272
|
+
if (!UTF8_P(value) || !USASCII_P(value)) {
|
|
273
|
+
value = rb_str_encode(value, rb_enc_from_encoding(rb_utf8_encoding()), 0, Qnil);
|
|
274
|
+
}
|
|
275
|
+
status = sqlite3_bind_text(
|
|
276
|
+
ctx->st,
|
|
277
|
+
index,
|
|
278
|
+
(const char *)StringValuePtr(value),
|
|
279
|
+
(int)RSTRING_LEN(value),
|
|
280
|
+
SQLITE_TRANSIENT
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
break;
|
|
285
|
+
case T_BIGNUM: {
|
|
286
|
+
sqlite3_int64 num64;
|
|
287
|
+
if (bignum_to_int64(value, &num64)) {
|
|
288
|
+
status = sqlite3_bind_int64(ctx->st, index, num64);
|
|
289
|
+
break;
|
|
290
|
+
}
|
|
269
291
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
292
|
+
case T_FLOAT:
|
|
293
|
+
status = sqlite3_bind_double(ctx->st, index, NUM2DBL(value));
|
|
294
|
+
break;
|
|
295
|
+
case T_FIXNUM:
|
|
296
|
+
status = sqlite3_bind_int64(ctx->st, index, (sqlite3_int64)FIX2LONG(value));
|
|
297
|
+
break;
|
|
298
|
+
case T_NIL:
|
|
299
|
+
status = sqlite3_bind_null(ctx->st, index);
|
|
300
|
+
break;
|
|
301
|
+
default:
|
|
302
|
+
rb_raise(rb_eRuntimeError, "can't prepare %s",
|
|
303
|
+
rb_class2name(CLASS_OF(value)));
|
|
304
|
+
break;
|
|
278
305
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
status = sqlite3_bind_int64(ctx->st, index, (sqlite3_int64)FIX2LONG(value));
|
|
284
|
-
break;
|
|
285
|
-
case T_NIL:
|
|
286
|
-
status = sqlite3_bind_null(ctx->st, index);
|
|
287
|
-
break;
|
|
288
|
-
default:
|
|
289
|
-
rb_raise(rb_eRuntimeError, "can't prepare %s",
|
|
290
|
-
rb_class2name(CLASS_OF(value)));
|
|
291
|
-
break;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
CHECK(sqlite3_db_handle(ctx->st), status);
|
|
295
|
-
|
|
296
|
-
return self;
|
|
306
|
+
|
|
307
|
+
CHECK(sqlite3_db_handle(ctx->st), status);
|
|
308
|
+
|
|
309
|
+
return self;
|
|
297
310
|
}
|
|
298
311
|
|
|
299
312
|
/* call-seq: stmt.reset!
|
|
@@ -301,18 +314,21 @@ static VALUE bind_param(VALUE self, VALUE key, VALUE value)
|
|
|
301
314
|
* Resets the statement. This is typically done internally, though it might
|
|
302
315
|
* occasionally be necessary to manually reset the statement.
|
|
303
316
|
*/
|
|
304
|
-
static VALUE
|
|
317
|
+
static VALUE
|
|
318
|
+
reset_bang(VALUE self)
|
|
305
319
|
{
|
|
306
|
-
|
|
320
|
+
sqlite3StmtRubyPtr ctx;
|
|
307
321
|
|
|
308
|
-
|
|
309
|
-
REQUIRE_OPEN_STMT(ctx);
|
|
322
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
|
310
323
|
|
|
311
|
-
|
|
324
|
+
REQUIRE_LIVE_DB(ctx);
|
|
325
|
+
REQUIRE_OPEN_STMT(ctx);
|
|
312
326
|
|
|
313
|
-
|
|
327
|
+
sqlite3_reset(ctx->st);
|
|
314
328
|
|
|
315
|
-
|
|
329
|
+
ctx->done_p = 0;
|
|
330
|
+
|
|
331
|
+
return self;
|
|
316
332
|
}
|
|
317
333
|
|
|
318
334
|
/* call-seq: stmt.clear_bindings!
|
|
@@ -320,132 +336,404 @@ static VALUE reset_bang(VALUE self)
|
|
|
320
336
|
* Resets the statement. This is typically done internally, though it might
|
|
321
337
|
* occasionally be necessary to manually reset the statement.
|
|
322
338
|
*/
|
|
323
|
-
static VALUE
|
|
339
|
+
static VALUE
|
|
340
|
+
clear_bindings_bang(VALUE self)
|
|
324
341
|
{
|
|
325
|
-
|
|
342
|
+
sqlite3StmtRubyPtr ctx;
|
|
343
|
+
|
|
344
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
|
326
345
|
|
|
327
|
-
|
|
328
|
-
|
|
346
|
+
REQUIRE_LIVE_DB(ctx);
|
|
347
|
+
REQUIRE_OPEN_STMT(ctx);
|
|
329
348
|
|
|
330
|
-
|
|
349
|
+
sqlite3_clear_bindings(ctx->st);
|
|
331
350
|
|
|
332
|
-
|
|
351
|
+
ctx->done_p = 0;
|
|
333
352
|
|
|
334
|
-
|
|
353
|
+
return self;
|
|
335
354
|
}
|
|
336
355
|
|
|
337
356
|
/* call-seq: stmt.done?
|
|
338
357
|
*
|
|
339
358
|
* returns true if all rows have been returned.
|
|
340
359
|
*/
|
|
341
|
-
static VALUE
|
|
360
|
+
static VALUE
|
|
361
|
+
done_p(VALUE self)
|
|
342
362
|
{
|
|
343
|
-
|
|
344
|
-
|
|
363
|
+
sqlite3StmtRubyPtr ctx;
|
|
364
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
|
345
365
|
|
|
346
|
-
|
|
347
|
-
|
|
366
|
+
if (ctx->done_p) { return Qtrue; }
|
|
367
|
+
return Qfalse;
|
|
348
368
|
}
|
|
349
369
|
|
|
350
370
|
/* call-seq: stmt.column_count
|
|
351
371
|
*
|
|
352
372
|
* Returns the number of columns to be returned for this statement
|
|
353
373
|
*/
|
|
354
|
-
static VALUE
|
|
374
|
+
static VALUE
|
|
375
|
+
column_count(VALUE self)
|
|
355
376
|
{
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
377
|
+
sqlite3StmtRubyPtr ctx;
|
|
378
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
|
379
|
+
|
|
380
|
+
REQUIRE_LIVE_DB(ctx);
|
|
381
|
+
REQUIRE_OPEN_STMT(ctx);
|
|
359
382
|
|
|
360
|
-
|
|
383
|
+
return INT2NUM(sqlite3_column_count(ctx->st));
|
|
361
384
|
}
|
|
362
385
|
|
|
386
|
+
#if HAVE_RB_ENC_INTERNED_STR_CSTR
|
|
387
|
+
static VALUE
|
|
388
|
+
interned_utf8_cstr(const char *str)
|
|
389
|
+
{
|
|
390
|
+
return rb_enc_interned_str_cstr(str, rb_utf8_encoding());
|
|
391
|
+
}
|
|
392
|
+
#else
|
|
393
|
+
static VALUE
|
|
394
|
+
interned_utf8_cstr(const char *str)
|
|
395
|
+
{
|
|
396
|
+
VALUE rb_str = rb_utf8_str_new_cstr(str);
|
|
397
|
+
return rb_funcall(rb_str, rb_intern("-@"), 0);
|
|
398
|
+
}
|
|
399
|
+
#endif
|
|
400
|
+
|
|
363
401
|
/* call-seq: stmt.column_name(index)
|
|
364
402
|
*
|
|
365
403
|
* Get the column name at +index+. 0 based.
|
|
366
404
|
*/
|
|
367
|
-
static VALUE
|
|
405
|
+
static VALUE
|
|
406
|
+
column_name(VALUE self, VALUE index)
|
|
368
407
|
{
|
|
369
|
-
|
|
370
|
-
|
|
408
|
+
sqlite3StmtRubyPtr ctx;
|
|
409
|
+
const char *name;
|
|
410
|
+
|
|
411
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
|
371
412
|
|
|
372
|
-
|
|
373
|
-
|
|
413
|
+
REQUIRE_LIVE_DB(ctx);
|
|
414
|
+
REQUIRE_OPEN_STMT(ctx);
|
|
374
415
|
|
|
375
|
-
|
|
416
|
+
name = sqlite3_column_name(ctx->st, (int)NUM2INT(index));
|
|
376
417
|
|
|
377
|
-
|
|
378
|
-
|
|
418
|
+
VALUE ret = Qnil;
|
|
419
|
+
|
|
420
|
+
if (name) {
|
|
421
|
+
ret = interned_utf8_cstr(name);
|
|
422
|
+
}
|
|
423
|
+
return ret;
|
|
379
424
|
}
|
|
380
425
|
|
|
381
426
|
/* call-seq: stmt.column_decltype(index)
|
|
382
427
|
*
|
|
383
428
|
* Get the column type at +index+. 0 based.
|
|
384
429
|
*/
|
|
385
|
-
static VALUE
|
|
430
|
+
static VALUE
|
|
431
|
+
column_decltype(VALUE self, VALUE index)
|
|
386
432
|
{
|
|
387
|
-
|
|
388
|
-
|
|
433
|
+
sqlite3StmtRubyPtr ctx;
|
|
434
|
+
const char *name;
|
|
389
435
|
|
|
390
|
-
|
|
391
|
-
REQUIRE_OPEN_STMT(ctx);
|
|
436
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
|
392
437
|
|
|
393
|
-
|
|
438
|
+
REQUIRE_LIVE_DB(ctx);
|
|
439
|
+
REQUIRE_OPEN_STMT(ctx);
|
|
394
440
|
|
|
395
|
-
|
|
396
|
-
|
|
441
|
+
name = sqlite3_column_decltype(ctx->st, (int)NUM2INT(index));
|
|
442
|
+
|
|
443
|
+
if (name) { return rb_str_new2(name); }
|
|
444
|
+
return Qnil;
|
|
397
445
|
}
|
|
398
446
|
|
|
399
447
|
/* call-seq: stmt.bind_parameter_count
|
|
400
448
|
*
|
|
401
449
|
* Return the number of bind parameters
|
|
402
450
|
*/
|
|
403
|
-
static VALUE
|
|
451
|
+
static VALUE
|
|
452
|
+
bind_parameter_count(VALUE self)
|
|
453
|
+
{
|
|
454
|
+
sqlite3StmtRubyPtr ctx;
|
|
455
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
|
456
|
+
|
|
457
|
+
REQUIRE_LIVE_DB(ctx);
|
|
458
|
+
REQUIRE_OPEN_STMT(ctx);
|
|
459
|
+
|
|
460
|
+
return INT2NUM(sqlite3_bind_parameter_count(ctx->st));
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/** call-seq: stmt.named_params
|
|
464
|
+
*
|
|
465
|
+
* Return the list of named parameters in the statement.
|
|
466
|
+
* This returns a frozen array of strings (without the leading prefix character).
|
|
467
|
+
* The values of this list can be used to bind parameters
|
|
468
|
+
* to the statement using bind_param. Positional (?NNN) and anonymous (?)
|
|
469
|
+
* parameters are excluded.
|
|
470
|
+
*
|
|
471
|
+
*/
|
|
472
|
+
static VALUE
|
|
473
|
+
named_params(VALUE self)
|
|
474
|
+
{
|
|
475
|
+
sqlite3StmtRubyPtr ctx;
|
|
476
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
|
477
|
+
|
|
478
|
+
REQUIRE_LIVE_DB(ctx);
|
|
479
|
+
REQUIRE_OPEN_STMT(ctx);
|
|
480
|
+
|
|
481
|
+
int param_count = sqlite3_bind_parameter_count(ctx->st);
|
|
482
|
+
VALUE params = rb_ary_new2(param_count);
|
|
483
|
+
|
|
484
|
+
// The first host parameter has an index of 1, not 0.
|
|
485
|
+
for (int i = 1; i <= param_count; i++) {
|
|
486
|
+
const char *name = sqlite3_bind_parameter_name(ctx->st, i);
|
|
487
|
+
// We ignore positional and anonymous parameters, and also null values, since there can be
|
|
488
|
+
// gaps in the list.
|
|
489
|
+
if (name && *name != '?') {
|
|
490
|
+
VALUE param = interned_utf8_cstr(name + 1);
|
|
491
|
+
rb_ary_push(params, param);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
return rb_obj_freeze(params);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
enum stmt_stat_sym {
|
|
498
|
+
stmt_stat_sym_fullscan_steps,
|
|
499
|
+
stmt_stat_sym_sorts,
|
|
500
|
+
stmt_stat_sym_autoindexes,
|
|
501
|
+
stmt_stat_sym_vm_steps,
|
|
502
|
+
#ifdef SQLITE_STMTSTATUS_REPREPARE
|
|
503
|
+
stmt_stat_sym_reprepares,
|
|
504
|
+
#endif
|
|
505
|
+
#ifdef SQLITE_STMTSTATUS_RUN
|
|
506
|
+
stmt_stat_sym_runs,
|
|
507
|
+
#endif
|
|
508
|
+
#ifdef SQLITE_STMTSTATUS_FILTER_MISS
|
|
509
|
+
stmt_stat_sym_filter_misses,
|
|
510
|
+
#endif
|
|
511
|
+
#ifdef SQLITE_STMTSTATUS_FILTER_HIT
|
|
512
|
+
stmt_stat_sym_filter_hits,
|
|
513
|
+
#endif
|
|
514
|
+
stmt_stat_sym_last
|
|
515
|
+
};
|
|
516
|
+
|
|
517
|
+
static VALUE stmt_stat_symbols[stmt_stat_sym_last];
|
|
518
|
+
|
|
519
|
+
static void
|
|
520
|
+
setup_stmt_stat_symbols(void)
|
|
521
|
+
{
|
|
522
|
+
if (stmt_stat_symbols[0] == 0) {
|
|
523
|
+
#define S(s) stmt_stat_symbols[stmt_stat_sym_##s] = ID2SYM(rb_intern_const(#s))
|
|
524
|
+
S(fullscan_steps);
|
|
525
|
+
S(sorts);
|
|
526
|
+
S(autoindexes);
|
|
527
|
+
S(vm_steps);
|
|
528
|
+
#ifdef SQLITE_STMTSTATUS_REPREPARE
|
|
529
|
+
S(reprepares);
|
|
530
|
+
#endif
|
|
531
|
+
#ifdef SQLITE_STMTSTATUS_RUN
|
|
532
|
+
S(runs);
|
|
533
|
+
#endif
|
|
534
|
+
#ifdef SQLITE_STMTSTATUS_FILTER_MISS
|
|
535
|
+
S(filter_misses);
|
|
536
|
+
#endif
|
|
537
|
+
#ifdef SQLITE_STMTSTATUS_FILTER_HIT
|
|
538
|
+
S(filter_hits);
|
|
539
|
+
#endif
|
|
540
|
+
#undef S
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
static size_t
|
|
545
|
+
stmt_stat_internal(VALUE hash_or_sym, sqlite3_stmt *stmt)
|
|
546
|
+
{
|
|
547
|
+
VALUE hash = Qnil, key = Qnil;
|
|
548
|
+
|
|
549
|
+
setup_stmt_stat_symbols();
|
|
550
|
+
|
|
551
|
+
if (RB_TYPE_P(hash_or_sym, T_HASH)) {
|
|
552
|
+
hash = hash_or_sym;
|
|
553
|
+
} else if (SYMBOL_P(hash_or_sym)) {
|
|
554
|
+
key = hash_or_sym;
|
|
555
|
+
} else {
|
|
556
|
+
rb_raise(rb_eTypeError, "non-hash or symbol argument");
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
#define SET(name, stat_type) \
|
|
560
|
+
if (key == stmt_stat_symbols[stmt_stat_sym_##name]) \
|
|
561
|
+
return sqlite3_stmt_status(stmt, stat_type, 0); \
|
|
562
|
+
else if (hash != Qnil) \
|
|
563
|
+
rb_hash_aset(hash, stmt_stat_symbols[stmt_stat_sym_##name], SIZET2NUM(sqlite3_stmt_status(stmt, stat_type, 0)));
|
|
564
|
+
|
|
565
|
+
SET(fullscan_steps, SQLITE_STMTSTATUS_FULLSCAN_STEP);
|
|
566
|
+
SET(sorts, SQLITE_STMTSTATUS_SORT);
|
|
567
|
+
SET(autoindexes, SQLITE_STMTSTATUS_AUTOINDEX);
|
|
568
|
+
SET(vm_steps, SQLITE_STMTSTATUS_VM_STEP);
|
|
569
|
+
#ifdef SQLITE_STMTSTATUS_REPREPARE
|
|
570
|
+
SET(reprepares, SQLITE_STMTSTATUS_REPREPARE);
|
|
571
|
+
#endif
|
|
572
|
+
#ifdef SQLITE_STMTSTATUS_RUN
|
|
573
|
+
SET(runs, SQLITE_STMTSTATUS_RUN);
|
|
574
|
+
#endif
|
|
575
|
+
#ifdef SQLITE_STMTSTATUS_FILTER_MISS
|
|
576
|
+
SET(filter_misses, SQLITE_STMTSTATUS_FILTER_MISS);
|
|
577
|
+
#endif
|
|
578
|
+
#ifdef SQLITE_STMTSTATUS_FILTER_HIT
|
|
579
|
+
SET(filter_hits, SQLITE_STMTSTATUS_FILTER_HIT);
|
|
580
|
+
#endif
|
|
581
|
+
#undef SET
|
|
582
|
+
|
|
583
|
+
if (!NIL_P(key)) { /* matched key should return above */
|
|
584
|
+
rb_raise(rb_eArgError, "unknown key: %"PRIsVALUE, rb_sym2str(key));
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
return 0;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/* call-seq: stmt.stats_as_hash(hash)
|
|
591
|
+
*
|
|
592
|
+
* Returns a Hash containing information about the statement.
|
|
593
|
+
*/
|
|
594
|
+
static VALUE
|
|
595
|
+
stats_as_hash(VALUE self)
|
|
404
596
|
{
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
597
|
+
sqlite3StmtRubyPtr ctx;
|
|
598
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
|
599
|
+
|
|
600
|
+
REQUIRE_LIVE_DB(ctx);
|
|
601
|
+
REQUIRE_OPEN_STMT(ctx);
|
|
408
602
|
|
|
409
|
-
|
|
603
|
+
VALUE arg = rb_hash_new();
|
|
604
|
+
|
|
605
|
+
stmt_stat_internal(arg, ctx->st);
|
|
606
|
+
return arg;
|
|
410
607
|
}
|
|
411
608
|
|
|
609
|
+
/* call-seq: stmt.stmt_stat(hash_or_key)
|
|
610
|
+
*
|
|
611
|
+
* Returns a Hash containing information about the statement.
|
|
612
|
+
*/
|
|
613
|
+
static VALUE
|
|
614
|
+
stat_for(VALUE self, VALUE key)
|
|
615
|
+
{
|
|
616
|
+
sqlite3StmtRubyPtr ctx;
|
|
617
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
|
618
|
+
|
|
619
|
+
REQUIRE_LIVE_DB(ctx);
|
|
620
|
+
REQUIRE_OPEN_STMT(ctx);
|
|
621
|
+
|
|
622
|
+
if (SYMBOL_P(key)) {
|
|
623
|
+
size_t value = stmt_stat_internal(key, ctx->st);
|
|
624
|
+
return SIZET2NUM(value);
|
|
625
|
+
} else {
|
|
626
|
+
rb_raise(rb_eTypeError, "non-symbol given");
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
#ifdef SQLITE_STMTSTATUS_MEMUSED
|
|
631
|
+
/* call-seq: stmt.memused
|
|
632
|
+
*
|
|
633
|
+
* Return the approximate number of bytes of heap memory used to store the prepared statement
|
|
634
|
+
*/
|
|
635
|
+
static VALUE
|
|
636
|
+
memused(VALUE self)
|
|
637
|
+
{
|
|
638
|
+
sqlite3StmtRubyPtr ctx;
|
|
639
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
|
640
|
+
|
|
641
|
+
REQUIRE_LIVE_DB(ctx);
|
|
642
|
+
REQUIRE_OPEN_STMT(ctx);
|
|
643
|
+
|
|
644
|
+
return INT2NUM(sqlite3_stmt_status(ctx->st, SQLITE_STMTSTATUS_MEMUSED, 0));
|
|
645
|
+
}
|
|
646
|
+
#endif
|
|
647
|
+
|
|
412
648
|
#ifdef HAVE_SQLITE3_COLUMN_DATABASE_NAME
|
|
413
649
|
|
|
414
650
|
/* call-seq: stmt.database_name(column_index)
|
|
415
651
|
*
|
|
416
652
|
* Return the database name for the column at +column_index+
|
|
417
653
|
*/
|
|
418
|
-
static VALUE
|
|
654
|
+
static VALUE
|
|
655
|
+
database_name(VALUE self, VALUE index)
|
|
419
656
|
{
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
REQUIRE_OPEN_STMT(ctx);
|
|
657
|
+
sqlite3StmtRubyPtr ctx;
|
|
658
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
|
423
659
|
|
|
424
|
-
|
|
425
|
-
|
|
660
|
+
REQUIRE_LIVE_DB(ctx);
|
|
661
|
+
REQUIRE_OPEN_STMT(ctx);
|
|
662
|
+
|
|
663
|
+
return SQLITE3_UTF8_STR_NEW2(
|
|
664
|
+
sqlite3_column_database_name(ctx->st, NUM2INT(index)));
|
|
426
665
|
}
|
|
427
666
|
|
|
428
667
|
#endif
|
|
429
668
|
|
|
430
|
-
|
|
669
|
+
/* call-seq: stmt.sql
|
|
670
|
+
*
|
|
671
|
+
* Returns the SQL statement used to create this prepared statement
|
|
672
|
+
*/
|
|
673
|
+
static VALUE
|
|
674
|
+
get_sql(VALUE self)
|
|
675
|
+
{
|
|
676
|
+
sqlite3StmtRubyPtr ctx;
|
|
677
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
|
678
|
+
|
|
679
|
+
REQUIRE_LIVE_DB(ctx);
|
|
680
|
+
REQUIRE_OPEN_STMT(ctx);
|
|
681
|
+
|
|
682
|
+
return rb_obj_freeze(SQLITE3_UTF8_STR_NEW2(sqlite3_sql(ctx->st)));
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
/* call-seq: stmt.expanded_sql
|
|
686
|
+
*
|
|
687
|
+
* Returns the SQL statement used to create this prepared statement, but
|
|
688
|
+
* with bind parameters substituted in to the statement.
|
|
689
|
+
*/
|
|
690
|
+
static VALUE
|
|
691
|
+
get_expanded_sql(VALUE self)
|
|
431
692
|
{
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
rb_define_method(cSqlite3Statement, "closed?", closed_p, 0);
|
|
438
|
-
rb_define_method(cSqlite3Statement, "bind_param", bind_param, 2);
|
|
439
|
-
rb_define_method(cSqlite3Statement, "reset!", reset_bang, 0);
|
|
440
|
-
rb_define_method(cSqlite3Statement, "clear_bindings!", clear_bindings_bang, 0);
|
|
441
|
-
rb_define_method(cSqlite3Statement, "step", step, 0);
|
|
442
|
-
rb_define_method(cSqlite3Statement, "done?", done_p, 0);
|
|
443
|
-
rb_define_method(cSqlite3Statement, "column_count", column_count, 0);
|
|
444
|
-
rb_define_method(cSqlite3Statement, "column_name", column_name, 1);
|
|
445
|
-
rb_define_method(cSqlite3Statement, "column_decltype", column_decltype, 1);
|
|
446
|
-
rb_define_method(cSqlite3Statement, "bind_parameter_count", bind_parameter_count, 0);
|
|
693
|
+
sqlite3StmtRubyPtr ctx;
|
|
694
|
+
char *expanded_sql;
|
|
695
|
+
VALUE rb_expanded_sql;
|
|
696
|
+
|
|
697
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
|
447
698
|
|
|
699
|
+
REQUIRE_LIVE_DB(ctx);
|
|
700
|
+
REQUIRE_OPEN_STMT(ctx);
|
|
701
|
+
|
|
702
|
+
expanded_sql = sqlite3_expanded_sql(ctx->st);
|
|
703
|
+
rb_expanded_sql = rb_obj_freeze(SQLITE3_UTF8_STR_NEW2(expanded_sql));
|
|
704
|
+
sqlite3_free(expanded_sql);
|
|
705
|
+
|
|
706
|
+
return rb_expanded_sql;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
void
|
|
710
|
+
init_sqlite3_statement(void)
|
|
711
|
+
{
|
|
712
|
+
cSqlite3Statement = rb_define_class_under(mSqlite3, "Statement", rb_cObject);
|
|
713
|
+
|
|
714
|
+
rb_define_alloc_func(cSqlite3Statement, allocate);
|
|
715
|
+
rb_define_method(cSqlite3Statement, "close", sqlite3_rb_close, 0);
|
|
716
|
+
rb_define_method(cSqlite3Statement, "closed?", closed_p, 0);
|
|
717
|
+
rb_define_method(cSqlite3Statement, "bind_param", bind_param, 2);
|
|
718
|
+
rb_define_method(cSqlite3Statement, "reset!", reset_bang, 0);
|
|
719
|
+
rb_define_method(cSqlite3Statement, "clear_bindings!", clear_bindings_bang, 0);
|
|
720
|
+
rb_define_method(cSqlite3Statement, "step", step, 0);
|
|
721
|
+
rb_define_method(cSqlite3Statement, "done?", done_p, 0);
|
|
722
|
+
rb_define_method(cSqlite3Statement, "column_count", column_count, 0);
|
|
723
|
+
rb_define_method(cSqlite3Statement, "column_name", column_name, 1);
|
|
724
|
+
rb_define_method(cSqlite3Statement, "column_decltype", column_decltype, 1);
|
|
725
|
+
rb_define_method(cSqlite3Statement, "bind_parameter_count", bind_parameter_count, 0);
|
|
726
|
+
rb_define_method(cSqlite3Statement, "named_params", named_params, 0);
|
|
727
|
+
rb_define_method(cSqlite3Statement, "sql", get_sql, 0);
|
|
728
|
+
rb_define_method(cSqlite3Statement, "expanded_sql", get_expanded_sql, 0);
|
|
448
729
|
#ifdef HAVE_SQLITE3_COLUMN_DATABASE_NAME
|
|
449
|
-
|
|
730
|
+
rb_define_method(cSqlite3Statement, "database_name", database_name, 1);
|
|
731
|
+
#endif
|
|
732
|
+
#ifdef SQLITE_STMTSTATUS_MEMUSED
|
|
733
|
+
rb_define_method(cSqlite3Statement, "memused", memused, 0);
|
|
450
734
|
#endif
|
|
735
|
+
|
|
736
|
+
rb_define_private_method(cSqlite3Statement, "prepare", prepare, 2);
|
|
737
|
+
rb_define_private_method(cSqlite3Statement, "stats_as_hash", stats_as_hash, 0);
|
|
738
|
+
rb_define_private_method(cSqlite3Statement, "stat_for", stat_for, 1);
|
|
451
739
|
}
|