rubyfb 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. data/CHANGELOG +6 -0
  2. data/LICENSE +411 -0
  3. data/Manifest +73 -0
  4. data/README +460 -0
  5. data/Rakefile +20 -0
  6. data/examples/example01.rb +65 -0
  7. data/ext/AddUser.c +464 -0
  8. data/ext/AddUser.h +37 -0
  9. data/ext/Backup.c +783 -0
  10. data/ext/Backup.h +37 -0
  11. data/ext/Blob.c +421 -0
  12. data/ext/Blob.h +65 -0
  13. data/ext/Common.c +54 -0
  14. data/ext/Common.h +37 -0
  15. data/ext/Connection.c +863 -0
  16. data/ext/Connection.h +50 -0
  17. data/ext/DataArea.c +274 -0
  18. data/ext/DataArea.h +38 -0
  19. data/ext/Database.c +449 -0
  20. data/ext/Database.h +48 -0
  21. data/ext/FireRuby.c +240 -0
  22. data/ext/FireRuby.h +50 -0
  23. data/ext/FireRubyException.c +268 -0
  24. data/ext/FireRubyException.h +51 -0
  25. data/ext/Generator.c +689 -0
  26. data/ext/Generator.h +53 -0
  27. data/ext/RemoveUser.c +212 -0
  28. data/ext/RemoveUser.h +37 -0
  29. data/ext/Restore.c +855 -0
  30. data/ext/Restore.h +37 -0
  31. data/ext/ResultSet.c +809 -0
  32. data/ext/ResultSet.h +60 -0
  33. data/ext/Row.c +965 -0
  34. data/ext/Row.h +55 -0
  35. data/ext/ServiceManager.c +316 -0
  36. data/ext/ServiceManager.h +48 -0
  37. data/ext/Services.c +124 -0
  38. data/ext/Services.h +42 -0
  39. data/ext/Statement.c +785 -0
  40. data/ext/Statement.h +62 -0
  41. data/ext/Transaction.c +684 -0
  42. data/ext/Transaction.h +50 -0
  43. data/ext/TypeMap.c +1182 -0
  44. data/ext/TypeMap.h +51 -0
  45. data/ext/extconf.rb +28 -0
  46. data/ext/mkmf.bat +1 -0
  47. data/lib/SQLType.rb +224 -0
  48. data/lib/active_record/connection_adapters/rubyfb_adapter.rb +805 -0
  49. data/lib/mkdoc +1 -0
  50. data/lib/rubyfb.rb +2 -0
  51. data/lib/rubyfb_lib.so +0 -0
  52. data/lib/src.rb +1800 -0
  53. data/rubyfb.gemspec +31 -0
  54. data/test/AddRemoveUserTest.rb +56 -0
  55. data/test/BackupRestoreTest.rb +99 -0
  56. data/test/BlobTest.rb +57 -0
  57. data/test/CharacterSetTest.rb +63 -0
  58. data/test/ConnectionTest.rb +111 -0
  59. data/test/DDLTest.rb +54 -0
  60. data/test/DatabaseTest.rb +83 -0
  61. data/test/GeneratorTest.rb +50 -0
  62. data/test/KeyTest.rb +140 -0
  63. data/test/ResultSetTest.rb +162 -0
  64. data/test/RoleTest.rb +73 -0
  65. data/test/RowCountTest.rb +65 -0
  66. data/test/RowTest.rb +203 -0
  67. data/test/SQLTest.rb +182 -0
  68. data/test/SQLTypeTest.rb +101 -0
  69. data/test/ServiceManagerTest.rb +29 -0
  70. data/test/StatementTest.rb +135 -0
  71. data/test/TestSetup.rb +11 -0
  72. data/test/TransactionTest.rb +112 -0
  73. data/test/TypeTest.rb +92 -0
  74. data/test/UnitTest.rb +65 -0
  75. metadata +149 -0
data/ext/Statement.c ADDED
@@ -0,0 +1,785 @@
1
+ /*------------------------------------------------------------------------------
2
+ * Statement.c
3
+ *----------------------------------------------------------------------------*/
4
+ /**
5
+ * Copyright � Peter Wood, 2005
6
+ *
7
+ * The contents of this file are subject to the Mozilla Public License Version
8
+ * 1.1 (the "License"); you may not use this file except in compliance with the
9
+ * License. You may obtain a copy of the License at
10
+ *
11
+ * http://www.mozilla.org/MPL/
12
+ *
13
+ * Software distributed under the License is distributed on an "AS IS" basis,
14
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
15
+ * the specificlanguage governing rights and limitations under the License.
16
+ *
17
+ * The Original Code is the FireRuby extension for the Ruby language.
18
+ *
19
+ * The Initial Developer of the Original Code is Peter Wood. All Rights
20
+ * Reserved.
21
+ *
22
+ * @author Peter Wood
23
+ * @version 1.0
24
+ */
25
+
26
+ /* Includes. */
27
+ #include "Statement.h"
28
+ #include "Common.h"
29
+ #include "Connection.h"
30
+ #include "Transaction.h"
31
+ #include "DataArea.h"
32
+ #include "TypeMap.h"
33
+ #include "ResultSet.h"
34
+
35
+ /* Function prototypes. */
36
+ static VALUE allocateStatement(VALUE);
37
+ static VALUE initializeStatement(VALUE, VALUE, VALUE, VALUE, VALUE);
38
+ static VALUE getStatementSQL(VALUE);
39
+ static VALUE getStatementTransaction(VALUE);
40
+ static VALUE getStatementConnection(VALUE);
41
+ static VALUE getStatementDialect(VALUE);
42
+ static VALUE getStatementType(VALUE);
43
+ static VALUE getStatementParameterCount(VALUE);
44
+ static VALUE executeStatement(VALUE);
45
+ static VALUE executeStatementFor(VALUE, VALUE);
46
+ static VALUE closeStatement(VALUE);
47
+
48
+ /* Globals. */
49
+ VALUE cStatement;
50
+
51
+
52
+ /**
53
+ * This function integrates with the Ruby memory control system to provide for
54
+ * the allocation of Statement objects.
55
+ *
56
+ * @param klass A reference to the Statement Class object.
57
+ *
58
+ * @return A reference to the newly allocated Statement object.
59
+ *
60
+ */
61
+ VALUE allocateStatement(VALUE klass)
62
+ {
63
+ StatementHandle *statement = ALLOC(StatementHandle);
64
+
65
+ if(statement == NULL)
66
+ {
67
+ rb_raise(rb_eNoMemError,
68
+ "Memory allocation failure allocating a statement.");
69
+ }
70
+
71
+ statement->handle = 0;
72
+ statement->type = -1;
73
+ statement->inputs = 0;
74
+ statement->dialect = 0;
75
+ statement->parameters = NULL;
76
+
77
+ return(Data_Wrap_Struct(klass, NULL, statementFree, statement));
78
+ }
79
+
80
+
81
+ /**
82
+ * This function provides the initialize method for the Statement class.
83
+ *
84
+ * @param self A reference to the Statement object to be initialized.
85
+ * @param connection A reference to the Connection object that the statement
86
+ * will execute through.
87
+ * @param transaction A reference to the Transaction object that the statement
88
+ * will work under.
89
+ * @param sql A reference to a String object containing the text of
90
+ * the SQL statement to be executed.
91
+ * @param dialect A reference to an integer object specifying the dialect
92
+ * to be used in executing the statement. This should be a
93
+ * value of between 1 and 3.
94
+ *
95
+ * @return A reference to the newly initialized Statement object.
96
+ *
97
+ */
98
+ VALUE initializeStatement(VALUE self, VALUE connection, VALUE transaction,
99
+ VALUE sql, VALUE dialect)
100
+ {
101
+ StatementHandle *statement = NULL;
102
+ short setting = 0;
103
+ VALUE value = Qnil;
104
+
105
+ /* Validate the inputs. */
106
+ if(TYPE(connection) == T_DATA &&
107
+ RDATA(connection)->dfree == (RUBY_DATA_FUNC)connectionFree)
108
+ {
109
+ if(rb_funcall(connection, rb_intern("open?"), 0) == Qfalse)
110
+ {
111
+ rb_fireruby_raise(NULL, "Closed connection specified for statement.");
112
+ }
113
+ }
114
+ else
115
+ {
116
+ rb_fireruby_raise(NULL, "Invalid connection specified for statement.");
117
+ }
118
+
119
+ if(TYPE(transaction) == T_DATA &&
120
+ RDATA(transaction)->dfree == (RUBY_DATA_FUNC)transactionFree)
121
+ {
122
+ if(rb_funcall(transaction, rb_intern("active?"), 0) == Qfalse)
123
+ {
124
+ rb_fireruby_raise(NULL, "Inactive transaction specified for statement.");
125
+ }
126
+ }
127
+ else
128
+ {
129
+ rb_fireruby_raise(NULL, "Invalid transaction specified for statement.");
130
+ }
131
+
132
+ value = rb_funcall(dialect, rb_intern("to_i"), 0);
133
+ if(TYPE(value) == T_FIXNUM)
134
+ {
135
+ setting = FIX2INT(value);
136
+ if(setting < 1 || setting > 3)
137
+ {
138
+ rb_fireruby_raise(NULL,
139
+ "Invalid dialect value specified for statement. "\
140
+ "The dialect value must be between 1 and 3.");
141
+ }
142
+ }
143
+ else
144
+ {
145
+ rb_fireruby_raise(NULL,
146
+ "Invalid dialect value specified for statement. The "\
147
+ "dialect value must be between 1 and 3.");
148
+ }
149
+
150
+ Data_Get_Struct(self, StatementHandle, statement);
151
+ rb_iv_set(self, "@connection", connection);
152
+ rb_iv_set(self, "@transaction", transaction);
153
+ rb_iv_set(self, "@sql", rb_funcall(sql, rb_intern("to_s"), 0));
154
+ rb_iv_set(self, "@dialect", value);
155
+ statement->dialect = setting;
156
+
157
+ return(self);
158
+ }
159
+
160
+
161
+ /**
162
+ * This function provides the sql sttribute accessor method for the Statement
163
+ * class.
164
+ *
165
+ * @param self A reference to the Statement object to call the method on.
166
+ *
167
+ * @return A reference to a String containing the SQL statement.
168
+ *
169
+ */
170
+ VALUE getStatementSQL(VALUE self)
171
+ {
172
+ return(rb_iv_get(self, "@sql"));
173
+ }
174
+
175
+
176
+ /**
177
+ * This function provides the connection sttribute accessor method for the
178
+ * Statement class.
179
+ *
180
+ * @param self A reference to the Statement object to call the method on.
181
+ *
182
+ * @return A reference to a Connection object.
183
+ *
184
+ */
185
+ VALUE getStatementConnection(VALUE self)
186
+ {
187
+ return(rb_iv_get(self, "@connection"));
188
+ }
189
+
190
+
191
+ /**
192
+ * This function provides the transaction sttribute accessor method for the
193
+ * Statement class.
194
+ *
195
+ * @param self A reference to the Statement object to call the method on.
196
+ *
197
+ * @return A reference to a Transaction object.
198
+ *
199
+ */
200
+ VALUE getStatementTransaction(VALUE self)
201
+ {
202
+ return(rb_iv_get(self, "@transaction"));
203
+ }
204
+
205
+
206
+ /**
207
+ * This function provides the dialect sttribute accessor method for the
208
+ * Statement class.
209
+ *
210
+ * @param self A reference to the Statement object to call the method on.
211
+ *
212
+ * @return A reference to an integer containing the SQL dialect setting.
213
+ *
214
+ */
215
+ VALUE getStatementDialect(VALUE self)
216
+ {
217
+ return(rb_iv_get(self, "@dialect"));
218
+ }
219
+
220
+
221
+
222
+ /**
223
+ * This function provides the type attribute accessor method for the Statement
224
+ * class.
225
+ *
226
+ * @param self A reference to the Statement object to call the method on.
227
+ *
228
+ * @return A reference to an integer containing the SQL type details.
229
+ *
230
+ */
231
+ VALUE getStatementType(VALUE self)
232
+ {
233
+ StatementHandle *statement = NULL;
234
+ ConnectionHandle *connection = NULL;
235
+ TransactionHandle *transaction = NULL;
236
+ int outputs = 0;
237
+
238
+ Data_Get_Struct(self, StatementHandle, statement);
239
+ Data_Get_Struct(rb_iv_get(self, "@connection"), ConnectionHandle, connection);
240
+ Data_Get_Struct(rb_iv_get(self, "@transaction"), TransactionHandle, transaction);
241
+ if(statement->handle == 0)
242
+ {
243
+ prepare(&connection->handle, &transaction->handle,
244
+ STR2CSTR(rb_iv_get(self, "@sql")), &statement->handle,
245
+ statement->dialect, &statement->type, &statement->inputs,
246
+ &outputs);
247
+ }
248
+
249
+ return(INT2FIX(statement->type));
250
+ }
251
+
252
+
253
+ /**
254
+ * This function provides the parameter count sttribute accessor method for the
255
+ * Statement class.
256
+ *
257
+ * @param self A reference to the Statement object to call the method on.
258
+ *
259
+ * @return A reference to an integer containing the statement parameter count.
260
+ *
261
+ */
262
+ VALUE getStatementParameterCount(VALUE self)
263
+ {
264
+ StatementHandle *statement = NULL;
265
+
266
+ Data_Get_Struct(self, StatementHandle, statement);
267
+ if(statement->handle == 0)
268
+ {
269
+ getStatementType(self);
270
+ }
271
+
272
+ return(INT2NUM(statement->inputs));
273
+ }
274
+
275
+
276
+ /**
277
+ * This method provides the execute method for the Statement class.
278
+ *
279
+ * @param self A reference to the Statement object to call the method on.
280
+ *
281
+ * @return One of a count of the number of rows affected by the SQL statement,
282
+ * a ResultSet object for a query or nil.
283
+ *
284
+ */
285
+ VALUE executeStatement(VALUE self)
286
+ {
287
+ VALUE result;
288
+ int type = FIX2INT(getStatementType(self));
289
+ long affected = 0;
290
+ StatementHandle *statement = NULL;
291
+ TransactionHandle *transaction = NULL;
292
+
293
+ switch(type)
294
+ {
295
+ case isc_info_sql_stmt_select :
296
+ case isc_info_sql_stmt_select_for_upd :
297
+ case isc_info_sql_stmt_exec_procedure :
298
+ result = rb_result_set_new(rb_iv_get(self, "@connection"),
299
+ rb_iv_get(self, "@transaction"),
300
+ rb_iv_get(self, "@sql"),
301
+ rb_iv_get(self, "@dialect"),
302
+ rb_ary_new());
303
+ break;
304
+
305
+ case isc_info_sql_stmt_insert :
306
+ case isc_info_sql_stmt_update :
307
+ case isc_info_sql_stmt_delete :
308
+ Data_Get_Struct(self, StatementHandle, statement);
309
+ Data_Get_Struct(rb_iv_get(self, "@transaction"), TransactionHandle,
310
+ transaction);
311
+ execute(&transaction->handle, &statement->handle, statement->dialect,
312
+ NULL, statement->type, &affected);
313
+ result = INT2NUM(affected);
314
+ break;
315
+
316
+ default :
317
+ Data_Get_Struct(self, StatementHandle, statement);
318
+ Data_Get_Struct(rb_iv_get(self, "@transaction"), TransactionHandle,
319
+ transaction);
320
+ execute(&transaction->handle, &statement->handle, statement->dialect,
321
+ NULL, statement->type, &affected);
322
+ result = Qnil;
323
+ }
324
+
325
+ return(result);
326
+ }
327
+
328
+
329
+ /**
330
+ * This method provides the execute method for the Statement class.
331
+ *
332
+ * @param self A reference to the Statement object to call the method
333
+ * on.
334
+ * @param parameters An array containing the parameters to be used in
335
+ * executing the statement.
336
+ *
337
+ * @return One of a count of the number of rows affected by the SQL statement,
338
+ * a ResultSet object for a query or nil.
339
+ *
340
+ */
341
+ VALUE executeStatementFor(VALUE self, VALUE parameters)
342
+ {
343
+ VALUE result = Qnil;
344
+ int type = FIX2INT(getStatementType(self));
345
+ long affected = 0;
346
+ StatementHandle *statement = NULL;
347
+ TransactionHandle *transaction = NULL;
348
+
349
+ if(type == isc_info_sql_stmt_select ||
350
+ type == isc_info_sql_stmt_select_for_upd)
351
+ {
352
+ /* Execute the statement via a ResultSet object. */
353
+ result = rb_result_set_new(rb_iv_get(self, "@connection"),
354
+ rb_iv_get(self, "@transaction"),
355
+ rb_iv_get(self, "@sql"),
356
+ rb_iv_get(self, "@dialect"),
357
+ parameters);
358
+ }
359
+ else
360
+ {
361
+ /* Check that sufficient parameters have been specified. */
362
+ Data_Get_Struct(self, StatementHandle, statement);
363
+ if(statement->inputs > 0)
364
+ {
365
+ VALUE value = Qnil;
366
+ int size = 0;
367
+
368
+ if(parameters == Qnil)
369
+ {
370
+ rb_fireruby_raise(NULL,
371
+ "Empty parameter list specified for statement.");
372
+ }
373
+
374
+ value = rb_funcall(parameters, rb_intern("size"), 0);
375
+ size = TYPE(value) == T_FIXNUM ? FIX2INT(value) : NUM2INT(value);
376
+ if(size < statement->inputs)
377
+ {
378
+ rb_fireruby_raise(NULL,
379
+ "Insufficient parameters specified for statement.");
380
+ }
381
+
382
+ /* Allocate the XSQLDA and populate it. */
383
+ statement->parameters = allocateInXSQLDA(statement->inputs,
384
+ &statement->handle,
385
+ statement->dialect);
386
+ prepareDataArea(statement->parameters);
387
+ setParameters(statement->parameters, parameters, self);
388
+ }
389
+
390
+ /* Execute the statement. */
391
+ Data_Get_Struct(self, StatementHandle, statement);
392
+ Data_Get_Struct(rb_iv_get(self, "@transaction"), TransactionHandle,
393
+ transaction);
394
+ execute(&transaction->handle, &statement->handle, statement->dialect,
395
+ statement->parameters, statement->type, &affected);
396
+ if(type == isc_info_sql_stmt_insert ||
397
+ type == isc_info_sql_stmt_update ||
398
+ type == isc_info_sql_stmt_delete)
399
+ {
400
+ result = INT2NUM(affected);
401
+ }
402
+ }
403
+
404
+ return(result);
405
+ }
406
+
407
+
408
+
409
+ /**
410
+ * This function provides the close method for the Statement class.
411
+ *
412
+ * @param self A reference to the Statement object to call the method on.
413
+ *
414
+ * @return A reference to the newly closed Statement object.
415
+ *
416
+ */
417
+ VALUE closeStatement(VALUE self)
418
+ {
419
+ StatementHandle *statement = NULL;
420
+
421
+ Data_Get_Struct(self, StatementHandle, statement);
422
+ if(statement->handle != 0)
423
+ {
424
+ ISC_STATUS status[20];
425
+
426
+ if(isc_dsql_free_statement(status, &statement->handle, DSQL_drop))
427
+ {
428
+ rb_fireruby_raise(status, "Error closing statement.");
429
+ }
430
+
431
+ if(statement->parameters != NULL)
432
+ {
433
+ releaseDataArea(statement->parameters);
434
+ }
435
+ }
436
+
437
+ return(self);
438
+ }
439
+
440
+
441
+ /**
442
+ * This function prepares a Firebird SQL statement for execution.
443
+ *
444
+ * @param connection A pointer to the database connection that will be used
445
+ * to prepare the statement.
446
+ * @param transaction A pointer to the database transaction that will be used
447
+ * to prepare the statement.
448
+ * @param sql A string containing the SQL statement to be executed.
449
+ * @param statement A pointer to a Firebird statement that will be prepared.
450
+ * @param dialect A short integer containing the SQL dialect to be used in
451
+ * preparing the statement.
452
+ * @param type A pointer to an integer that will be assigned the type
453
+ * of the SQL statement prepared.
454
+ * @param inputs A pointer to an integer that will be assigned a count of
455
+ * the parameters for the SQL statement.
456
+ * @param outputs A pointer to an integer that will be assigned a count of
457
+ * the output columns for the SQL statement.
458
+ *
459
+ */
460
+ void prepare(isc_db_handle *connection, isc_tr_handle *transaction,
461
+ char *sql, isc_stmt_handle *statement, short dialect,
462
+ int *type, int *inputs, int *outputs)
463
+ {
464
+ ISC_STATUS status[20];
465
+ XSQLDA *da = NULL;
466
+ char list[] = {isc_info_sql_stmt_type},
467
+ info[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
468
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
469
+
470
+ /* Prepare the statement. */
471
+ if(isc_dsql_allocate_statement(status, connection, statement))
472
+ {
473
+ rb_fireruby_raise(status, "Error allocating a SQL statement.");
474
+ }
475
+
476
+ da = (XSQLDA *)ALLOC_N(char, XSQLDA_LENGTH(1));
477
+ if(da == NULL)
478
+ {
479
+ rb_raise(rb_eNoMemError,
480
+ "Memory allocation failure preparing a statement.");
481
+ }
482
+ da->version = SQLDA_VERSION1;
483
+ da->sqln = 1;
484
+ if(isc_dsql_prepare(status, transaction, statement, 0, sql, dialect,
485
+ da))
486
+ {
487
+ free(da);
488
+ rb_fireruby_raise(status, "Error preparing a SQL statement.");
489
+ }
490
+ *outputs = da->sqld;
491
+
492
+ /* Get the parameter count. */
493
+ if(isc_dsql_describe_bind(status, statement, dialect, da))
494
+ {
495
+ free(da);
496
+ rb_fireruby_raise(status, "Error determining statement parameters.");
497
+ }
498
+ *inputs = da->sqld;
499
+ free(da);
500
+
501
+ /* Get the statement type details. */
502
+ if(isc_dsql_sql_info(status, statement, 1, list, 20, info) ||
503
+ info[0] != isc_info_sql_stmt_type)
504
+ {
505
+ rb_fireruby_raise(status, "Error determining SQL statement type.");
506
+ }
507
+ *type = isc_vax_integer(&info[3], isc_vax_integer(&info[1], 2));
508
+ }
509
+
510
+
511
+ /**
512
+ * This function executes a previously prepare SQL statement.
513
+ *
514
+ * @param transaction A pointer to the Firebird transaction handle to be used in
515
+ * executing the statement.
516
+ * @param statement A pointer to the Firebird statement handle to be used in
517
+ * executing the statement.
518
+ * @param dialect Database dialect used in the statement
519
+ *
520
+ * @param parameters A pointer to the XSQLDA block that contains the input
521
+ * parameters for the SQL statement.
522
+ * @param type A integer containing the type details relating to the
523
+ * statement being executed.
524
+ * @param affected A pointer to a long integer that will be assigned a count
525
+ * of rows affected by inserts, updates or deletes.
526
+ * @param output A pointer to the XSQLDA block that will hold the output
527
+ * data generated by the execution.
528
+ */
529
+ void execute_2(isc_tr_handle *transaction, isc_stmt_handle *statement,
530
+ short dialect, XSQLDA *parameters, int type, long *affected, XSQLDA *output)
531
+ {
532
+ ISC_STATUS status[20];
533
+ ISC_STATUS execute_result;
534
+
535
+ if(output) {
536
+ execute_result = isc_dsql_execute2(status, transaction, statement, dialect, parameters, output);
537
+ } else {
538
+ execute_result = isc_dsql_execute(status, transaction, statement, dialect, parameters);
539
+ }
540
+ if(execute_result)
541
+ {
542
+ rb_fireruby_raise(status, "Error executing SQL statement.");
543
+ }
544
+
545
+ /* Check if a row count is needed. */
546
+ if(type == isc_info_sql_stmt_update || type == isc_info_sql_stmt_delete ||
547
+ type == isc_info_sql_stmt_insert)
548
+ {
549
+ int info = 0,
550
+ done = 0;
551
+ char items[] = {isc_info_sql_records},
552
+ buffer[40],
553
+ *position = buffer + 3;
554
+
555
+ switch(type)
556
+ {
557
+ case isc_info_sql_stmt_update :
558
+ info = isc_info_req_update_count;
559
+ break;
560
+
561
+ case isc_info_sql_stmt_delete :
562
+ info = isc_info_req_delete_count;
563
+ break;
564
+
565
+ case isc_info_sql_stmt_insert :
566
+ info = isc_info_req_insert_count;
567
+ break;
568
+ }
569
+
570
+ if(isc_dsql_sql_info(status, statement, sizeof(items), items,
571
+ sizeof(buffer), buffer))
572
+ {
573
+ rb_fireruby_raise(status, "Error retrieving affected row count.");
574
+ }
575
+
576
+ while(*position != isc_info_end && done == 0)
577
+ {
578
+ char current = *position++;
579
+ long temp[] = {0, 0};
580
+
581
+ temp[0] = isc_vax_integer(position, 2);
582
+ position += 2;
583
+ temp[1] = isc_vax_integer(position, temp[0]);
584
+ position += temp[0];
585
+
586
+ if(current == info)
587
+ {
588
+ *affected = temp[1];
589
+ done = 1;
590
+ }
591
+ }
592
+ }
593
+ }
594
+
595
+
596
+ /**
597
+ * This function executes a previously prepare SQL statement.
598
+ *
599
+ * @param transaction A pointer to the Firebird transaction handle to be used in
600
+ * executing the statement.
601
+ * @param statement A pointer to the Firebird statement handle to be used in
602
+ * executing the statement.
603
+ * @param dialect Database dialect used in the statement
604
+ *
605
+ * @param parameters A pointer to the XSQLDA block that contains the input
606
+ * parameters for the SQL statement.
607
+ * @param type A integer containing the type details relating to the
608
+ * statement being executed.
609
+ * @param affected A pointer to a long integer that will be assigned a count
610
+ * of rows affected by inserts, updates or deletes.
611
+ */
612
+ void execute(isc_tr_handle *transaction, isc_stmt_handle *statement,
613
+ short dialect, XSQLDA *parameters, int type, long *affected)
614
+ {
615
+ execute_2(transaction, statement, dialect, parameters, type, affected, NULL);
616
+ }
617
+
618
+ /**
619
+ * This function provides a programmatic means of creating a Statement object.
620
+ *
621
+ * @param connection A reference to a Connection object that will be used by
622
+ * the Statement.
623
+ * @param transaction A reference to a Transaction object that will be used
624
+ * by the Statement.
625
+ * @param sql A reference to a String object containing the text of
626
+ * of a SQL statement for the Statement.
627
+ * @param dialect A reference to an integer object that contains the SQL
628
+ * dialect setting for the Statement.
629
+ *
630
+ * @return A reference to the newly created Statement object.
631
+ *
632
+ */
633
+ VALUE rb_statement_new(VALUE connection, VALUE transaction, VALUE sql,
634
+ VALUE dialect)
635
+ {
636
+ VALUE statement = allocateStatement(cStatement);
637
+
638
+ initializeStatement(statement, connection, transaction, sql, dialect);
639
+
640
+ return(statement);
641
+ }
642
+
643
+
644
+ /**
645
+ * This function provides a programmatic way of executing a Statement object
646
+ * without parameters.
647
+ *
648
+ * @param statement A reference to the statement object to be executed.
649
+ *
650
+ * @return A reference to the results of executing the statement.
651
+ *
652
+ */
653
+ VALUE rb_execute_statement(VALUE statement)
654
+ {
655
+ return(executeStatement(statement));
656
+ }
657
+
658
+
659
+ /**
660
+ * This function provides a programmatic way of executing a Statement object
661
+ * with parameters.
662
+ *
663
+ * @param statement A reference to the statement object to be executed.
664
+ * @param parameters A reference to an array of parameters to be used in the
665
+ * execution of the statement.
666
+ *
667
+ * @return A reference to the results of executing the statement.
668
+ *
669
+ */
670
+ VALUE rb_execute_statement_for(VALUE statement, VALUE parameters)
671
+ {
672
+ return(executeStatementFor(statement, parameters));
673
+ }
674
+
675
+
676
+ /**
677
+ * This method retrieves the type information for a Statement object.
678
+ *
679
+ * @param statement A reference to a Statement object.
680
+ *
681
+ * @return A reference to an integer containing the statement type details.
682
+ *
683
+ */
684
+ VALUE rb_get_statement_type(VALUE statement)
685
+ {
686
+ return(getStatementType(statement));
687
+ }
688
+
689
+
690
+ /**
691
+ * This function provides a programmatic means of closing a Statement object.
692
+ *
693
+ * @param statement A reference to the Statement object to be closed.
694
+ *
695
+ */
696
+ void rb_statement_close(VALUE statement)
697
+ {
698
+ closeStatement(statement);
699
+ }
700
+
701
+
702
+ /**
703
+ * This function integrates with the Ruby garbage collector to release the
704
+ * resources associated with a Statement object that is being collected.
705
+ *
706
+ * @param handle A pointer to the StatementHandle structure for the Statement
707
+ * object being collected.
708
+ *
709
+ */
710
+ void statementFree(void *handle)
711
+ {
712
+ if(handle != NULL)
713
+ {
714
+ StatementHandle *statement = (StatementHandle *)handle;
715
+
716
+ if(statement->handle != 0)
717
+ {
718
+ ISC_STATUS status[20];
719
+
720
+ isc_dsql_free_statement(status, &statement->handle, DSQL_drop);
721
+ }
722
+
723
+ if(statement->parameters)
724
+ {
725
+ releaseDataArea(statement->parameters);
726
+ }
727
+ free(statement);
728
+ }
729
+ }
730
+
731
+
732
+
733
+
734
+ /**
735
+ * This function initializes the Statement class within the Ruby environment.
736
+ * The class is established under the module specified to the function.
737
+ *
738
+ * @param module A reference to the module to create the class within.
739
+ *
740
+ */
741
+ void Init_Statement(VALUE module)
742
+ {
743
+ cStatement = rb_define_class_under(module, "Statement", rb_cObject);
744
+ rb_define_alloc_func(cStatement, allocateStatement);
745
+ rb_define_method(cStatement, "initialize", initializeStatement, 4);
746
+ rb_define_method(cStatement, "initialize_copy", forbidObjectCopy, 1);
747
+ rb_define_method(cStatement, "sql", getStatementSQL, 0);
748
+ rb_define_method(cStatement, "connection", getStatementConnection, 0);
749
+ rb_define_method(cStatement, "transaction", getStatementTransaction, 0);
750
+ rb_define_method(cStatement, "dialect", getStatementDialect, 0);
751
+ rb_define_method(cStatement, "type", getStatementType, 0);
752
+ rb_define_method(cStatement, "execute", executeStatement, 0);
753
+ rb_define_method(cStatement, "execute_for", executeStatementFor, 1);
754
+ rb_define_method(cStatement, "close", closeStatement, 0);
755
+ rb_define_method(cStatement, "parameter_count", getStatementParameterCount, 0);
756
+
757
+ rb_define_const(cStatement, "SELECT_STATEMENT",
758
+ INT2FIX(isc_info_sql_stmt_select));
759
+ rb_define_const(cStatement, "INSERT_STATEMENT",
760
+ INT2FIX(isc_info_sql_stmt_insert));
761
+ rb_define_const(cStatement, "UPDATE_STATEMENT",
762
+ INT2FIX(isc_info_sql_stmt_update));
763
+ rb_define_const(cStatement, "DELETE_STATEMENT",
764
+ INT2FIX(isc_info_sql_stmt_delete));
765
+ rb_define_const(cStatement, "DDL_STATEMENT",
766
+ INT2FIX(isc_info_sql_stmt_ddl));
767
+ rb_define_const(cStatement, "GET_SEGMENT_STATEMENT",
768
+ INT2FIX(isc_info_sql_stmt_get_segment));
769
+ rb_define_const(cStatement, "PUT_SEGMENT_STATEMENT",
770
+ INT2FIX(isc_info_sql_stmt_put_segment));
771
+ rb_define_const(cStatement, "EXECUTE_PROCEDURE_STATEMENT",
772
+ INT2FIX(isc_info_sql_stmt_exec_procedure));
773
+ rb_define_const(cStatement, "START_TRANSACTION_STATEMENT",
774
+ INT2FIX(isc_info_sql_stmt_start_trans));
775
+ rb_define_const(cStatement, "COMMIT_STATEMENT",
776
+ INT2FIX(isc_info_sql_stmt_commit));
777
+ rb_define_const(cStatement, "ROLLBACK_STATEMENT",
778
+ INT2FIX(isc_info_sql_stmt_rollback));
779
+ rb_define_const(cStatement, "SELECT_FOR_UPDATE_STATEMENT",
780
+ INT2FIX(isc_info_sql_stmt_select_for_upd));
781
+ rb_define_const(cStatement, "SET_GENERATOR_STATEMENT",
782
+ INT2FIX(isc_info_sql_stmt_set_generator));
783
+ rb_define_const(cStatement, "SAVE_POINT_STATEMENT",
784
+ INT2FIX(isc_info_sql_stmt_savepoint));
785
+ }