rubyfb 0.5.9 → 0.6
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.
- data/CHANGELOG +36 -0
- data/Manifest +1 -0
- data/README +75 -175
- data/Rakefile +1 -1
- data/ext/Blob.c +1 -1
- data/ext/Connection.c +40 -126
- data/ext/FireRubyException.c +27 -41
- data/ext/Generator.c +61 -339
- data/ext/Generator.h +0 -5
- data/ext/ResultSet.c +201 -381
- data/ext/ResultSet.h +8 -9
- data/ext/Statement.c +495 -426
- data/ext/Statement.h +8 -11
- data/ext/Transaction.c +3 -2
- data/ext/TypeMap.c +44 -43
- data/ext/TypeMap.h +1 -1
- data/lib/active_record/connection_adapters/rubyfb_adapter.rb +370 -120
- data/lib/arel/visitors/rubyfb.rb +7 -3
- data/lib/arel/visitors/rubyfb_15compat.rb +8 -4
- data/lib/rubyfb_lib.so +0 -0
- data/lib/src.rb +76 -39
- data/rubyfb.gemspec +3 -3
- data/test/AddRemoveUserTest.rb +7 -0
- data/test/BackupRestoreTest.rb +1 -1
- data/test/BlobTest.rb +5 -5
- data/test/GeneratorTest.rb +8 -8
- data/test/KeyTest.rb +1 -2
- data/test/ResultSetTest.rb +14 -16
- data/test/RoleTest.rb +2 -2
- data/test/RowCountTest.rb +19 -19
- data/test/RowTest.rb +7 -8
- data/test/SQLTest.rb +7 -8
- data/test/StatementTest.rb +18 -24
- data/test/StoredProcedureTest.rb +80 -0
- data/test/TransactionTest.rb +1 -1
- data/test/TypeTest.rb +4 -5
- metadata +5 -5
data/ext/Statement.c
CHANGED
@@ -34,20 +34,194 @@
|
|
34
34
|
|
35
35
|
/* Function prototypes. */
|
36
36
|
static VALUE allocateStatement(VALUE);
|
37
|
-
static VALUE initializeStatement(VALUE, VALUE, VALUE
|
37
|
+
static VALUE initializeStatement(VALUE, VALUE, VALUE);
|
38
38
|
static VALUE getStatementSQL(VALUE);
|
39
|
-
static VALUE getStatementTransaction(VALUE);
|
40
39
|
static VALUE getStatementConnection(VALUE);
|
41
40
|
static VALUE getStatementDialect(VALUE);
|
42
41
|
static VALUE getStatementType(VALUE);
|
43
42
|
static VALUE getStatementParameterCount(VALUE);
|
44
|
-
static VALUE
|
45
|
-
static VALUE
|
43
|
+
static VALUE execStatement(int, VALUE*, VALUE);
|
44
|
+
static VALUE execAndCloseStatement(int, VALUE*, VALUE);
|
46
45
|
static VALUE closeStatement(VALUE);
|
46
|
+
static VALUE getStatementPrepared(VALUE);
|
47
|
+
static VALUE prepareStatement(int, VALUE*, VALUE);
|
48
|
+
|
49
|
+
VALUE execAndManageTransaction(VALUE, VALUE, VALUE);
|
50
|
+
VALUE execAndManageStatement(VALUE, VALUE, VALUE);
|
51
|
+
VALUE rescueLocalTransaction(VALUE, VALUE);
|
52
|
+
VALUE execStatementFromArray(VALUE);
|
53
|
+
VALUE rescueStatement(VALUE, VALUE);
|
54
|
+
VALUE execInTransactionFromArray(VALUE);
|
55
|
+
VALUE execInTransaction(VALUE, VALUE, VALUE);
|
56
|
+
void prepareInTransaction(VALUE, VALUE);
|
57
|
+
VALUE prepareFromArray(VALUE);
|
58
|
+
void statementFree(void *);
|
59
|
+
StatementHandle* getPreparedHandle(VALUE self);
|
47
60
|
|
48
61
|
/* Globals. */
|
49
62
|
VALUE cStatement;
|
50
63
|
|
64
|
+
/**
|
65
|
+
* This function prepares a Firebird SQL statement for execution.
|
66
|
+
*
|
67
|
+
* @param connection A pointer to the database connection that will be used
|
68
|
+
* to prepare the statement.
|
69
|
+
* @param transaction A pointer to the database transaction that will be used
|
70
|
+
* to prepare the statement.
|
71
|
+
* @param sql A string containing the SQL statement to be executed.
|
72
|
+
* @param statement A pointer to a Firebird statement that will be prepared.
|
73
|
+
* @param dialect A short integer containing the SQL dialect to be used in
|
74
|
+
* preparing the statement.
|
75
|
+
* @param type A pointer to an integer that will be assigned the type
|
76
|
+
* of the SQL statement prepared.
|
77
|
+
* @param inputs A pointer to an integer that will be assigned a count of
|
78
|
+
* the parameters for the SQL statement.
|
79
|
+
* @param outputs A pointer to an integer that will be assigned a count of
|
80
|
+
* the output columns for the SQL statement.
|
81
|
+
*
|
82
|
+
*/
|
83
|
+
void fb_prepare(isc_db_handle *connection, isc_tr_handle *transaction,
|
84
|
+
char *sql, isc_stmt_handle *statement, short dialect,
|
85
|
+
int *type, int *inputs, int *outputs) {
|
86
|
+
ISC_STATUS status[ISC_STATUS_LENGTH];
|
87
|
+
XSQLDA *da = NULL;
|
88
|
+
char list[] = {isc_info_sql_stmt_type},
|
89
|
+
info[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
90
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
91
|
+
|
92
|
+
/* Prepare the statement. */
|
93
|
+
if(isc_dsql_allocate_statement(status, connection, statement)) {
|
94
|
+
rb_fireruby_raise(status, "Error allocating a SQL statement.");
|
95
|
+
}
|
96
|
+
|
97
|
+
da = (XSQLDA *)ALLOC_N(char, XSQLDA_LENGTH(1));
|
98
|
+
if(da == NULL) {
|
99
|
+
rb_raise(rb_eNoMemError,
|
100
|
+
"Memory allocation failure preparing a statement.");
|
101
|
+
}
|
102
|
+
da->version = SQLDA_VERSION1;
|
103
|
+
da->sqln = 1;
|
104
|
+
if(isc_dsql_prepare(status, transaction, statement, 0, sql, dialect,
|
105
|
+
da)) {
|
106
|
+
free(da);
|
107
|
+
rb_fireruby_raise(status, "Error preparing a SQL statement.");
|
108
|
+
}
|
109
|
+
*outputs = da->sqld;
|
110
|
+
|
111
|
+
/* Get the parameter count. */
|
112
|
+
if(isc_dsql_describe_bind(status, statement, dialect, da)) {
|
113
|
+
free(da);
|
114
|
+
rb_fireruby_raise(status, "Error determining statement parameters.");
|
115
|
+
}
|
116
|
+
*inputs = da->sqld;
|
117
|
+
free(da);
|
118
|
+
|
119
|
+
/* Get the statement type details. */
|
120
|
+
if(isc_dsql_sql_info(status, statement, 1, list, 20, info) ||
|
121
|
+
info[0] != isc_info_sql_stmt_type) {
|
122
|
+
rb_fireruby_raise(status, "Error determining SQL statement type.");
|
123
|
+
}
|
124
|
+
*type = isc_vax_integer(&info[3], isc_vax_integer(&info[1], 2));
|
125
|
+
}
|
126
|
+
|
127
|
+
/**
|
128
|
+
* Return affected row count for DML statements
|
129
|
+
*
|
130
|
+
* @param statement A pointer to the statement handle
|
131
|
+
*/
|
132
|
+
long fb_query_affected(StatementHandle *statement) {
|
133
|
+
ISC_STATUS status[ISC_STATUS_LENGTH];
|
134
|
+
ISC_STATUS execute_result;
|
135
|
+
long result = 0;
|
136
|
+
int info = 0,
|
137
|
+
done = 0;
|
138
|
+
char items[] = {isc_info_sql_records},
|
139
|
+
buffer[40],
|
140
|
+
*position = buffer + 3;
|
141
|
+
|
142
|
+
switch(statement->type) {
|
143
|
+
case isc_info_sql_stmt_update:
|
144
|
+
info = isc_info_req_update_count;
|
145
|
+
break;
|
146
|
+
case isc_info_sql_stmt_delete:
|
147
|
+
info = isc_info_req_delete_count;
|
148
|
+
break;
|
149
|
+
case isc_info_sql_stmt_insert:
|
150
|
+
info = isc_info_req_insert_count;
|
151
|
+
break;
|
152
|
+
default:
|
153
|
+
return (result);
|
154
|
+
}
|
155
|
+
|
156
|
+
if(isc_dsql_sql_info(status, &statement->handle, sizeof(items), items,
|
157
|
+
sizeof(buffer), buffer)) {
|
158
|
+
rb_fireruby_raise(status, "Error retrieving affected row count.");
|
159
|
+
}
|
160
|
+
|
161
|
+
while(*position != isc_info_end && done == 0) {
|
162
|
+
char current = *position++;
|
163
|
+
long temp[] = {0, 0};
|
164
|
+
|
165
|
+
temp[0] = isc_vax_integer(position, 2);
|
166
|
+
position += 2;
|
167
|
+
temp[1] = isc_vax_integer(position, temp[0]);
|
168
|
+
position += temp[0];
|
169
|
+
|
170
|
+
if(current == info) {
|
171
|
+
result = temp[1];
|
172
|
+
done = 1;
|
173
|
+
}
|
174
|
+
}
|
175
|
+
return (result);
|
176
|
+
}
|
177
|
+
|
178
|
+
/**
|
179
|
+
* Prepare statement parsing arguments array
|
180
|
+
*
|
181
|
+
* @param args Array containing statement and transaction objects
|
182
|
+
*
|
183
|
+
* @return Qnil
|
184
|
+
*/
|
185
|
+
VALUE prepareFromArray(VALUE args) {
|
186
|
+
VALUE self = rb_ary_entry(args, 0);
|
187
|
+
VALUE transaction = rb_ary_entry(args, 1);
|
188
|
+
prepareInTransaction(self, transaction);
|
189
|
+
return (Qnil);
|
190
|
+
}
|
191
|
+
|
192
|
+
/**
|
193
|
+
* Prepare statement within transaction context
|
194
|
+
*
|
195
|
+
* @param self A reference to the statement object
|
196
|
+
*
|
197
|
+
* @param transaction A reference to the transaction object
|
198
|
+
*
|
199
|
+
*/
|
200
|
+
void prepareInTransaction(VALUE self, VALUE transaction) {
|
201
|
+
StatementHandle *hStatement = NULL;
|
202
|
+
Data_Get_Struct(self, StatementHandle, hStatement);
|
203
|
+
|
204
|
+
if(0 == hStatement->handle) {
|
205
|
+
ConnectionHandle *hConnection = NULL;
|
206
|
+
TransactionHandle *hTransaction = NULL;
|
207
|
+
VALUE sql = rb_iv_get(self, "@sql");
|
208
|
+
Data_Get_Struct(getStatementConnection(self), ConnectionHandle, hConnection);
|
209
|
+
Data_Get_Struct(transaction, TransactionHandle, hTransaction);
|
210
|
+
|
211
|
+
|
212
|
+
fb_prepare(&hConnection->handle, &hTransaction->handle,
|
213
|
+
StringValuePtr(sql), &hStatement->handle,
|
214
|
+
hStatement->dialect, &hStatement->type, &hStatement->inputs,
|
215
|
+
&hStatement->outputs);
|
216
|
+
if(hStatement->outputs > 0) {
|
217
|
+
/* Allocate the XSQLDA */
|
218
|
+
hStatement->output = allocateOutXSQLDA(hStatement->outputs,
|
219
|
+
&hStatement->handle,
|
220
|
+
hStatement->dialect);
|
221
|
+
prepareDataArea(hStatement->output);
|
222
|
+
}
|
223
|
+
}
|
224
|
+
}
|
51
225
|
|
52
226
|
/**
|
53
227
|
* This function integrates with the Ruby memory control system to provide for
|
@@ -69,8 +243,9 @@ VALUE allocateStatement(VALUE klass) {
|
|
69
243
|
statement->handle = 0;
|
70
244
|
statement->type = -1;
|
71
245
|
statement->inputs = 0;
|
246
|
+
statement->outputs = 0;
|
72
247
|
statement->dialect = 0;
|
73
|
-
statement->
|
248
|
+
statement->output = NULL;
|
74
249
|
|
75
250
|
return(Data_Wrap_Struct(klass, NULL, statementFree, statement));
|
76
251
|
}
|
@@ -82,23 +257,18 @@ VALUE allocateStatement(VALUE klass) {
|
|
82
257
|
* @param self A reference to the Statement object to be initialized.
|
83
258
|
* @param connection A reference to the Connection object that the statement
|
84
259
|
* will execute through.
|
85
|
-
* @param transaction A reference to the Transaction object that the statement
|
86
|
-
* will work under.
|
87
260
|
* @param sql A reference to a String object containing the text of
|
88
261
|
* the SQL statement to be executed.
|
89
|
-
* @param dialect A reference to an integer object specifying the dialect
|
90
|
-
* to be used in executing the statement. This should be a
|
91
|
-
* value of between 1 and 3.
|
92
262
|
*
|
93
263
|
* @return A reference to the newly initialized Statement object.
|
94
264
|
*
|
95
265
|
*/
|
96
|
-
VALUE initializeStatement(VALUE self, VALUE connection, VALUE
|
97
|
-
|
98
|
-
StatementHandle *statement = NULL;
|
266
|
+
VALUE initializeStatement(VALUE self, VALUE connection, VALUE sql) {
|
267
|
+
StatementHandle *hStatement = NULL;
|
99
268
|
short setting = 0;
|
100
|
-
VALUE value = Qnil;
|
101
269
|
|
270
|
+
sql = rb_funcall(sql, rb_intern("to_s"), 0);
|
271
|
+
|
102
272
|
/* Validate the inputs. */
|
103
273
|
if(TYPE(connection) == T_DATA &&
|
104
274
|
RDATA(connection)->dfree == (RUBY_DATA_FUNC)connectionFree) {
|
@@ -109,35 +279,10 @@ VALUE initializeStatement(VALUE self, VALUE connection, VALUE transaction,
|
|
109
279
|
rb_fireruby_raise(NULL, "Invalid connection specified for statement.");
|
110
280
|
}
|
111
281
|
|
112
|
-
|
113
|
-
RDATA(transaction)->dfree == (RUBY_DATA_FUNC)transactionFree) {
|
114
|
-
if(rb_funcall(transaction, rb_intern("active?"), 0) == Qfalse) {
|
115
|
-
rb_fireruby_raise(NULL, "Inactive transaction specified for statement.");
|
116
|
-
}
|
117
|
-
} else {
|
118
|
-
rb_fireruby_raise(NULL, "Invalid transaction specified for statement.");
|
119
|
-
}
|
120
|
-
|
121
|
-
value = rb_funcall(dialect, rb_intern("to_i"), 0);
|
122
|
-
if(TYPE(value) == T_FIXNUM) {
|
123
|
-
setting = FIX2INT(value);
|
124
|
-
if(setting < 1 || setting > 3) {
|
125
|
-
rb_fireruby_raise(NULL,
|
126
|
-
"Invalid dialect value specified for statement. " \
|
127
|
-
"The dialect value must be between 1 and 3.");
|
128
|
-
}
|
129
|
-
} else {
|
130
|
-
rb_fireruby_raise(NULL,
|
131
|
-
"Invalid dialect value specified for statement. The " \
|
132
|
-
"dialect value must be between 1 and 3.");
|
133
|
-
}
|
134
|
-
|
135
|
-
Data_Get_Struct(self, StatementHandle, statement);
|
282
|
+
Data_Get_Struct(self, StatementHandle, hStatement);
|
136
283
|
rb_iv_set(self, "@connection", connection);
|
137
|
-
rb_iv_set(self, "@
|
138
|
-
|
139
|
-
rb_iv_set(self, "@dialect", value);
|
140
|
-
statement->dialect = setting;
|
284
|
+
rb_iv_set(self, "@sql", sql);
|
285
|
+
hStatement->dialect = 3; //FIXME - from connection
|
141
286
|
|
142
287
|
return(self);
|
143
288
|
}
|
@@ -167,21 +312,9 @@ VALUE getStatementSQL(VALUE self) {
|
|
167
312
|
*
|
168
313
|
*/
|
169
314
|
VALUE getStatementConnection(VALUE self) {
|
170
|
-
|
171
|
-
}
|
172
|
-
|
315
|
+
VALUE connection = rb_iv_get(self, "@connection");
|
173
316
|
|
174
|
-
|
175
|
-
* This function provides the transaction sttribute accessor method for the
|
176
|
-
* Statement class.
|
177
|
-
*
|
178
|
-
* @param self A reference to the Statement object to call the method on.
|
179
|
-
*
|
180
|
-
* @return A reference to a Transaction object.
|
181
|
-
*
|
182
|
-
*/
|
183
|
-
VALUE getStatementTransaction(VALUE self) {
|
184
|
-
return(rb_iv_get(self, "@transaction"));
|
317
|
+
return(connection);
|
185
318
|
}
|
186
319
|
|
187
320
|
|
@@ -195,11 +328,11 @@ VALUE getStatementTransaction(VALUE self) {
|
|
195
328
|
*
|
196
329
|
*/
|
197
330
|
VALUE getStatementDialect(VALUE self) {
|
198
|
-
|
331
|
+
StatementHandle *hStatement = NULL;
|
332
|
+
Data_Get_Struct(self, StatementHandle, hStatement);
|
333
|
+
return(INT2FIX(hStatement->dialect));
|
199
334
|
}
|
200
335
|
|
201
|
-
|
202
|
-
|
203
336
|
/**
|
204
337
|
* This function provides the type attribute accessor method for the Statement
|
205
338
|
* class.
|
@@ -210,27 +343,10 @@ VALUE getStatementDialect(VALUE self) {
|
|
210
343
|
*
|
211
344
|
*/
|
212
345
|
VALUE getStatementType(VALUE self) {
|
213
|
-
StatementHandle
|
214
|
-
|
215
|
-
TransactionHandle *transaction = NULL;
|
216
|
-
int outputs = 0;
|
217
|
-
VALUE tmp_str = Qnil;
|
218
|
-
|
219
|
-
Data_Get_Struct(self, StatementHandle, statement);
|
220
|
-
Data_Get_Struct(rb_iv_get(self, "@connection"), ConnectionHandle, connection);
|
221
|
-
Data_Get_Struct(rb_iv_get(self, "@transaction"), TransactionHandle, transaction);
|
222
|
-
if(statement->handle == 0) {
|
223
|
-
tmp_str = rb_iv_get(self, "@sql");
|
224
|
-
prepare(&connection->handle, &transaction->handle,
|
225
|
-
StringValuePtr(tmp_str), &statement->handle,
|
226
|
-
statement->dialect, &statement->type, &statement->inputs,
|
227
|
-
&outputs);
|
228
|
-
}
|
229
|
-
|
230
|
-
return(INT2FIX(statement->type));
|
346
|
+
StatementHandle *hStatement = getPreparedHandle(self);
|
347
|
+
return(INT2FIX(hStatement->type));
|
231
348
|
}
|
232
349
|
|
233
|
-
|
234
350
|
/**
|
235
351
|
* This function provides the parameter count sttribute accessor method for the
|
236
352
|
* Statement class.
|
@@ -241,329 +357,334 @@ VALUE getStatementType(VALUE self) {
|
|
241
357
|
*
|
242
358
|
*/
|
243
359
|
VALUE getStatementParameterCount(VALUE self) {
|
244
|
-
StatementHandle *statement =
|
245
|
-
|
246
|
-
Data_Get_Struct(self, StatementHandle, statement);
|
247
|
-
if(statement->handle == 0) {
|
248
|
-
getStatementType(self);
|
249
|
-
}
|
250
|
-
|
360
|
+
StatementHandle *statement = getPreparedHandle(self);
|
251
361
|
return(INT2NUM(statement->inputs));
|
252
362
|
}
|
253
363
|
|
254
|
-
|
255
364
|
/**
|
256
|
-
*
|
365
|
+
* Execute statement and take care of implicit transaction management
|
257
366
|
*
|
258
|
-
* @param self
|
367
|
+
* @param self A reference to the statement object
|
368
|
+
*
|
369
|
+
* @param parameters A reference to the parameter bindings object, can be Qnil
|
370
|
+
*
|
371
|
+
* @param transaction A reference to the transaction object, can be Qnil,
|
372
|
+
* if so - an implicit transaction is started and resolved when appropriate
|
259
373
|
*
|
260
374
|
* @return One of a count of the number of rows affected by the SQL statement,
|
261
375
|
* a ResultSet object for a query or nil.
|
262
376
|
*
|
263
377
|
*/
|
264
|
-
VALUE
|
265
|
-
VALUE result;
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
result =
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
case isc_info_sql_stmt_update:
|
284
|
-
case isc_info_sql_stmt_delete:
|
285
|
-
Data_Get_Struct(self, StatementHandle, statement);
|
286
|
-
Data_Get_Struct(rb_iv_get(self, "@transaction"), TransactionHandle,
|
287
|
-
transaction);
|
288
|
-
execute(&transaction->handle, &statement->handle, statement->dialect,
|
289
|
-
NULL, statement->type, &affected);
|
290
|
-
result = INT2NUM(affected);
|
291
|
-
break;
|
292
|
-
|
293
|
-
default:
|
294
|
-
Data_Get_Struct(self, StatementHandle, statement);
|
295
|
-
Data_Get_Struct(rb_iv_get(self, "@transaction"), TransactionHandle,
|
296
|
-
transaction);
|
297
|
-
execute(&transaction->handle, &statement->handle, statement->dialect,
|
298
|
-
NULL, statement->type, &affected);
|
299
|
-
result = Qnil;
|
378
|
+
VALUE execAndManageTransaction(VALUE self, VALUE parameters, VALUE transaction) {
|
379
|
+
VALUE result = Qnil;
|
380
|
+
|
381
|
+
if(Qnil == transaction) {
|
382
|
+
VALUE args = rb_ary_new();
|
383
|
+
|
384
|
+
transaction = rb_transaction_new(getStatementConnection(self));
|
385
|
+
rb_ary_push(args, self);
|
386
|
+
rb_ary_push(args, transaction);
|
387
|
+
rb_ary_push(args, parameters);
|
388
|
+
|
389
|
+
result = rb_rescue(execInTransactionFromArray, args, rescueLocalTransaction, transaction);
|
390
|
+
if(isActiveResultSet(result)) {
|
391
|
+
resultSetManageTransaction(result);
|
392
|
+
} else {
|
393
|
+
rb_funcall(transaction, rb_intern("commit"), 0);
|
394
|
+
}
|
395
|
+
} else {
|
396
|
+
result = execInTransaction(self, transaction, parameters);
|
300
397
|
}
|
301
|
-
|
302
|
-
return(result);
|
398
|
+
return (result);
|
303
399
|
}
|
304
400
|
|
305
|
-
|
306
401
|
/**
|
307
|
-
*
|
402
|
+
* Execute statement and take care of closing it when appropriate
|
403
|
+
*
|
404
|
+
* @param self A reference to the statement object
|
405
|
+
*
|
406
|
+
* @param parameters A reference to the parameter bindings object, can be Qnil
|
308
407
|
*
|
309
|
-
* @param
|
310
|
-
*
|
311
|
-
* @param parameters An array containing the parameters to be used in
|
312
|
-
* executing the statement.
|
408
|
+
* @param transaction A reference to the transaction object, can be Qnil,
|
409
|
+
* if so - an implicit transaction is started and resolved when appropriate
|
313
410
|
*
|
314
411
|
* @return One of a count of the number of rows affected by the SQL statement,
|
315
412
|
* a ResultSet object for a query or nil.
|
316
413
|
*
|
317
414
|
*/
|
318
|
-
VALUE
|
319
|
-
VALUE result
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
result = rb_result_set_new(rb_iv_get(self, "@connection"),
|
329
|
-
rb_iv_get(self, "@transaction"),
|
330
|
-
rb_iv_get(self, "@sql"),
|
331
|
-
rb_iv_get(self, "@dialect"),
|
332
|
-
parameters);
|
415
|
+
VALUE execAndManageStatement(VALUE self, VALUE parameters, VALUE transaction) {
|
416
|
+
VALUE result = Qnil,
|
417
|
+
args = rb_ary_new();
|
418
|
+
|
419
|
+
rb_ary_push(args, self);
|
420
|
+
rb_ary_push(args, parameters);
|
421
|
+
rb_ary_push(args, transaction);
|
422
|
+
result = rb_rescue(execStatementFromArray, args, rescueStatement, self);
|
423
|
+
if(isActiveResultSet(result)) {
|
424
|
+
resultSetManageStatement(result);
|
333
425
|
} else {
|
334
|
-
|
335
|
-
Data_Get_Struct(self, StatementHandle, statement);
|
336
|
-
if(statement->inputs > 0) {
|
337
|
-
VALUE value = Qnil;
|
338
|
-
int size = 0;
|
339
|
-
|
340
|
-
if(parameters == Qnil) {
|
341
|
-
rb_fireruby_raise(NULL,
|
342
|
-
"Empty parameter list specified for statement.");
|
343
|
-
}
|
344
|
-
|
345
|
-
value = rb_funcall(parameters, rb_intern("size"), 0);
|
346
|
-
size = TYPE(value) == T_FIXNUM ? FIX2INT(value) : NUM2INT(value);
|
347
|
-
if(size < statement->inputs) {
|
348
|
-
rb_fireruby_raise(NULL,
|
349
|
-
"Insufficient parameters specified for statement.");
|
350
|
-
}
|
351
|
-
|
352
|
-
/* Allocate the XSQLDA and populate it. */
|
353
|
-
statement->parameters = allocateInXSQLDA(statement->inputs,
|
354
|
-
&statement->handle,
|
355
|
-
statement->dialect);
|
356
|
-
prepareDataArea(statement->parameters);
|
357
|
-
setParameters(statement->parameters, parameters, self);
|
358
|
-
}
|
359
|
-
|
360
|
-
/* Execute the statement. */
|
361
|
-
Data_Get_Struct(self, StatementHandle, statement);
|
362
|
-
Data_Get_Struct(rb_iv_get(self, "@transaction"), TransactionHandle,
|
363
|
-
transaction);
|
364
|
-
execute(&transaction->handle, &statement->handle, statement->dialect,
|
365
|
-
statement->parameters, statement->type, &affected);
|
366
|
-
if(type == isc_info_sql_stmt_insert ||
|
367
|
-
type == isc_info_sql_stmt_update ||
|
368
|
-
type == isc_info_sql_stmt_delete) {
|
369
|
-
result = INT2NUM(affected);
|
370
|
-
}
|
426
|
+
closeStatement(self);
|
371
427
|
}
|
372
|
-
|
373
|
-
return(result);
|
428
|
+
return (result);
|
374
429
|
}
|
375
430
|
|
376
|
-
|
431
|
+
/**
|
432
|
+
* Resolve (rollback) transaction in rescue block
|
433
|
+
*
|
434
|
+
* @param transaction A reference to the transaction object
|
435
|
+
*
|
436
|
+
* @param error A reference to the exception object
|
437
|
+
*
|
438
|
+
* @return Qnil
|
439
|
+
*
|
440
|
+
*/
|
441
|
+
VALUE rescueLocalTransaction(VALUE transaction, VALUE error) {
|
442
|
+
rb_funcall(transaction, rb_intern("rollback"), 0);
|
443
|
+
rb_exc_raise(error);
|
444
|
+
return(Qnil);
|
445
|
+
}
|
377
446
|
|
378
447
|
/**
|
379
|
-
*
|
448
|
+
* Close statement in rescue block
|
380
449
|
*
|
381
|
-
* @param
|
450
|
+
* @param statement A reference to the statement object
|
382
451
|
*
|
383
|
-
* @
|
452
|
+
* @param error A reference to the exception object
|
453
|
+
*
|
454
|
+
* @return Qnil
|
384
455
|
*
|
385
456
|
*/
|
386
|
-
VALUE
|
387
|
-
|
457
|
+
VALUE rescueStatement(VALUE statement, VALUE error) {
|
458
|
+
rb_funcall(statement, rb_intern("close"), 0);
|
459
|
+
rb_exc_raise(error);
|
460
|
+
return(Qnil);
|
461
|
+
}
|
388
462
|
|
389
|
-
|
390
|
-
|
391
|
-
|
463
|
+
/**
|
464
|
+
* Execute a statement within a transaction context parsing arguments array
|
465
|
+
*
|
466
|
+
* @param args Array containing statement, transaction and parameter bindings objects
|
467
|
+
*
|
468
|
+
* @return One of a count of the number of rows affected by the SQL statement,
|
469
|
+
* a ResultSet object for a query or nil.
|
470
|
+
*/
|
471
|
+
VALUE execInTransactionFromArray(VALUE args) {
|
472
|
+
VALUE self = rb_ary_entry(args, 0);
|
473
|
+
VALUE transaction = rb_ary_entry(args, 1);
|
474
|
+
VALUE parameters = rb_ary_entry(args, 2);
|
392
475
|
|
393
|
-
|
394
|
-
|
395
|
-
}
|
476
|
+
return(execInTransaction(self, transaction, parameters));
|
477
|
+
}
|
396
478
|
|
397
|
-
|
398
|
-
|
399
|
-
|
479
|
+
/**
|
480
|
+
* Check if the statement is a select statement
|
481
|
+
*
|
482
|
+
* @param hStatement A pointer to the statement handle
|
483
|
+
*
|
484
|
+
* @return 1 if the statement is a select statement, 0 otherwise
|
485
|
+
*/
|
486
|
+
short isCursorStatement(StatementHandle *hStatement) {
|
487
|
+
switch(hStatement->type) {
|
488
|
+
case isc_info_sql_stmt_select:
|
489
|
+
case isc_info_sql_stmt_select_for_upd:
|
490
|
+
return 1;
|
491
|
+
default:
|
492
|
+
return 0;
|
400
493
|
}
|
401
|
-
|
402
|
-
return(self);
|
403
494
|
}
|
404
495
|
|
405
|
-
|
406
496
|
/**
|
407
|
-
*
|
497
|
+
* Execute a statement within a transaction context
|
408
498
|
*
|
409
|
-
* @param
|
410
|
-
*
|
411
|
-
* @param transaction
|
412
|
-
* to prepare the statement.
|
413
|
-
* @param sql A string containing the SQL statement to be executed.
|
414
|
-
* @param statement A pointer to a Firebird statement that will be prepared.
|
415
|
-
* @param dialect A short integer containing the SQL dialect to be used in
|
416
|
-
* preparing the statement.
|
417
|
-
* @param type A pointer to an integer that will be assigned the type
|
418
|
-
* of the SQL statement prepared.
|
419
|
-
* @param inputs A pointer to an integer that will be assigned a count of
|
420
|
-
* the parameters for the SQL statement.
|
421
|
-
* @param outputs A pointer to an integer that will be assigned a count of
|
422
|
-
* the output columns for the SQL statement.
|
499
|
+
* @param self A reference to the statement object
|
500
|
+
*
|
501
|
+
* @param transaction A reference to the transaction object
|
423
502
|
*
|
503
|
+
* @param parameters A reference to the parameter bindings object
|
504
|
+
*
|
505
|
+
* @return One of a count of the number of rows affected by the SQL statement,
|
506
|
+
* a ResultSet object for a query or nil.
|
424
507
|
*/
|
425
|
-
|
426
|
-
|
427
|
-
|
508
|
+
VALUE execInTransaction(VALUE self, VALUE transaction, VALUE parameters) {
|
509
|
+
VALUE result = Qnil;
|
510
|
+
long affected = 0;
|
511
|
+
StatementHandle *hStatement = NULL;
|
512
|
+
TransactionHandle *hTransaction = NULL;
|
513
|
+
XSQLDA *bindings = NULL;
|
428
514
|
ISC_STATUS status[ISC_STATUS_LENGTH];
|
429
|
-
|
430
|
-
char list[] = {isc_info_sql_stmt_type},
|
431
|
-
info[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
432
|
-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
515
|
+
ISC_STATUS execute_result;
|
433
516
|
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
517
|
+
prepareInTransaction(self, transaction);
|
518
|
+
Data_Get_Struct(self, StatementHandle, hStatement);
|
519
|
+
if(hStatement->inputs > 0) {
|
520
|
+
VALUE value = Qnil;
|
521
|
+
int size = 0;
|
438
522
|
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
}
|
444
|
-
da->version = SQLDA_VERSION1;
|
445
|
-
da->sqln = 1;
|
446
|
-
if(isc_dsql_prepare(status, transaction, statement, 0, sql, dialect,
|
447
|
-
da)) {
|
448
|
-
free(da);
|
449
|
-
rb_fireruby_raise(status, "Error preparing a SQL statement.");
|
450
|
-
}
|
451
|
-
*outputs = da->sqld;
|
523
|
+
if(parameters == Qnil) {
|
524
|
+
rb_fireruby_raise(NULL,
|
525
|
+
"Empty parameter list specified for statement.");
|
526
|
+
}
|
452
527
|
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
free(da);
|
528
|
+
value = rb_funcall(parameters, rb_intern("size"), 0);
|
529
|
+
size = TYPE(value) == T_FIXNUM ? FIX2INT(value) : NUM2INT(value);
|
530
|
+
if(size < hStatement->inputs) {
|
531
|
+
rb_fireruby_raise(NULL,
|
532
|
+
"Insufficient parameters specified for statement.");
|
533
|
+
}
|
460
534
|
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
535
|
+
/* Allocate the XSQLDA */
|
536
|
+
bindings = allocateInXSQLDA(hStatement->inputs, &hStatement->handle, hStatement->dialect);
|
537
|
+
prepareDataArea(bindings);
|
538
|
+
setParameters(bindings, parameters, transaction, getStatementConnection(self));
|
465
539
|
}
|
466
|
-
*type = isc_vax_integer(&info[3], isc_vax_integer(&info[1], 2));
|
467
|
-
}
|
468
540
|
|
541
|
+
/* Execute the statement. */
|
542
|
+
Data_Get_Struct(transaction, TransactionHandle, hTransaction);
|
469
543
|
|
470
|
-
|
471
|
-
|
472
|
-
*
|
473
|
-
* @param transaction A pointer to the Firebird transaction handle to be used in
|
474
|
-
* executing the statement.
|
475
|
-
* @param statement A pointer to the Firebird statement handle to be used in
|
476
|
-
* executing the statement.
|
477
|
-
* @param dialect Database dialect used in the statement
|
478
|
-
*
|
479
|
-
* @param parameters A pointer to the XSQLDA block that contains the input
|
480
|
-
* parameters for the SQL statement.
|
481
|
-
* @param type A integer containing the type details relating to the
|
482
|
-
* statement being executed.
|
483
|
-
* @param affected A pointer to a long integer that will be assigned a count
|
484
|
-
* of rows affected by inserts, updates or deletes.
|
485
|
-
* @param output A pointer to the XSQLDA block that will hold the output
|
486
|
-
* data generated by the execution.
|
487
|
-
*/
|
488
|
-
void execute_2(isc_tr_handle *transaction, isc_stmt_handle *statement,
|
489
|
-
short dialect, XSQLDA *parameters, int type, long *affected, XSQLDA *output) {
|
490
|
-
ISC_STATUS status[ISC_STATUS_LENGTH];
|
491
|
-
ISC_STATUS execute_result;
|
492
|
-
|
493
|
-
if(output) {
|
494
|
-
execute_result = isc_dsql_execute2(status, transaction, statement, dialect, parameters, output);
|
544
|
+
if (isCursorStatement(hStatement)) {
|
545
|
+
execute_result = isc_dsql_execute(status, &hTransaction->handle, &hStatement->handle, hStatement->dialect, bindings);
|
495
546
|
} else {
|
496
|
-
execute_result =
|
547
|
+
execute_result = isc_dsql_execute2(status, &hTransaction->handle, &hStatement->handle, hStatement->dialect, bindings, hStatement->output);
|
548
|
+
}
|
549
|
+
if(bindings) {
|
550
|
+
releaseDataArea(bindings);
|
497
551
|
}
|
498
552
|
if(execute_result) {
|
499
553
|
rb_fireruby_raise(status, "Error executing SQL statement.");
|
500
554
|
}
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
int info = 0,
|
506
|
-
done = 0;
|
507
|
-
char items[] = {isc_info_sql_records},
|
508
|
-
buffer[40],
|
509
|
-
*position = buffer + 3;
|
510
|
-
|
511
|
-
switch(type) {
|
512
|
-
case isc_info_sql_stmt_update:
|
513
|
-
info = isc_info_req_update_count;
|
514
|
-
break;
|
515
|
-
|
516
|
-
case isc_info_sql_stmt_delete:
|
517
|
-
info = isc_info_req_delete_count;
|
518
|
-
break;
|
519
|
-
|
520
|
-
case isc_info_sql_stmt_insert:
|
521
|
-
info = isc_info_req_insert_count;
|
522
|
-
break;
|
555
|
+
if (hStatement->output) {
|
556
|
+
result = rb_result_set_new(self, transaction);
|
557
|
+
if(rb_block_given_p()) {
|
558
|
+
result = yieldResultsRows(result);
|
523
559
|
}
|
560
|
+
} else {
|
561
|
+
result = INT2NUM(fb_query_affected(hStatement));
|
562
|
+
}
|
524
563
|
|
525
|
-
|
526
|
-
|
527
|
-
rb_fireruby_raise(status, "Error retrieving affected row count.");
|
528
|
-
}
|
564
|
+
return(result);
|
565
|
+
}
|
529
566
|
|
530
|
-
|
531
|
-
|
532
|
-
|
567
|
+
/**
|
568
|
+
* This method provides the exec method for the Statement class.
|
569
|
+
*
|
570
|
+
* @param self A reference to the Statement object to call the method on.
|
571
|
+
*
|
572
|
+
* @param argc Parameters count
|
573
|
+
*
|
574
|
+
* @param argv Parameters array
|
575
|
+
*
|
576
|
+
* @return One of a count of the number of rows affected by the SQL statement,
|
577
|
+
* a ResultSet object for a query or nil.
|
578
|
+
*
|
579
|
+
*/
|
580
|
+
VALUE execStatement(int argc, VALUE *argv, VALUE self) {
|
581
|
+
VALUE transaction, parameters = Qnil;
|
533
582
|
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
position += temp[0];
|
583
|
+
rb_scan_args(argc, argv, "02", ¶meters, &transaction);
|
584
|
+
return execAndManageTransaction(self, parameters, transaction);
|
585
|
+
}
|
538
586
|
|
539
|
-
|
540
|
-
|
541
|
-
|
587
|
+
/**
|
588
|
+
* This method provides the exec_and_close method for the Statement class.
|
589
|
+
*
|
590
|
+
* @param self A reference to the Statement object to call the method on.
|
591
|
+
*
|
592
|
+
* @param argc Parameters count
|
593
|
+
*
|
594
|
+
* @param argv Parameters array
|
595
|
+
*
|
596
|
+
* @return One of a count of the number of rows affected by the SQL statement,
|
597
|
+
* a ResultSet object for a query or nil.
|
598
|
+
*
|
599
|
+
*/
|
600
|
+
VALUE execAndCloseStatement(int argc, VALUE *argv, VALUE self) {
|
601
|
+
VALUE parameters, transaction = Qnil;
|
602
|
+
|
603
|
+
rb_scan_args(argc, argv, "02", ¶meters, &transaction);
|
604
|
+
return execAndManageStatement(self, parameters, transaction);
|
605
|
+
}
|
606
|
+
|
607
|
+
/**
|
608
|
+
* Clean up statement handle - release allocated resources
|
609
|
+
*
|
610
|
+
* @param statement A pointer to the statement handle
|
611
|
+
*
|
612
|
+
* @param raise_errors If this parameter is 0 - no exceptions are raised from this function,
|
613
|
+
* otherwise an exception is raised whenever a problem occurs while releasing resources.
|
614
|
+
*
|
615
|
+
*/
|
616
|
+
void cleanUpStatement(StatementHandle *statement, int raise_errors) {
|
617
|
+
if(statement->handle) {
|
618
|
+
ISC_STATUS status[ISC_STATUS_LENGTH];
|
619
|
+
if(isc_dsql_free_statement(status, &statement->handle, DSQL_drop)) {
|
620
|
+
if(raise_errors) {
|
621
|
+
rb_fireruby_raise(status, "Error closing statement.");
|
542
622
|
}
|
543
623
|
}
|
624
|
+
if(statement->output != NULL) {
|
625
|
+
releaseDataArea(statement->output);
|
626
|
+
statement->output = NULL;
|
627
|
+
}
|
628
|
+
statement->handle = 0;
|
544
629
|
}
|
545
630
|
}
|
546
631
|
|
632
|
+
/**
|
633
|
+
* This function provides the close method for the Statement class.
|
634
|
+
*
|
635
|
+
* @param self A reference to the Statement object to call the method on.
|
636
|
+
*
|
637
|
+
* @return A reference to the newly closed Statement object.
|
638
|
+
*
|
639
|
+
*/
|
640
|
+
VALUE closeStatement(VALUE self) {
|
641
|
+
StatementHandle *statement = NULL;
|
642
|
+
Data_Get_Struct(self, StatementHandle, statement);
|
643
|
+
cleanUpStatement(statement, 1);
|
644
|
+
return(self);
|
645
|
+
}
|
646
|
+
|
647
|
+
/**
|
648
|
+
* This function provides the prepared? method for the Statement class.
|
649
|
+
*
|
650
|
+
* @param self A reference to the Statement object to call the method on.
|
651
|
+
*
|
652
|
+
* @return Qtrue if the statement is prepared, Qfalse otherwise.
|
653
|
+
*
|
654
|
+
*/
|
655
|
+
VALUE getStatementPrepared(VALUE self) {
|
656
|
+
VALUE result = Qfalse;
|
657
|
+
StatementHandle *statement = NULL;
|
658
|
+
Data_Get_Struct(self, StatementHandle, statement);
|
659
|
+
|
660
|
+
if(statement->handle) {
|
661
|
+
result = Qtrue;
|
662
|
+
}
|
663
|
+
|
664
|
+
return(result);
|
665
|
+
}
|
547
666
|
|
548
667
|
/**
|
549
|
-
* This function
|
550
|
-
*
|
551
|
-
* @param
|
552
|
-
*
|
553
|
-
* @param
|
554
|
-
*
|
555
|
-
* @param
|
556
|
-
*
|
557
|
-
* @
|
558
|
-
*
|
559
|
-
* @param type A integer containing the type details relating to the
|
560
|
-
* statement being executed.
|
561
|
-
* @param affected A pointer to a long integer that will be assigned a count
|
562
|
-
* of rows affected by inserts, updates or deletes.
|
668
|
+
* This function provides the prepare method for the Statement class.
|
669
|
+
*
|
670
|
+
* @param self A reference to the Statement object to call the method on.
|
671
|
+
*
|
672
|
+
* @param argc Parameters count
|
673
|
+
*
|
674
|
+
* @param argv Parameters array
|
675
|
+
*
|
676
|
+
* @return A reference to the statement object
|
677
|
+
*
|
563
678
|
*/
|
564
|
-
|
565
|
-
|
566
|
-
|
679
|
+
static VALUE prepareStatement(int argc, VALUE *argv, VALUE self) {
|
680
|
+
VALUE transaction = Qnil;
|
681
|
+
rb_scan_args(argc, argv, "01", &transaction);
|
682
|
+
if(Qnil == transaction) {
|
683
|
+
getPreparedHandle(self);
|
684
|
+
} else {
|
685
|
+
prepareInTransaction(self, transaction);
|
686
|
+
}
|
687
|
+
return (self);
|
567
688
|
}
|
568
689
|
|
569
690
|
/**
|
@@ -571,114 +692,74 @@ void execute(isc_tr_handle *transaction, isc_stmt_handle *statement,
|
|
571
692
|
*
|
572
693
|
* @param connection A reference to a Connection object that will be used by
|
573
694
|
* the Statement.
|
574
|
-
* @param transaction A reference to a Transaction object that will be used
|
575
|
-
* by the Statement.
|
576
695
|
* @param sql A reference to a String object containing the text of
|
577
696
|
* of a SQL statement for the Statement.
|
578
|
-
* @param dialect A reference to an integer object that contains the SQL
|
579
|
-
* dialect setting for the Statement.
|
580
697
|
*
|
581
698
|
* @return A reference to the newly created Statement object.
|
582
699
|
*
|
583
700
|
*/
|
584
|
-
VALUE rb_statement_new(VALUE connection, VALUE
|
585
|
-
VALUE dialect) {
|
701
|
+
VALUE rb_statement_new(VALUE connection, VALUE sql) {
|
586
702
|
VALUE statement = allocateStatement(cStatement);
|
587
703
|
|
588
|
-
initializeStatement(statement, connection,
|
704
|
+
initializeStatement(statement, connection, sql);
|
589
705
|
|
590
706
|
return(statement);
|
591
707
|
}
|
592
708
|
|
593
|
-
|
594
709
|
/**
|
595
|
-
*
|
596
|
-
* without parameters.
|
597
|
-
*
|
598
|
-
* @param statement A reference to the statement object to be executed.
|
710
|
+
* Execute statement parsing arguments array
|
599
711
|
*
|
600
|
-
* @
|
712
|
+
* @param args Array containing statement, parameters and transaction objects
|
601
713
|
*
|
714
|
+
* @return One of a count of the number of rows affected by the SQL statement,
|
715
|
+
* a ResultSet object for a query or nil.
|
602
716
|
*/
|
603
|
-
VALUE
|
604
|
-
|
605
|
-
|
606
|
-
|
717
|
+
VALUE execStatementFromArray(VALUE args) {
|
718
|
+
VALUE self = rb_ary_entry(args, 0);
|
719
|
+
VALUE params = rb_ary_entry(args, 1);
|
720
|
+
VALUE transaction = rb_ary_entry(args, 2);
|
607
721
|
|
608
|
-
|
609
|
-
* This function provides a programmatic way of executing a Statement object
|
610
|
-
* with parameters.
|
611
|
-
*
|
612
|
-
* @param statement A reference to the statement object to be executed.
|
613
|
-
* @param parameters A reference to an array of parameters to be used in the
|
614
|
-
* execution of the statement.
|
615
|
-
*
|
616
|
-
* @return A reference to the results of executing the statement.
|
617
|
-
*
|
618
|
-
*/
|
619
|
-
VALUE rb_execute_statement_for(VALUE statement, VALUE parameters) {
|
620
|
-
return(executeStatementFor(statement, parameters));
|
722
|
+
return execAndManageTransaction(self, params, transaction);
|
621
723
|
}
|
622
724
|
|
623
|
-
|
624
725
|
/**
|
625
|
-
* This function provides a programmatic way of executing a SQL
|
726
|
+
* This function provides a programmatic way of executing a parametrized SQL
|
626
727
|
* within transaction
|
627
728
|
*
|
628
729
|
* @param connection A reference to the connection object.
|
629
|
-
* @param transaction A reference to the transaction object.
|
630
730
|
* @param sql SQL text.
|
731
|
+
* @param params Array containing parameter values for the statement.
|
732
|
+
* @param transaction A reference to the transaction object.
|
631
733
|
*
|
632
734
|
* @return A reference to the results of executing the statement.
|
633
735
|
*
|
634
736
|
*/
|
635
|
-
VALUE rb_execute_sql(VALUE connection, VALUE
|
636
|
-
|
637
|
-
statement = rb_statement_new(connection, transaction, sql, INT2FIX(3));
|
638
|
-
|
639
|
-
results = rb_execute_statement(statement);
|
640
|
-
if(results != Qnil && rb_obj_is_kind_of(results, rb_cInteger) == Qfalse) {
|
641
|
-
if(rb_block_given_p()) {
|
642
|
-
VALUE row = rb_funcall(results, rb_intern("fetch"), 0),
|
643
|
-
last = Qnil;
|
644
|
-
|
645
|
-
while(row != Qnil) {
|
646
|
-
last = rb_yield(row);
|
647
|
-
row = rb_funcall(results, rb_intern("fetch"), 0);
|
648
|
-
}
|
649
|
-
rb_funcall(results, rb_intern("close"), 0);
|
650
|
-
results = last;
|
651
|
-
}
|
652
|
-
}
|
653
|
-
rb_statement_close(statement);
|
654
|
-
|
655
|
-
return(results);
|
656
|
-
}
|
657
|
-
|
658
|
-
/**
|
659
|
-
* This method retrieves the type information for a Statement object.
|
660
|
-
*
|
661
|
-
* @param statement A reference to a Statement object.
|
662
|
-
*
|
663
|
-
* @return A reference to an integer containing the statement type details.
|
664
|
-
*
|
665
|
-
*/
|
666
|
-
VALUE rb_get_statement_type(VALUE statement) {
|
667
|
-
return(getStatementType(statement));
|
737
|
+
VALUE rb_execute_sql(VALUE connection, VALUE sql, VALUE params, VALUE transaction) {
|
738
|
+
return execAndManageStatement(rb_statement_new(connection, sql), params, transaction);
|
668
739
|
}
|
669
740
|
|
670
|
-
|
671
741
|
/**
|
672
|
-
* This function
|
742
|
+
* This function guarantess that the returned statement handle is prepared
|
673
743
|
*
|
674
|
-
* @param
|
744
|
+
* @param self A reference to the Statement object to call the method on.
|
675
745
|
*
|
676
746
|
*/
|
677
|
-
|
678
|
-
|
747
|
+
StatementHandle* getPreparedHandle(VALUE self) {
|
748
|
+
StatementHandle *hStatement;
|
749
|
+
Data_Get_Struct(self, StatementHandle, hStatement);
|
750
|
+
if(0 == hStatement->handle) {
|
751
|
+
VALUE transaction = rb_transaction_new(getStatementConnection(self));
|
752
|
+
VALUE args = rb_ary_new();
|
753
|
+
|
754
|
+
rb_ary_push(args, self);
|
755
|
+
rb_ary_push(args, transaction);
|
756
|
+
|
757
|
+
rb_rescue(prepareFromArray, args, rescueLocalTransaction, transaction);
|
758
|
+
rb_funcall(transaction, rb_intern("commit"), 0);
|
759
|
+
}
|
760
|
+
return (hStatement);
|
679
761
|
}
|
680
762
|
|
681
|
-
|
682
763
|
/**
|
683
764
|
* This function integrates with the Ruby garbage collector to release the
|
684
765
|
* resources associated with a Statement object that is being collected.
|
@@ -689,24 +770,11 @@ void rb_statement_close(VALUE statement) {
|
|
689
770
|
*/
|
690
771
|
void statementFree(void *handle) {
|
691
772
|
if(handle != NULL) {
|
692
|
-
|
693
|
-
|
694
|
-
if(statement->handle != 0) {
|
695
|
-
ISC_STATUS status[ISC_STATUS_LENGTH];
|
696
|
-
|
697
|
-
isc_dsql_free_statement(status, &statement->handle, DSQL_drop);
|
698
|
-
}
|
699
|
-
|
700
|
-
if(statement->parameters) {
|
701
|
-
releaseDataArea(statement->parameters);
|
702
|
-
}
|
703
|
-
free(statement);
|
773
|
+
cleanUpStatement((StatementHandle *)handle, 0);
|
774
|
+
free(handle);
|
704
775
|
}
|
705
776
|
}
|
706
777
|
|
707
|
-
|
708
|
-
|
709
|
-
|
710
778
|
/**
|
711
779
|
* This function initializes the Statement class within the Ruby environment.
|
712
780
|
* The class is established under the module specified to the function.
|
@@ -717,17 +785,18 @@ void statementFree(void *handle) {
|
|
717
785
|
void Init_Statement(VALUE module) {
|
718
786
|
cStatement = rb_define_class_under(module, "Statement", rb_cObject);
|
719
787
|
rb_define_alloc_func(cStatement, allocateStatement);
|
720
|
-
rb_define_method(cStatement, "initialize", initializeStatement,
|
788
|
+
rb_define_method(cStatement, "initialize", initializeStatement, 2);
|
721
789
|
rb_define_method(cStatement, "initialize_copy", forbidObjectCopy, 1);
|
722
790
|
rb_define_method(cStatement, "sql", getStatementSQL, 0);
|
723
791
|
rb_define_method(cStatement, "connection", getStatementConnection, 0);
|
724
|
-
rb_define_method(cStatement, "transaction", getStatementTransaction, 0);
|
725
792
|
rb_define_method(cStatement, "dialect", getStatementDialect, 0);
|
726
793
|
rb_define_method(cStatement, "type", getStatementType, 0);
|
727
|
-
rb_define_method(cStatement, "
|
728
|
-
rb_define_method(cStatement, "
|
794
|
+
rb_define_method(cStatement, "exec", execStatement, -1);
|
795
|
+
rb_define_method(cStatement, "exec_and_close", execAndCloseStatement, -1);
|
729
796
|
rb_define_method(cStatement, "close", closeStatement, 0);
|
730
797
|
rb_define_method(cStatement, "parameter_count", getStatementParameterCount, 0);
|
798
|
+
rb_define_method(cStatement, "prepare", prepareStatement, -1);
|
799
|
+
rb_define_method(cStatement, "prepared?", getStatementPrepared, 0);
|
731
800
|
|
732
801
|
rb_define_const(cStatement, "SELECT_STATEMENT",
|
733
802
|
INT2FIX(isc_info_sql_stmt_select));
|