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/Connection.c ADDED
@@ -0,0 +1,863 @@
1
+ /*------------------------------------------------------------------------------
2
+ * Connection.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 "Connection.h"
28
+ #include "Database.h"
29
+ #include "ResultSet.h"
30
+ #include "Statement.h"
31
+ #include "Transaction.h"
32
+ #include "Common.h"
33
+
34
+ /* Function prototypes. */
35
+ static VALUE allocateConnection(VALUE);
36
+ static VALUE initializeConnection(int, VALUE *, VALUE);
37
+ static VALUE isConnectionOpen(VALUE);
38
+ static VALUE isConnectionClosed(VALUE);
39
+ static VALUE closeConnection(VALUE);
40
+ static VALUE getConnectionDatabase(VALUE);
41
+ static VALUE startConnectionTransaction(VALUE);
42
+ static VALUE connectionToString(VALUE);
43
+ static VALUE executeOnConnection(VALUE, VALUE, VALUE);
44
+ static VALUE executeOnConnectionImmediate(VALUE, VALUE);
45
+ static VALUE getConnectionUser(VALUE);
46
+ VALUE startTransactionBlock(VALUE);
47
+ VALUE startTransactionRescue(VALUE, VALUE);
48
+ VALUE executeBlock(VALUE);
49
+ VALUE executeRescue(VALUE, VALUE);
50
+ VALUE executeImmediateBlock(VALUE);
51
+ VALUE executeImmediateRescue(VALUE, VALUE);
52
+ char *createDPB(VALUE, VALUE, VALUE, short *);
53
+
54
+ /* Globals. */
55
+ VALUE cConnection;
56
+
57
+
58
+ /**
59
+ * This function provides the allocation functionality for the Connection
60
+ * class.
61
+ *
62
+ * @param klass A reference to the Connection Class object.
63
+ *
64
+ * @return A reference to the newly created instance.
65
+ *
66
+ */
67
+ static VALUE allocateConnection(VALUE klass)
68
+ {
69
+ VALUE instance = Qnil;
70
+ ConnectionHandle *connection = ALLOC(ConnectionHandle);
71
+
72
+ if(connection != NULL)
73
+ {
74
+ /* Wrap the structure in a class. */
75
+ connection->handle = 0;
76
+ instance = Data_Wrap_Struct(klass, NULL, connectionFree, connection);
77
+ }
78
+ else
79
+ {
80
+ rb_raise(rb_eNoMemError,
81
+ "Memory allocation failure creating a connection.");
82
+ }
83
+
84
+ return(instance);
85
+ }
86
+
87
+
88
+ /**
89
+ * This function provides the initialize method for the Connection class.
90
+ *
91
+ * @param argc A count of the total number of arguments passed to the
92
+ * function.
93
+ * @param argv A pointer to an array of VALUEs that contain the arguments
94
+ * to the function.
95
+ * @param self A reference to the object being initialized.
96
+ *
97
+ * @return A reference to the initialized object.
98
+ *
99
+ */
100
+ static VALUE initializeConnection(int argc, VALUE *argv, VALUE self)
101
+ {
102
+ ConnectionHandle *connection = NULL;
103
+ ISC_STATUS status[20];
104
+ short length = 0;
105
+ char *file = NULL,
106
+ *dpb = NULL;
107
+ VALUE user = Qnil,
108
+ password = Qnil,
109
+ options = Qnil;
110
+
111
+ if(argc < 1)
112
+ {
113
+ rb_raise(rb_eArgError, "Wrong number of arguments (%d for %d).", argc, 1);
114
+ }
115
+
116
+ if(TYPE(argv[0]) != T_DATA ||
117
+ RDATA(argv[0])->dfree != (RUBY_DATA_FUNC)databaseFree)
118
+ {
119
+ rb_fireruby_raise(NULL, "Invalid database specified for connection.");
120
+ }
121
+ file = STR2CSTR(rb_iv_get(argv[0], "@file"));
122
+ Data_Get_Struct(self, ConnectionHandle, connection);
123
+
124
+ /* Extract parameters. */
125
+ if(argc > 1)
126
+ {
127
+ user = argv[1];
128
+ }
129
+ if(argc > 2)
130
+ {
131
+ password = argv[2];
132
+ }
133
+ if(argc > 3)
134
+ {
135
+ options = argv[3];
136
+ }
137
+
138
+ /* Open the connection connection. */
139
+ dpb = createDPB(user, password, options, &length);
140
+ if(isc_attach_database(status, strlen(file), file, &connection->handle,
141
+ length, dpb) != 0)
142
+ {
143
+ /* Generate an error. */
144
+ free(dpb);
145
+ rb_fireruby_raise(status, "Error opening database connection.");
146
+ }
147
+ free(dpb);
148
+
149
+ /* Store connection attributes. */
150
+ rb_iv_set(self, "@database", argv[0]);
151
+ rb_iv_set(self, "@user", user);
152
+ rb_iv_set(self, "@transactions", rb_ary_new());
153
+
154
+ return(self);
155
+ }
156
+
157
+
158
+ /**
159
+ * This function provides the open? method for the Connection class.
160
+ *
161
+ * @param self A reference to the object that the call is being made on.
162
+ *
163
+ * @return Qtrue if the connection is open, Qfalse if it is closed.
164
+ *
165
+ */
166
+ static VALUE isConnectionOpen(VALUE self)
167
+ {
168
+ VALUE result = Qfalse;
169
+ ConnectionHandle *connection = NULL;
170
+
171
+ Data_Get_Struct(self, ConnectionHandle, connection);
172
+ if(connection->handle != 0)
173
+ {
174
+ result = Qtrue;
175
+ }
176
+
177
+ return(result);
178
+ }
179
+
180
+
181
+ /**
182
+ * This function provides the closed? method for the Connection class.
183
+ *
184
+ * @param self A reference to the object that the call is being made on.
185
+ *
186
+ * @return Qtrue if the connection is closed, Qfalse if it is open.
187
+ *
188
+ */
189
+ static VALUE isConnectionClosed(VALUE self)
190
+ {
191
+ return(isConnectionOpen(self) == Qtrue ? Qfalse : Qtrue);
192
+ }
193
+
194
+
195
+ /**
196
+ * This method provides the close method for the Connection class.
197
+ *
198
+ * @param self A reference to the object that the call is being made on.
199
+ *
200
+ * @return A reference to the closed Connection on success, nil otherwise or
201
+ * if the method is called on a closed Connection.
202
+ *
203
+ */
204
+ static VALUE closeConnection(VALUE self)
205
+ {
206
+ VALUE result = Qnil;
207
+ ConnectionHandle *connection = NULL;
208
+
209
+ Data_Get_Struct(self, ConnectionHandle, connection);
210
+ if(connection->handle != 0)
211
+ {
212
+ VALUE transactions = rb_iv_get(self, "@transactions"),
213
+ transaction = Qnil;
214
+ ISC_STATUS status[20];
215
+
216
+ /* Roll back an outstanding transactions. */
217
+ while((transaction = rb_ary_pop(transactions)) != Qnil)
218
+ {
219
+ VALUE active = rb_funcall(transaction, rb_intern("active?"), 0);
220
+
221
+ if(active == Qtrue)
222
+ {
223
+ rb_funcall(transaction, rb_intern("rollback"), 0);
224
+ }
225
+ }
226
+
227
+ /* Detach from the database. */
228
+ if(isc_detach_database(status, &connection->handle) == 0)
229
+ {
230
+ connection->handle = 0;
231
+ result = self;
232
+ }
233
+ else
234
+ {
235
+ /* Generate an error. */
236
+ rb_fireruby_raise(status, "Error closing connection.");
237
+ }
238
+ }
239
+
240
+ return(result);
241
+ }
242
+
243
+
244
+ /**
245
+ * This function retrieves the connection associated with a Connection object.
246
+ *
247
+ * @param self A reference to the object that the call is being made on.
248
+ *
249
+ * @return A reference to the Connection connection.
250
+ *
251
+ */
252
+ static VALUE getConnectionDatabase(VALUE self)
253
+ {
254
+ return(rb_iv_get(self, "@database"));
255
+ }
256
+
257
+
258
+ /**
259
+ * This function provides the start_transaction method for the Database class.
260
+ *
261
+ * @param self A reference to the Database object to start the transaction
262
+ * on.
263
+ *
264
+ * @return A reference to a Transaction object or nil if a problem occurs.
265
+ *
266
+ */
267
+ static VALUE startConnectionTransaction(VALUE self)
268
+ {
269
+ VALUE result = rb_transaction_new(self);
270
+
271
+ if(rb_block_given_p())
272
+ {
273
+ result = rb_rescue(startTransactionBlock, result,
274
+ startTransactionRescue, result);
275
+ }
276
+
277
+ return(result);
278
+ }
279
+
280
+
281
+ /**
282
+ * This method provides the to_s method for the Connection class.
283
+ *
284
+ * @param self A reference to the Connection object that the method will be
285
+ * called on.
286
+ *
287
+ * @return A reference to a String object describing the connection.
288
+ *
289
+ */
290
+ static VALUE connectionToString(VALUE self)
291
+ {
292
+ VALUE result = rb_str_new2("(CLOSED)");
293
+ ConnectionHandle *connection = NULL;
294
+
295
+ Data_Get_Struct(self, ConnectionHandle, connection);
296
+ if(connection->handle != 0)
297
+ {
298
+ VALUE database = rb_iv_get(self, "@database"),
299
+ user = rb_iv_get(self, "@user"),
300
+ file = rb_iv_get(database, "@file");
301
+ char text[256];
302
+
303
+ sprintf(text, "%s@%s (OPEN)", STR2CSTR(user), STR2CSTR(file));
304
+ result = rb_str_new2(text);
305
+ }
306
+
307
+ return(result);
308
+ }
309
+
310
+
311
+ /**
312
+ * This function provides the execute method for the Connection class.
313
+ *
314
+ * @param self A reference to the connection object to perform the
315
+ * execution through.
316
+ * @param sql A reference to the SQL statement to be executed.
317
+ * @param transaction A reference to the transction that the statement will
318
+ * be executed under.
319
+ *
320
+ * @return Either a ResultSet object for a query statement or nil for a
321
+ * non-query statement.
322
+ *
323
+ */
324
+ static VALUE executeOnConnection(VALUE self, VALUE sql, VALUE transaction)
325
+ {
326
+ VALUE results = Qnil,
327
+ statement = rb_statement_new(self, transaction, sql, INT2FIX(3));
328
+
329
+ results = rb_execute_statement(statement);
330
+ if(results != Qnil && rb_obj_is_kind_of(results, rb_cInteger) == Qfalse)
331
+ {
332
+ if(rb_block_given_p())
333
+ {
334
+ VALUE row = rb_funcall(results, rb_intern("fetch"), 0),
335
+ last = Qnil;
336
+
337
+ while(row != Qnil)
338
+ {
339
+ last = rb_yield(row);
340
+ row = rb_funcall(results, rb_intern("fetch"), 0);
341
+ }
342
+ rb_funcall(results, rb_intern("close"), 0);
343
+ results = last;
344
+ }
345
+ }
346
+ rb_statement_close(statement);
347
+
348
+ return(results);
349
+ }
350
+
351
+
352
+ /**
353
+ * This function provides the execute_immediate method for the Connection class.
354
+ *
355
+ * @param self A reference to the connection object to perform the execution
356
+ * through.
357
+ * @param sql A reference to the SQL statement to be executed.
358
+ *
359
+ * @return Always returns nil.
360
+ *
361
+ */
362
+ static VALUE executeOnConnectionImmediate(VALUE self, VALUE sql)
363
+ {
364
+ VALUE transaction = rb_transaction_new(self),
365
+ set = Qnil,
366
+ results = Qnil,
367
+ array = rb_ary_new(),
368
+ dialect = INT2FIX(3),
369
+ statement = rb_statement_new(self, transaction, sql, dialect);
370
+
371
+ rb_ary_push(array, self);
372
+ rb_ary_push(array, transaction);
373
+ rb_ary_push(array, sql);
374
+ rb_ary_push(array, statement);
375
+
376
+ set = rb_rescue(executeBlock, array, executeRescue, array);
377
+ if(set != Qnil)
378
+ {
379
+ if(TYPE(set) == T_DATA &&
380
+ RDATA(set)->dfree == (RUBY_DATA_FUNC)resultSetFree)
381
+ {
382
+ rb_assign_transaction(set, transaction);
383
+ if(rb_block_given_p())
384
+ {
385
+ results = rb_rescue(executeImmediateBlock, set,
386
+ executeImmediateRescue, set);
387
+ }
388
+ else
389
+ {
390
+ results = set;
391
+ }
392
+ }
393
+ else
394
+ {
395
+ rb_funcall(transaction, rb_intern("commit"), 0);
396
+ results = set;
397
+ }
398
+ }
399
+ else
400
+ {
401
+ rb_funcall(transaction, rb_intern("commit"), 0);
402
+ }
403
+
404
+ return(results);
405
+ }
406
+
407
+
408
+ /**
409
+ * This function provides the user accessor method for the Connection object.
410
+ *
411
+ * @param self A reference to the Connection object to fetch theuser from.
412
+ *
413
+ * @return A reference to the user name used to establish the connection.
414
+ *
415
+ */
416
+ static VALUE getConnectionUser(VALUE self)
417
+ {
418
+ return(rb_iv_get(self, "@user"));
419
+ }
420
+
421
+
422
+ /**
423
+ * This function provides the block handling capabilities for the
424
+ * start_transaction method.
425
+ *
426
+ * @param transaction The Transaction object that was created for the block.
427
+ *
428
+ * @return A reference to the return value provided by the block.
429
+ *
430
+ */
431
+ VALUE startTransactionBlock(VALUE transaction)
432
+ {
433
+ VALUE result = rb_yield(transaction);
434
+
435
+ rb_funcall(transaction, rb_intern("commit"), 0);
436
+
437
+ return(result);
438
+ }
439
+
440
+
441
+ /**
442
+ * This function provides the rescue handling capabilities for the
443
+ * start_transaction block handling functionality.
444
+ *
445
+ * @param transaction A reference to the Transaction object that was created
446
+ * @param error A reference to details relating to the exception raised.
447
+ * for the block.
448
+ *
449
+ * @return Would be nil but always throws an exception.
450
+ *
451
+ */
452
+ VALUE startTransactionRescue(VALUE transaction, VALUE error)
453
+ {
454
+ rb_funcall(transaction, rb_intern("rollback"), 0);
455
+ rb_exc_raise(error);
456
+ return(Qnil);
457
+ }
458
+
459
+
460
+ /**
461
+ * This function is used to wrap the call to the executeOnConnection() function
462
+ * made by the executeOnConnectionImmediate() function to help insure that the
463
+ * transaction is rolled back in case of an error.
464
+ *
465
+ * @param array An array of the parameters for the function to use.
466
+ *
467
+ * @return The ResultSet object generated by execution or nil if it wasn't a
468
+ * query.
469
+ *
470
+ */
471
+ VALUE executeBlock(VALUE array)
472
+ {
473
+ VALUE result = Qnil,
474
+ connection = rb_ary_entry(array, 0),
475
+ transaction = rb_ary_entry(array, 1),
476
+ sql = rb_ary_entry(array, 2),
477
+ statement = rb_ary_entry(array, 3);
478
+
479
+ result = rb_execute_statement(statement);
480
+ rb_statement_close(statement);
481
+
482
+ return(result);
483
+ }
484
+
485
+
486
+ /**
487
+ * This function provides clean up for the execution of a block associated
488
+ * with the execute method.
489
+ *
490
+ * @param array An array of the parameters for the function to use.
491
+ * @param error A reference to details relating to the exception raised.
492
+ *
493
+ * @return Would always returns nil except that it always raises an exception.
494
+ *
495
+ */
496
+ VALUE executeRescue(VALUE array, VALUE error)
497
+ {
498
+ VALUE transaction = rb_ary_entry(array, 1),
499
+ statement = rb_ary_entry(array, 3);
500
+
501
+ rb_funcall(transaction, rb_intern("rollback"), 0);
502
+ rb_statement_close(statement);
503
+ rb_exc_raise(error);
504
+ return(Qnil);
505
+ }
506
+
507
+
508
+ /**
509
+ * This function is executed to process a block passed to the execute_immedate
510
+ * method.
511
+ *
512
+ * @param set A reference to the ResultSet to be processed by the block.
513
+ *
514
+ * @return A reference to the return value generated by the block.
515
+ *
516
+ */
517
+ VALUE executeImmediateBlock(VALUE set)
518
+ {
519
+ VALUE result = Qnil,
520
+ row = rb_funcall(set, rb_intern("fetch"), 0);
521
+
522
+ while(row != Qnil)
523
+ {
524
+ result = rb_yield(row);
525
+ row = rb_funcall(set, rb_intern("fetch"), 0);
526
+ }
527
+ rb_funcall(set, rb_intern("close"), 0);
528
+
529
+ return(result);
530
+ }
531
+
532
+
533
+ /**
534
+ * This function provides clean up for the execution of a block associated
535
+ * with the execute_immediate method.
536
+ *
537
+ * @param set A reference to the ResultSet object for the block.
538
+ * @param error A reference to details relating to the exception raised.
539
+ *
540
+ * @return Would always returns nil except that it always raises an exception.
541
+ *
542
+ */
543
+ VALUE executeImmediateRescue(VALUE set, VALUE error)
544
+ {
545
+ rb_funcall(set, rb_intern("close"), 0);
546
+ rb_exc_raise(error);
547
+ return(Qnil);
548
+ }
549
+
550
+
551
+ /**
552
+ * This method creates a database parameter buffer to be used in creating a
553
+ * database connection.
554
+ *
555
+ * @param user A reference to a string containing the user name to be used
556
+ * in making the connection.
557
+ * @param password A reference to a string containing the password to be used
558
+ * in making the connection.
559
+ * @param options A hash of the options to be used in making the connection
560
+ * to the database.
561
+ * @param length A pointer to a short integer that will be set to the
562
+ * length of the buffer.
563
+ *
564
+ * @return A pointer to an array of characters containing the database
565
+ * parameter buffer.
566
+ *
567
+ */
568
+ char *createDPB(VALUE user, VALUE password, VALUE options, short *length)
569
+ {
570
+ char *dpb = NULL;
571
+ VALUE keys;
572
+ VALUE entry;
573
+ int i;
574
+ short type;
575
+
576
+ /* Determine the dpb length and allocate it. */
577
+ *length = 1;
578
+ if(user != Qnil)
579
+ {
580
+ *length += strlen(StringValuePtr(user)) + 2;
581
+ }
582
+ if(password != Qnil)
583
+ {
584
+ *length += strlen(StringValuePtr(password)) + 2;
585
+ }
586
+ if(options != Qnil)
587
+ {
588
+ keys = rb_funcall(options, rb_intern("keys"), 0);
589
+
590
+ for(i = 0; i < RARRAY_LEN(keys); i++)
591
+ {
592
+ type = FIX2INT(rb_ary_entry(keys, i));
593
+
594
+ switch (type)
595
+ {
596
+ case isc_dpb_sql_role_name:
597
+ case isc_dpb_lc_messages:
598
+ case isc_dpb_lc_ctype:
599
+ case isc_dpb_reserved:
600
+ {
601
+ entry = rb_hash_aref(options, INT2FIX(type));
602
+ *length += strlen(StringValuePtr(entry)) + 2;
603
+ break;
604
+ }
605
+ default:
606
+ {
607
+ *length += 3;
608
+ }
609
+ }
610
+ }
611
+ }
612
+ dpb = ALLOC_N(char, *length);
613
+
614
+ /* Populate the buffer. */
615
+ if(dpb != NULL)
616
+ {
617
+ char *ptr = NULL;
618
+ int size = 0;
619
+
620
+ /* Fill out the DPB. */
621
+ memset(dpb, 0, *length);
622
+ dpb[0] = isc_dpb_version1;
623
+ ptr = &dpb[1];
624
+
625
+ if(user != Qnil)
626
+ {
627
+ char *username = StringValuePtr(user);
628
+
629
+ size = strlen(username);
630
+ *ptr++ = isc_dpb_user_name;
631
+ *ptr++ = (char)size;
632
+ memcpy(ptr, username, size);
633
+ ptr = ptr + size;
634
+ }
635
+
636
+ if(password != Qnil)
637
+ {
638
+ char *userpwd = StringValuePtr(password);
639
+
640
+ size = strlen(userpwd);
641
+ *ptr++ = isc_dpb_password;
642
+ *ptr++ = (char)size;
643
+ memcpy(ptr, userpwd, size);
644
+ ptr = ptr + size;
645
+ }
646
+
647
+ if(options != Qnil)
648
+ {
649
+ for(i = 0; i < RARRAY_LEN(keys); i++)
650
+ {
651
+ type = FIX2INT(rb_ary_entry(keys, i));
652
+ entry = rb_hash_aref(options, INT2FIX(type));
653
+
654
+ switch (type)
655
+ {
656
+ case isc_dpb_sql_role_name:
657
+ case isc_dpb_lc_messages:
658
+ case isc_dpb_lc_ctype:
659
+ case isc_dpb_reserved:
660
+ {
661
+ char *text = StringValuePtr(entry);
662
+
663
+ size = strlen(text);
664
+ *ptr++ = type;
665
+ *ptr++ = (char)size;
666
+ memcpy(ptr, text, size);
667
+ ptr = ptr + size;
668
+ break;
669
+ }
670
+ default:
671
+ {
672
+ short value;
673
+ switch (TYPE(entry))
674
+ {
675
+ case T_FIXNUM : value = FIX2INT(entry);
676
+ case T_NIL : value = 0;
677
+ case T_FALSE : value = 0;
678
+ case T_TRUE : value = 1;
679
+ case T_UNDEF : value = 0;
680
+ case T_FLOAT : value = NUM2INT(entry);
681
+ case T_BIGNUM : value = NUM2INT(entry);
682
+ default : value = 0;
683
+ }
684
+
685
+ *ptr++ = type;
686
+ *ptr++ = (char)1;
687
+ *ptr++ = value;
688
+ }
689
+ }
690
+ }
691
+ }
692
+ }
693
+ else
694
+ {
695
+ /* Generate an error. */
696
+ rb_raise(rb_eNoMemError,
697
+ "Memory allocation failure creating database DPB.");
698
+ }
699
+
700
+ return(dpb);
701
+ }
702
+
703
+
704
+ /**
705
+ * This function allows integration with the Ruby garbage collector to insure
706
+ * that the resources associated with a Connection object are released.
707
+ *
708
+ * @param connection A pointer to the ConnectionHandle structure associated
709
+ * with a Connection object.
710
+ *
711
+ */
712
+ void connectionFree(void *connection)
713
+ {
714
+ if(connection != NULL)
715
+ {
716
+ ConnectionHandle *handle = (ConnectionHandle *)connection;
717
+
718
+ if(handle->handle != 0)
719
+ {
720
+ ISC_STATUS status[20];
721
+
722
+ isc_detach_database(status, &handle->handle);
723
+ }
724
+ free(handle);
725
+ }
726
+ }
727
+
728
+
729
+ /**
730
+ * This function provides a programatic way of creating a new Connection
731
+ * object.
732
+ *
733
+ * @param database A reference to the database that the connection will relate
734
+ * to.
735
+ * @param user A reference to the database user name to be used in making
736
+ * the connection.
737
+ * @param password A reference to the database password to be used in making
738
+ * the connection.
739
+ * @param options A hash of the options to be used in creating the connection
740
+ * object.
741
+ *
742
+ * @return A reference to the newly created Connection object.
743
+ *
744
+ */
745
+ VALUE rb_connection_new(VALUE database, VALUE user, VALUE password, VALUE options)
746
+ {
747
+ VALUE connection = allocateConnection(cConnection),
748
+ parameters[4];
749
+
750
+ parameters[0] = database;
751
+ parameters[1] = user;
752
+ parameters[2] = password;
753
+ parameters[3] = options;
754
+
755
+ initializeConnection(4, parameters, connection);
756
+
757
+ return(connection);
758
+ }
759
+
760
+
761
+ /**
762
+ * This function is called to record the beginnings of a transactions against
763
+ * a related connection.
764
+ *
765
+ * @param transaction A reference to the newly created Transaction object.
766
+ * @param connection Either a reference to a Connection object or an Array
767
+ * of Connection objects that are included in the
768
+ * transaction.
769
+ *
770
+ */
771
+ void rb_tx_started(VALUE transaction, VALUE connection)
772
+ {
773
+ VALUE array = TYPE(connection) == T_ARRAY ? connection : rb_ary_new(),
774
+ number = Qnil;
775
+ long size = 0,
776
+ index;
777
+
778
+ if(TYPE(connection) != T_ARRAY)
779
+ {
780
+ rb_ary_push(array, connection);
781
+ }
782
+ number = rb_funcall(array, rb_intern("size"), 0);
783
+ size = TYPE(number) == T_FIXNUM ? FIX2INT(number) : NUM2INT(number);
784
+
785
+ for(index = 0; index < size; index++)
786
+ {
787
+ VALUE entry = rb_ary_entry(array, index),
788
+ list = rb_iv_get(entry, "@transactions");
789
+
790
+ rb_ary_push(list, transaction);
791
+ }
792
+ }
793
+
794
+
795
+ /**
796
+ * This function is invoked by a Transaction object whenever it is committed or
797
+ * rolled back. The connection can then discount the Transaction from its list
798
+ * of transaction to be cleaned up and close time.
799
+ *
800
+ * @param connection A reference to the Connection object or an array of
801
+ * Connection objects that is to be informed about the
802
+ * transaction.
803
+ * @param transaction A reference to the Transaction object that is to be
804
+ * released.
805
+ *
806
+ */
807
+ void rb_tx_released(VALUE connection, VALUE transaction)
808
+ {
809
+ VALUE array = TYPE(connection) == T_ARRAY ? connection : rb_ary_new(),
810
+ number = Qnil;
811
+ long size = 0,
812
+ index;
813
+
814
+ if(TYPE(connection) != T_ARRAY)
815
+ {
816
+ rb_ary_push(array, connection);
817
+ }
818
+ number = rb_funcall(array, rb_intern("size"), 0);
819
+ size = TYPE(number) == T_FIXNUM ? FIX2INT(number) : NUM2INT(number);
820
+
821
+ for(index = 0; index < size; index++)
822
+ {
823
+ VALUE entry = rb_ary_entry(array, index),
824
+ list = rb_iv_get(entry, "@transactions");
825
+
826
+ rb_ary_delete(list, transaction);
827
+ }
828
+ }
829
+
830
+
831
+ /**
832
+ * This function initializes the Connection class within the Ruby environment.
833
+ * The class is established under the module specified to the function.
834
+ *
835
+ * @param module A reference to the module to create the class within.
836
+ *
837
+ */
838
+ void Init_Connection(VALUE module)
839
+ {
840
+ cConnection = rb_define_class_under(module, "Connection", rb_cObject);
841
+ rb_define_alloc_func(cConnection, allocateConnection);
842
+ rb_define_method(cConnection, "initialize", initializeConnection, -1);
843
+ rb_define_method(cConnection, "initialize_copy", forbidObjectCopy, 1);
844
+ rb_define_method(cConnection, "user", getConnectionUser, 0);
845
+ rb_define_method(cConnection, "open?", isConnectionOpen, 0);
846
+ rb_define_method(cConnection, "closed?", isConnectionClosed, 0);
847
+ rb_define_method(cConnection, "close", closeConnection, 0);
848
+ rb_define_method(cConnection, "database", getConnectionDatabase, 0);
849
+ rb_define_method(cConnection, "start_transaction", startConnectionTransaction, 0);
850
+ rb_define_method(cConnection, "to_s", connectionToString, 0);
851
+ rb_define_method(cConnection, "execute", executeOnConnection, 2);
852
+ rb_define_method(cConnection, "execute_immediate", executeOnConnectionImmediate, 1);
853
+
854
+ rb_define_const(cConnection, "MARK_DATABASE_DAMAGED", INT2FIX(isc_dpb_damaged));
855
+ rb_define_const(cConnection, "WRITE_POLICY", INT2FIX(isc_dpb_force_write));
856
+ rb_define_const(cConnection, "CHARACTER_SET", INT2FIX(isc_dpb_lc_ctype));
857
+ rb_define_const(cConnection, "MESSAGE_FILE", INT2FIX(isc_dpb_lc_messages));
858
+ rb_define_const(cConnection, "NUMBER_OF_CACHE_BUFFERS", INT2FIX(isc_dpb_num_buffers));
859
+ rb_define_const(cConnection, "DBA_USER_NAME", INT2FIX(isc_dpb_sys_user_name));
860
+ rb_define_const(cConnection, "SQL_ROLE_NAME", INT2FIX(isc_dpb_sql_role_name));
861
+ rb_define_const(cConnection, "WRITE_ASYNCHRONOUS", INT2FIX(0));
862
+ rb_define_const(cConnection, "WRITE_SYNCHRONOUS", INT2FIX(1));
863
+ }