rubyfb 0.5.2-x86-linux

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.
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
+ }