nuodb 1.0.2 → 1.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -9,3 +9,4 @@ rdoc/
9
9
  pkg/
10
10
  tmp
11
11
  .idea
12
+ .DS_Store
@@ -1,10 +1,15 @@
1
1
  language: ruby
2
2
 
3
3
  rvm:
4
+ - 2.0.0
4
5
  - 1.9.3
5
6
 
6
7
  env:
7
- - NUODB_ROOT=/opt/nuodb
8
+ - NUODB_ROOT=/opt/nuodb NUODB_VERSION=1.2
9
+ - NUODB_ROOT=/opt/nuodb NUODB_VERSION=1.1.1
10
+ - NUODB_ROOT=/opt/nuodb NUODB_VERSION=1.1
11
+ - NUODB_ROOT=/opt/nuodb NUODB_VERSION=1.0.2
12
+ - NUODB_ROOT=/opt/nuodb NUODB_VERSION=1.0.1
8
13
 
9
14
  notifications:
10
15
  recipients:
@@ -13,19 +18,19 @@ notifications:
13
18
  - lbayas@nuodb.com
14
19
 
15
20
  before_install:
16
- - wget http://www.nuodb.com/latest/nuodb-1.0.2.linux.x64.deb --output-document=/var/tmp/nuodb.deb
21
+ - wget http://www.nuodb.com/latest/releases/nuodb-${NUODB_VERSION}.linux.x64.deb --output-document=/var/tmp/nuodb.deb
17
22
  - sudo dpkg -i /var/tmp/nuodb.deb
18
23
  - sleep 2
19
24
 
20
25
  before_script:
21
26
  - ${NUODB_ROOT}/bin/nuodb --chorus test --password bar --dba-user dba --dba-password baz --verbose debug --archive /var/tmp/nuodb --initialize --force &
22
- - sleep 2
27
+ - sleep 4
23
28
  - ${NUODB_ROOT}/bin/nuodb --chorus test --password bar --dba-user dba --dba-password baz &
24
- - sleep 2
29
+ - sleep 4
25
30
  - echo "create user cloud password 'user';" | ${NUODB_ROOT}/bin/nuosql test@localhost --user dba --password baz
26
31
 
27
32
  script:
28
- - NUODB_ROOT=/opt/nuodb bundle exec rake spec install
33
+ - NUODB_ROOT=/opt/nuodb bundle exec rake spec
29
34
 
30
35
  after_script:
31
- - sudo dpkg -r nuodb
36
+ - sudo dpkg -r nuodb
@@ -1,20 +1,20 @@
1
- = Contributing to the Ruby NuoDB Driver
1
+ # Contributing to the Ruby NuoDB Driver
2
2
 
3
- == BUILDING THE GEM
3
+ ## BUILDING THE GEM
4
4
 
5
5
  To compile and test run this command:
6
6
 
7
7
  rake clean build rdoc spec
8
8
 
9
- == INSTALLING THE GEM
9
+ ## INSTALLING THE GEM
10
10
 
11
- NUODB_ROOT=/Users/rbuck/tmp/nuodb gem install nuodb-1.0.2.gem
11
+ NUODB_ROOT=/Users/rbuck/tmp/nuodb gem install nuodb-1.1.gem
12
12
 
13
13
  Or from the source tree:
14
14
 
15
- NUODB_ROOT=/Users/rbuck/tmp/nuodb gem install pkg/nuodb-1.0.2.gem
15
+ NUODB_ROOT=/Users/rbuck/tmp/nuodb gem install pkg/nuodb-1.1.gem
16
16
 
17
- == TESTING THE GEM
17
+ ## TESTING THE GEM
18
18
 
19
19
  Start up a minimal chorus as follows:
20
20
 
@@ -32,33 +32,34 @@ Run the tests:
32
32
 
33
33
  rake spec
34
34
 
35
- == PUBLISHING THE GEM
35
+ ## PUBLISHING THE GEM
36
36
 
37
- === TAGGING
37
+ ### TAGGING
38
38
 
39
- Tag the product using tags per the SemVer specification; our tags have a v-prefix:
39
+ Tag the product using tags per the SemVer specification; our tags have a
40
+ v-prefix:
40
41
 
41
- git tag -a v1.0.2 -m "SemVer Version: v1.0.2"
42
+ git tag -a v1.1 -m "SemVer Version: v1.1"
42
43
 
43
44
  If you make a mistake, take it back quickly:
44
45
 
45
- git tag -d v1.0.2
46
- git push origin :refs/tags/v1.0.2
46
+ git tag -d v1.1
47
+ git push origin :refs/tags/v1.1
47
48
 
48
- ===PUBLISHING
49
+ ### PUBLISHING
49
50
 
50
51
  Here are the commands used to publish:
51
52
 
52
- gem push pkg/nuodb-1.0.2.gem
53
+ gem push pkg/nuodb-1.1.gem
53
54
 
54
- == INSPECTING THE GEM
55
+ ## INSPECTING THE GEM
55
56
 
56
- It is often useful to inspect the contents of a Gem before distribution.
57
- To do this you dump the contents of a gem thus:
57
+ It is often useful to inspect the contents of a Gem before distribution. To do
58
+ this you dump the contents of a gem thus:
58
59
 
59
- gem unpack pkg/nuodb-1.0.2.gem
60
+ gem unpack pkg/nuodb-1.1.gem
60
61
 
61
- == INSPECTING THE EXPORTED SYMBOLS
62
+ ## INSPECTING THE EXPORTED SYMBOLS
62
63
 
63
64
  To inspec the symbols on Linux:
64
65
 
data/Gemfile CHANGED
@@ -2,4 +2,4 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'rake'
5
+ gem 'rake', '~>10.1.0'
@@ -0,0 +1,56 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ nuodb (1.1)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ diff-lcs (1.1.3)
10
+ erubis (2.7.0)
11
+ haml (3.0.25)
12
+ hanna-nouveau (0.2.7)
13
+ haml (= 3.0.25)
14
+ rdoc (~> 3.1)
15
+ json (1.8.0)
16
+ multi_json (1.7.9)
17
+ optiflag (0.7)
18
+ rake (10.1.0)
19
+ rdoc (3.12.2)
20
+ json (~> 1.4)
21
+ rspec (2.11.0)
22
+ rspec-core (~> 2.11.0)
23
+ rspec-expectations (~> 2.11.0)
24
+ rspec-mocks (~> 2.11.0)
25
+ rspec-core (2.11.1)
26
+ rspec-expectations (2.11.3)
27
+ diff-lcs (~> 1.1.3)
28
+ rspec-mocks (2.11.3)
29
+ ruby-prof (0.13.0)
30
+ rubydoc (0.0.1)
31
+ optiflag (~> 0.7)
32
+ sdoc (0.3.20)
33
+ json (>= 1.1.3)
34
+ rdoc (~> 3.10)
35
+ simplecov (0.7.1)
36
+ multi_json (~> 1.0)
37
+ simplecov-html (~> 0.7.1)
38
+ simplecov-html (0.7.1)
39
+
40
+ PLATFORMS
41
+ ruby
42
+
43
+ DEPENDENCIES
44
+ erubis (~> 2.7.0)
45
+ hanna-nouveau
46
+ nuodb!
47
+ rake (~> 10.1.0)
48
+ rdoc
49
+ rspec (~> 2.11.0)
50
+ rspec-core (~> 2.11.0)
51
+ rspec-expectations (~> 2.11.0)
52
+ rspec-mocks (~> 2.11.0)
53
+ ruby-prof
54
+ rubydoc
55
+ sdoc
56
+ simplecov
@@ -1,3 +1,6 @@
1
+ === 1.1
2
+ - Refactored C++ code with metadata enhancements
3
+
1
4
  === 1.0.2
2
5
  - Fixed each iteration bug
3
6
 
@@ -0,0 +1,43 @@
1
+ # Ruby/NuoDB Interface [<img src="https://api.travis-ci.org/nuodb/ruby-nuodb.png?branch=master" alt="Build Status" />](http://travis-ci.org/nuodb/ruby-nuodb) [<img src="https://gemnasium.com/nuodb/ruby-nuodb.png?travis" alt="Dependency Status" />](https://gemnasium.com/nuodb/ruby-nuodb) [<img src="https://codeclimate.com/github/nuodb/ruby-nuodb.png" />](https://codeclimate.com/github/nuodb/ruby-nuodb)
2
+
3
+ This is the official Ruby Gem for [NuoDB](http://www.nuodb.com/). It wraps the
4
+ NuoDB C++ API, providing a natural API for Ruby.
5
+
6
+ To use NuoDB with Rails you will also want the [ActiveRecord NuoDB
7
+ Adapter](https://github.com/nuodb/ruby-activerecord-nuodb-adapter)
8
+
9
+ Note: At this time the Ruby/NuoDB Interface does not support Windows.
10
+
11
+ ## Getting Started
12
+
13
+ 1. If you haven't already, [Download and Install NuoDB](http://nuodb.com/download-nuodb/)
14
+
15
+ 2. Install the gem
16
+
17
+ gem install nuodb
18
+
19
+ 3. Use NuoDB in Ruby
20
+
21
+ require "nuodb"
22
+
23
+ conn = NuoDB::Connection.new(:database => 'test@localhost', :username => 'dba', :password => 'goalie', :schema => 'hockey')
24
+ stmt = conn.statement
25
+ stmt.execute("SELECT * FROM hockey")
26
+ stmt.results.each do |res|
27
+ puts res.inspect
28
+ end
29
+
30
+
31
+ ## More Information
32
+
33
+ * [Ruby/NuoDB Interface Rdoc](http://nuodb.github.io/ruby-nuodb/rdoc/)
34
+ * [NuoDB Community Forum](http://www.nuodb.com/community/forum.php)
35
+ * [NuoDB Online Documentation](http://www.nuodb.com/community/documentation.php)
36
+
37
+
38
+ ## Contributing
39
+
40
+ See [Contribution](CONTRIBUTION.md) for information about contributing to
41
+ the Ruby ActiveRecord NuoDB Adapter.
42
+
43
+ [![githalytics.com alpha](https://cruel-carlota.pagodabox.com/9acbb24d79760ffb071e5e653305e21e "githalytics.com")](http://githalytics.com/nuodb/ruby-nuodb)
data/Rakefile CHANGED
@@ -129,7 +129,7 @@ namespace :nuodb do
129
129
  case RUBY_PLATFORM
130
130
  when /linux/i
131
131
  unless File.exists? '/etc/redhat-release'
132
- puts %x(wget http://www.nuodb.com/latest/nuodb-1.0-GA.linux.x86_64.deb --output-document=/var/tmp/nuodb.deb)
132
+ puts %x(wget http://www.nuodb.com/latest/releases/nuodb-1.1.linux.x64.deb --output-document=/var/tmp/nuodb.deb)
133
133
  puts %x(sudo dpkg -i /var/tmp/nuodb.deb)
134
134
  end
135
135
  else
@@ -36,17 +36,21 @@
36
36
  #include <time.h>
37
37
  #include <stdio.h>
38
38
  #include <typeinfo>
39
+ #include <stdarg.h>
40
+
41
+ #define NANOS_PER_SECOND 1000000000
42
+ #define NANOS_PER_MICRO 1000
39
43
 
40
44
  #define HAVE_CXA_DEMANGLE
41
45
 
42
46
  #ifdef HAVE_CXA_DEMANGLE
43
47
  #include <cxxabi.h>
44
- const char * demangle(const char * name)
48
+ const char* demangle(const char* name)
45
49
  {
46
50
  char buf[1024];
47
51
  size_t size = 1024;
48
52
  int status;
49
- char * res = abi::__cxa_demangle (name,
53
+ char* res = abi::__cxa_demangle (name,
50
54
  buf, &size, &status);
51
55
  return res;
52
56
  }
@@ -121,19 +125,19 @@ static const bool ENABLE_CLOSE_HOOK = true;
121
125
 
122
126
  enum LogLevel
123
127
  {
124
- ERROR,
125
- WARN,
126
- INFO,
127
128
  TRACE,
128
129
  DEBUG,
130
+ INFO,
131
+ WARN,
132
+ ERROR,
129
133
  NONE
130
134
  };
131
135
 
132
- static LogLevel logLevel = NONE;
136
+ static LogLevel logLevel = ERROR;
133
137
 
134
- static char const * log_level_name(LogLevel level)
138
+ static char const* log_level_name(LogLevel level)
135
139
  {
136
- char const * level_name = NULL;
140
+ char const* level_name = NULL;
137
141
  switch(level)
138
142
  {
139
143
  case NONE:
@@ -158,7 +162,7 @@ static char const * log_level_name(LogLevel level)
158
162
  return level_name;
159
163
  }
160
164
 
161
- static void log(LogLevel level, char const * message)
165
+ static void log(LogLevel level, char const* message)
162
166
  {
163
167
  if (level >= logLevel)
164
168
  {
@@ -166,17 +170,17 @@ static void log(LogLevel level, char const * message)
166
170
  }
167
171
  }
168
172
 
169
- static void trace(char const * message)
173
+ static void trace(char const* message)
170
174
  {
171
175
  log(TRACE, message);
172
176
  }
173
177
 
174
- static void print_address(char const * context, void * address)
178
+ static void print_address(char const* context, void* address)
175
179
  {
176
180
  if (DEBUG >= logLevel)
177
181
  {
178
182
  unsigned char *p = (unsigned char *)&address;
179
- int i;
183
+ unsigned int i;
180
184
  printf("%s: ", context);
181
185
  for (i = 0; i < sizeof address; i++)
182
186
  {
@@ -187,137 +191,35 @@ static void print_address(char const * context, void * address)
187
191
  }
188
192
 
189
193
  // ----------------------------------------------------------------------------
190
- // NEXT GEN GC INTEGRATION SERVICES
191
-
192
- #ifdef ENABLE_NEXTGEN_GC_INTEGRATION
193
-
194
- /*
195
- * GC Notes:
196
- *
197
- * 1. gc_entities are placed in the Ruby object table and are freed via mark
198
- * and sweep.
199
- * 2. gc_entities may be freed in any order.
200
- * 3. gc_entities may be freed either before shutdown or during shutdown.
201
- * 4. gc_entities may no longer be accessed once freed by the garbage
202
- * collector; once gc_entities are freed they no longer appear in the
203
- * object table. As such, calls to Data_Get_Struct on previously garbage
204
- * collected entities will cause the Ruby VM to crash; viz. SIGABRT via
205
- * EXC_BAD_ACCESS.
206
- *
207
- * a. So a general observation of this is thusly: if e.g. with graphs of
208
- * child to parent relationships an orderly de-allocation is required,
209
- * as parents (gc_entities) may be freed prior to childrens (gc_entities)
210
- * it becomes imperative that the logic between freeing gc_entity objects
211
- * be kept completely and distinctly apart from the logic of the managed
212
- * entities themselves.
213
- */
214
-
215
- typedef void (*callback)(void *);
216
-
217
- /*
218
- * Application Rules:
219
- *
220
- * 1. Assign a callback for the increment and decrement refers counter so that
221
- * context specific logging and tracking may be implemented.
222
- * 2. Direct access to refers should never occur.
223
- * 3. The freed bit indicates that the resources associated to the data_handle
224
- * has been freed, and NOT that the os_entity struct has been freed.
225
- *
226
- * Logic:
227
- *
228
- * 1. The incr_func is called on a child when it is first created.
229
- * 2. The incr_func is called on a parent when its child is first created.
230
- * 3. When incr_func is called, ATOMIC_INC increments the refers field.
231
- * 4. When decr_func is called, ATOMIC_DEC decrements the refers field.
232
- * 5. When the refers field reaches zero (inside decr_func):
233
- * 5.1. ATOMIC-CAS the freed bit, if the prior freed bit is not set:
234
- * 5.1.1. ATOMIC-OR all parents freed bits and if the result does not have
235
- * the freed bit set:
236
- * 5.1.1.1. Call the free function, passing the os_entity itself as a parameter.
237
- * The free function releases any resources related to the data
238
- * handle itself and sets the handle to null.
239
- * 5.2. Call the decr_func on its parent (this may act recursively).
240
- * 5.3. Call xfree on the os_entity structure itself.
241
- * 6. When a user calls finish on an object:
242
- * 6.1. ATOMIC-CAS the freed bit, if the prior freed bit is not set
243
- * perform operations 5.1.1 through 5.1.1.1.
244
- *
245
- * Details:
246
- *
247
- * 1. Regarding 5a, above, we neither want to doubly release an object, nor
248
- * call free_function when a parent has already released all the resources.
249
- * This optionally is configurable, for cases when parents forcibly close
250
- * child resources, or for cases where they don't. This is a behavioral
251
- * configuration parameter to the resource manager. But the above documentation
252
- * is tailored for cases where parents automatically release child resources
253
- * when they themselves are closed.
254
- * 2. A race condition may occur between 5.1 and 5.2, above, where a parent
255
- * resource is released just after 5.1.1.1 and before 5.2; the result will
256
- * be a SEGV. This may prompt the use of a global lock for the reference
257
- * manager.
258
- *
259
- * Interface:
260
- *
261
- * 1. Structures as defined below.
262
- * 2. Function to release a reference:
263
- * void rc_decr_refs (void * handle, int * err_code)
264
- * 3. Function to acquire a reference:
265
- * void rc_incr_refs (void * handle, int * err_code)
266
- * 4. Function to wrap an entity:
267
- * void * rc_add_object (void * object, int * err_code)
268
- * 5. Function to get wrapped pointer:
269
- * void * rc_get_object (void * handle, int * err_code)
270
- *
271
- * Questions:
272
- *
273
- * 1. Do we go opaque so that the data type definition is malleable? We don't
274
- * want this any more type specific than it is.
275
- */
276
- struct os_entity
277
- {
278
- void * data_handle;
279
- unsigned int flags;
280
- rb_atomic_t refers;
281
-
282
- callback incr_func;
283
- callback decr_func;
284
- callback free_func;
285
-
286
- os_entity * parent;
287
- };
194
+ // H A N D L E S
195
+ //
196
+ //
288
197
 
289
198
  /*
290
- * Rules:
199
+ * Each nuodb client datatype that we need to expose to ruby will be done via a handle object. The handle contains
200
+ * two kinds of things, a pointer to a client instance and GC handling information. The GC information is there to
201
+ * deal with the fact that the nuodb client API requires that things be closed before they are deallocated and that
202
+ * the closures happen in a very specific order. Namely, that all result sets are closed before their creating
203
+ * statement can be closed. And that all statements are closed before their creating connection may be closed.
204
+ * Ruby's GC hooks allow us to hook into the MARK phase so that all objects may mark their parents to prevent that
205
+ * out-of-order condition. However, ruby guarantees no particular order when freeing objects determined to be
206
+ * garbage. Therefore the GC thread may invoke free on a statement before it's result set even though both are
207
+ * garbage and will eventually be freed in the same sweep. Therefore, each handle also has a numUsed reference
208
+ * count. On creation, a handle increments its parent's numUsed. On free, a handle decrements its parent's numUsed.
209
+ * A handle cannot be freed if its numUsed is greater than 0. Therefore, it is the responsibility of every child to
210
+ * check if it needs to clean up its parent.
291
211
  *
292
- * 1. When mark is called, traverse marks list till a null is reached, for
293
- * each value call rb_gc_mark.
294
- * 2. When the garbage collector frees an object, the decr_function is called
295
- * on the entity passing the entity as its parameter.
212
+ * When a handle has finally been deemed to be free-able, the cleanupFunc needs to be called to actually close out
213
+ * the handle's client instances.
296
214
  */
297
- struct gc_entity
298
- {
299
- os_entity * entity;
300
- VALUE ** mark_refs;
301
- };
302
-
303
- /*
304
- * A strict release strategy only permits free calls after the reference count
305
- * drops to zero. A lenient release strategy permits free calls at any time,
306
- * yet the entity itself is not freed until its reference count drops to zero.
307
- */
308
- typedef enum {strict, lenient} free_strategy;
309
-
310
- #endif /* ENABLE_NEXTGEN_GC_INTEGRATION */
311
-
312
- // ----------------------------------------------------------------------------
313
- // H A N D L E S
314
215
 
315
216
  struct nuodb_handle
316
217
  {
317
- RUBY_DATA_FUNC free_func;
318
- rb_atomic_t atomic;
319
- nuodb_handle * parent_handle;
320
- VALUE parent;
218
+ bool freePending; //GC wants to free us, but we still have some children outstanding
219
+ void (*cleanupFunc)(nuodb_handle*); //cleanup function
220
+
221
+ int numUsed; //number of surviving children to prevent premature free
222
+ nuodb_handle* parent;
321
223
  };
322
224
 
323
225
  struct nuodb_connection_handle : nuodb_handle
@@ -328,128 +230,59 @@ struct nuodb_connection_handle : nuodb_handle
328
230
  VALUE schema;
329
231
  VALUE timezone;
330
232
 
331
- NuoDB::Connection * pointer;
233
+ NuoDB::Connection* pointer;
332
234
  };
333
235
 
334
236
  struct nuodb_prepared_statement_handle : nuodb_handle
335
237
  {
336
- NuoDB::PreparedStatement * pointer;
238
+ NuoDB::PreparedStatement* pointer;
239
+
240
+ VALUE connection;
241
+ nuodb_connection_handle* connection_handle;
337
242
  };
338
243
 
339
244
  struct nuodb_statement_handle : nuodb_handle
340
245
  {
341
- NuoDB::Statement * pointer;
246
+ NuoDB::Statement* pointer;
247
+
248
+ VALUE connection;
249
+ nuodb_connection_handle* connection_handle;
342
250
  };
343
251
 
344
252
  struct nuodb_result_handle : nuodb_handle
345
253
  {
346
- NuoDB::ResultSet * pointer;
347
- NuoDB::Connection * connection;
254
+ NuoDB::ResultSet* pointer;
255
+ NuoDB::Connection* connection;
256
+
257
+ VALUE statement;
258
+ int columnCount;
259
+ NuoDB::SqlType* types;
260
+ NuoDB::ResultSetMetaData* resultMetaData;
261
+
262
+ nuodb_prepared_statement_handle* prepStmt;
263
+ nuodb_statement_handle* stmt;
348
264
  };
349
265
 
350
266
  template<typename handle_type>
351
- handle_type * cast_handle(VALUE value)
267
+ handle_type* cast_handle(VALUE value)
352
268
  {
353
269
  Check_Type(value, T_DATA);
354
270
  return static_cast<handle_type*>(DATA_PTR(value));
355
271
  }
356
272
 
357
273
  template<typename handle_type, typename return_type>
358
- return_type * cast_pointer_member(VALUE value)
274
+ return_type* cast_pointer_member(VALUE value)
359
275
  {
360
276
  Check_Type(value, T_DATA);
361
277
  return cast_handle<handle_type>(value)->pointer;
362
278
  }
363
279
 
364
- static void track_ref_count(char const * context, nuodb_handle * handle)
365
- {
366
- trace("track_ref_count");
367
-
368
- if (handle != 0)
369
- {
370
- int parent_count = -10;
371
- if (handle->parent_handle != 0)
372
- {
373
- parent_count = handle->parent_handle->atomic;
374
- }
375
- if (logLevel <= DEBUG)
376
- {
377
- nuodb_handle * parent = handle->parent_handle;
378
- unsigned char *p = (unsigned char *)&handle;
379
- unsigned char *q = (unsigned char *)&parent;
380
- int i;
381
- printf("[REFERENCE COUNT][%s] (%s @ ", context, demangle(typeid(*handle).name()));
382
- for (i = 0; i < sizeof handle; i++)
383
- {
384
- printf("%02x ", p[i]);
385
- }
386
- printf("): %d (%s @ ", handle->atomic, demangle(typeid(*parent).name()));
387
- for (i = 0; i < sizeof parent; i++)
388
- {
389
- printf("%02x ", q[i]);
390
- }
391
- printf("): %d", parent_count);
392
- putchar('\n');
393
- }
394
- }
395
- }
396
-
397
- void incr_reference_count(nuodb_handle * handle)
398
- {
399
- trace("incr_reference_count");
400
-
401
- track_ref_count("I INCR", handle);
402
-
403
- ATOMIC_INC(handle->atomic);
404
- if (handle->parent_handle != 0)
405
- {
406
- log(DEBUG, "incrementing parent");
407
- ATOMIC_INC(handle->parent_handle->atomic);
408
- }
409
-
410
- track_ref_count("O INCR", handle);
411
- }
412
-
413
- void decr_reference_count(nuodb_handle * handle)
414
- {
415
- trace("decr_reference_count");
416
-
417
- track_ref_count("I DECR", handle);
418
-
419
- if (handle->atomic == 0)
420
- {
421
- return;
422
- }
423
-
424
- if (ATOMIC_DEC(handle->atomic) == 0)
425
- {
426
- (*(handle->free_func))(handle);
427
- if (handle->parent_handle != 0)
428
- {
429
- log(DEBUG, "decrementing parent");
430
- decr_reference_count(handle->parent_handle);
431
- handle->parent = Qnil;
432
- handle->parent_handle = 0;
433
- assert(NIL_P(handle->parent));
434
- }
435
- track_ref_count("O DECR", handle);
436
-
437
- print_address("[DELETING HANDLE]", handle);
438
- xfree(handle);
439
- handle = NULL;
440
- }
441
- else
442
- {
443
- track_ref_count("O DECR", handle);
444
- }
445
- }
446
-
447
280
  //------------------------------------------------------------------------------
448
281
  // exception mapper
449
282
 
450
283
  static ID c_error_code_assignment;
451
284
 
452
- static void rb_raise_nuodb_error(int code, const char * fmt, ...)
285
+ static void rb_raise_nuodb_error(int code, const char* fmt, ...)
453
286
  {
454
287
  va_list args;
455
288
  char text[BUFSIZ];
@@ -468,60 +301,124 @@ static void rb_raise_nuodb_error(int code, const char * fmt, ...)
468
301
  using namespace NuoDB;
469
302
 
470
303
  //------------------------------------------------------------------------------
304
+ //
305
+ //
306
+ static
307
+ void handle_init(nuodb_handle* self, nuodb_handle* parent, int initialChildren, void (*cleaner)(nuodb_handle*))
308
+ {
309
+ self->numUsed = 0;
310
+ self->freePending = false;
311
+ self->cleanupFunc = NULL;
312
+ self->parent = parent;
313
+ self->cleanupFunc = cleaner;
314
+ }
471
315
 
316
+ /*
317
+ * Adjusts the parent's reference count
318
+ */
472
319
  static
473
- VALUE nuodb_result_free_protect(VALUE value)
320
+ int add_child(nuodb_handle* parent, nuodb_handle* child)
474
321
  {
475
- trace("nuodb_result_free_protect");
476
- nuodb_result_handle * handle = reinterpret_cast<nuodb_result_handle *>(value);
477
- if (handle != NULL)
478
- {
479
- if (handle->pointer != NULL)
480
- {
481
- try
482
- {
483
- track_ref_count("CLOSE RESULT", handle);
484
- log(INFO, "closing result");
485
- handle->pointer->close();
486
- handle->pointer = NULL;
487
- }
488
- catch (SQLException & e)
489
- {
490
- rb_raise_nuodb_error(e.getSqlcode(), "Failed to successfully close result: %s", e.getText());
491
- }
492
- }
322
+ parent->numUsed++;
323
+
324
+ return parent->numUsed;
325
+ }
326
+
327
+ /*
328
+ * Decrements the parent's reference count. Returns whether or not this child was the last one.
329
+ * If true, that means the responsibility for freeing the parent rests with the child handle
330
+ * calling this function.
331
+ */
332
+ static
333
+ bool remove_from_parent(nuodb_handle* child, nuodb_handle* parent)
334
+ {
335
+ //parent may be NULL
336
+ if (parent) {
337
+ parent->numUsed--;
338
+ assert(parent->numUsed >= 0);
339
+ return parent->numUsed == 0 && parent->freePending;
493
340
  }
494
- return Qnil;
341
+
342
+ return false;
495
343
  }
496
344
 
345
+ /*
346
+ * Method attempts to free handle and recursively free its parent if necessary. Returns a pointer
347
+ * to any exception encoundered while executing cleanup functions. Errors do not stop recursion.
348
+ * An error in the child won't stop this from attempting to free the parent. To do otherwise would
349
+ * cause a leak.
350
+ */
497
351
  static
498
- void nuodb_result_free(void * ptr)
352
+ NuoDB::SQLException* handle_free(nuodb_handle* handle, nuodb_handle* parent)
499
353
  {
500
- trace("nuodb_result_free");
501
- if (ptr != NULL)
502
- {
503
- int exception = 0;
504
- rb_protect(nuodb_result_free_protect, reinterpret_cast<VALUE>(ptr), &exception);
505
- if (exception)
506
- {
507
- rb_jump_tag(exception);
354
+ if (handle->numUsed == 0) {
355
+ bool needToRemoveParent = remove_from_parent(handle, parent);
356
+
357
+ NuoDB::SQLException* caughtError = NULL;
358
+
359
+ try {
360
+ //clean up ourselves
361
+ handle->cleanupFunc(handle);
362
+ } catch (NuoDB::SQLException& err) {
363
+ caughtError = &err;
364
+ }
365
+
366
+ try {
367
+ //clean up parent if we're the last ones out
368
+ if (needToRemoveParent) {
369
+ handle_free(parent, parent->parent);
370
+ }
371
+ } catch (NuoDB::SQLException& err) {
372
+ if (!caughtError) {
373
+ caughtError = &err;
374
+ }
508
375
  }
376
+
377
+ //free ourselves
378
+ trace("freeing object");
379
+ free(handle);
380
+
381
+ return caughtError;
382
+ } else {
383
+ handle->freePending = true;
384
+ return NULL;
509
385
  }
510
386
  }
511
387
 
512
388
  static
513
- void nuodb_result_mark(void * ptr)
389
+ void nuodb_result_mark(void* ptr)
514
390
  {
515
391
  trace("nuodb_result_mark");
516
- nuodb_result_handle * handle = static_cast<nuodb_result_handle *>(ptr);
517
- rb_gc_mark(handle->parent);
392
+ nuodb_result_handle* handle = static_cast<nuodb_result_handle *>(ptr);
393
+ rb_gc_mark(handle->statement);
518
394
  }
519
395
 
520
396
  static
521
- void nuodb_result_decr_reference_count(nuodb_handle * handle)
397
+ void nuodb_result_cleanup(nuodb_handle* handle)
522
398
  {
523
- trace("nuodb_result_decr_reference_count");
524
- decr_reference_count(handle);
399
+ nuodb_result_handle* resultHandle = (nuodb_result_handle*)handle;
400
+
401
+ if (resultHandle && resultHandle->pointer) {
402
+ resultHandle->pointer->close();
403
+ }
404
+ }
405
+
406
+ static
407
+ void nuodb_result_free(nuodb_handle* handle)
408
+ {
409
+ trace("nuodb_result_free");
410
+ nuodb_result_handle* result_handle = (nuodb_result_handle*)handle;
411
+
412
+ if (result_handle) {
413
+ NuoDB::SQLException* err = handle_free(handle, (result_handle->prepStmt != NULL ? (nuodb_handle*)result_handle->prepStmt : (nuodb_handle*)result_handle->stmt));
414
+
415
+ if (err) {
416
+ //Not ok to raise an error during GC
417
+ //rb_raise_nuodb_error(err->getSqlcode(), "Failed to successfully close result set: %s", err->getText());
418
+ log(ERROR, "Failed to successfully close result set");
419
+ log(ERROR, err->getText());
420
+ }
421
+ }
525
422
  }
526
423
 
527
424
  /*
@@ -534,49 +431,9 @@ static
534
431
  VALUE nuodb_result_finish(VALUE self)
535
432
  {
536
433
  trace("nuodb_result_free_protect");
537
- nuodb_result_handle * handle = cast_handle<nuodb_result_handle>(self);//reinterpret_cast<nuodb_result_handle *>(value);
434
+ nuodb_result_handle* handle = cast_handle<nuodb_result_handle>(self);
538
435
  nuodb_result_free(handle);
539
- // if (handle != NULL)
540
- // {
541
- // if (handle->pointer != NULL)
542
- // {
543
- // try
544
- // {
545
- // //handle->pointer->close();
546
- // //handle->pointer = NULL;
547
- // }
548
- // catch (SQLException & e)
549
- // {
550
- // rb_raise_nuodb_error(e.getSqlcode(), "Failed to successfully close result: %s", e.getText());
551
- // }
552
- // }
553
- // }
554
436
  return Qnil;
555
- //
556
- //
557
- //
558
- // trace("nuodb_result_finish");
559
- // if (ENABLE_CLOSE_HOOK)
560
- // {
561
- // //nuodb_result_decr_reference_count(cast_handle<nuodb_result_handle>(self));
562
- // }
563
- // nuodb_result_handle * handle = ;
564
- // if (handle != NULL && handle->pointer != NULL)
565
- // {
566
- // if (ATOMIC_DEC(handle->atomic) == 0)
567
- // {
568
- // try
569
- // {
570
- // //handle->pointer->close();
571
- // //handle->pointer = NULL;
572
- // }
573
- // catch (SQLException & e)
574
- // {
575
- // rb_raise_nuodb_error(e.getSqlcode(), "Failed to successfully close result set: %s", e.getText());
576
- // }
577
- // }
578
- // }
579
- // return Qnil;
580
437
  }
581
438
 
582
439
  static
@@ -592,6 +449,10 @@ VALUE nuodb_map_sql_type(int type)
592
449
  symbol = ID2SYM(rb_intern("integer"));
593
450
  break;
594
451
 
452
+ case NUOSQL_BINARY:
453
+ symbol = ID2SYM(rb_intern("binary"));
454
+ break;
455
+
595
456
  case NUOSQL_FLOAT:
596
457
  case NUOSQL_DOUBLE:
597
458
  symbol = ID2SYM(rb_intern("float"));
@@ -628,18 +489,16 @@ VALUE nuodb_map_sql_type(int type)
628
489
  symbol = ID2SYM(rb_intern("numeric"));
629
490
  break;
630
491
 
631
- // case NUOSQL_BLOB:
632
- // symbol = ID2SYM(rb_intern("blob"));
633
- // break;
634
- //
492
+ case NUOSQL_BLOB:
493
+ symbol = ID2SYM(rb_intern("blob"));
494
+ break;
635
495
  // case NUOSQL_CLOB:
636
496
  // symbol = ID2SYM(rb_intern("clob"));
637
497
  // break;
638
498
 
639
499
  case NUOSQL_NULL:
640
- case NUOSQL_BLOB:
500
+ //case NUOSQL_BLOB:
641
501
  case NUOSQL_CLOB:
642
- case NUOSQL_BINARY:
643
502
  case NUOSQL_LONGVARBINARY:
644
503
  default:
645
504
  rb_raise(rb_eNotImpError, "Unsupported SQL type: %d", type);
@@ -647,53 +506,51 @@ VALUE nuodb_map_sql_type(int type)
647
506
  return symbol;
648
507
  }
649
508
  static
650
- VALUE nuodb_result_alloc(VALUE parent, NuoDB::ResultSet * results, NuoDB::Connection * connection)
651
- {
652
- trace("nuodb_result_alloc");
653
- nuodb_handle * parent_handle = cast_handle<nuodb_handle>(parent);
654
- if (parent_handle != NULL)
655
- {
656
- nuodb_result_handle * handle = ALLOC(struct nuodb_result_handle);
657
- handle->free_func = RUBY_DATA_FUNC(nuodb_result_free);
658
- handle->atomic = 0;
659
- handle->parent = parent;
660
- handle->parent_handle = parent_handle;
509
+ VALUE nuodb_result_init(VALUE parent, NuoDB::ResultSet* results, NuoDB::Connection* connection)
510
+ {
511
+ trace("nuodb_result_init");
512
+ nuodb_handle* parent_handle = cast_handle<nuodb_handle>(parent);
513
+ if (parent_handle != NULL) {
514
+ trace("alloc result set");
515
+ nuodb_result_handle* handle = ALLOC(struct nuodb_result_handle);
516
+ handle_init(handle, parent_handle, 0, nuodb_result_cleanup);
517
+ handle->statement = parent;
518
+ add_child(parent_handle, handle);
519
+
520
+ handle->prepStmt = NULL;
521
+ handle->stmt = NULL;
522
+ handle->columnCount = -1;
523
+ handle->types = NULL;
524
+ handle->resultMetaData = NULL;
661
525
  handle->pointer = results;
662
526
  handle->connection = connection;
663
- incr_reference_count(handle);
664
- VALUE self = Data_Wrap_Struct(nuodb_result_klass, nuodb_result_mark, nuodb_result_decr_reference_count, handle);
527
+ VALUE self = Data_Wrap_Struct(nuodb_result_klass, nuodb_result_mark, nuodb_result_free, handle);
665
528
 
666
529
  rb_iv_set(self, "@columns", Qnil);
667
530
  rb_iv_set(self, "@rows", Qnil);
668
531
 
669
532
  if (!rb_block_given_p()) {
670
- trace("nuodb_result_alloc: no block");
533
+ trace("nuodb_result_init: no block");
671
534
 
672
535
  return self;
673
536
  }
674
537
 
675
- trace("nuodb_result_alloc: begin block");
538
+ trace("nuodb_result_init: begin block");
676
539
 
677
540
  int exception = 0;
678
541
  VALUE result = rb_protect(rb_yield, self, &exception);
679
542
 
680
- trace("nuodb_result_alloc: end block");
543
+ trace("nuodb_result_init: end block");
681
544
 
682
- //nuodb_result_finish(self);
545
+ trace("nuodb_result_init: auto finish");
683
546
 
684
- trace("nuodb_result_alloc: auto finish");
685
-
686
- if (exception)
687
- {
547
+ if (exception) {
548
+ //@TODO - don't we need to free here?
688
549
  rb_jump_tag(exception);
689
- }
690
- else
691
- {
550
+ } else {
692
551
  return result;
693
552
  }
694
- }
695
- else
696
- {
553
+ } else {
697
554
  rb_raise(rb_eArgError, "invalid state: statement handle nil");
698
555
  }
699
556
  return Qnil;
@@ -708,10 +565,9 @@ nuodb_get_rb_timezone_offset()
708
565
  }
709
566
 
710
567
  static VALUE
711
- nuodb_get_rb_value(int column, SqlType type, ResultSet * results)
568
+ nuodb_get_rb_value(int column, SqlType type, ResultSet* results)
712
569
  {
713
570
  VALUE value = Qnil;
714
-
715
571
  switch (type)
716
572
  {
717
573
  case NUOSQL_BIT:
@@ -764,11 +620,13 @@ nuodb_get_rb_value(int column, SqlType type, ResultSet * results)
764
620
  }
765
621
  break;
766
622
  }
767
- case NUOSQL_CHAR:
623
+
624
+ case NUOSQL_BLOB:
625
+ case NUOSQL_BINARY:
768
626
  case NUOSQL_VARCHAR:
769
627
  case NUOSQL_LONGVARCHAR:
770
628
  {
771
- char const * field = results->getString(column);
629
+ char const* field = results->getString(column);
772
630
  if (!results->wasNull())
773
631
  {
774
632
  value = rb_str_new2(field);
@@ -777,7 +635,7 @@ nuodb_get_rb_value(int column, SqlType type, ResultSet * results)
777
635
  }
778
636
  case NUOSQL_DATE:
779
637
  {
780
- NuoDB::Date * field = results->getDate(column);
638
+ NuoDB::Date* field = results->getDate(column);
781
639
  if (!results->wasNull())
782
640
  {
783
641
  double secs = (double) field->getSeconds();
@@ -789,17 +647,17 @@ nuodb_get_rb_value(int column, SqlType type, ResultSet * results)
789
647
  case NUOSQL_TIME:
790
648
  case NUOSQL_TIMESTAMP:
791
649
  {
792
- NuoDB::Timestamp * field = results->getTimestamp(column);
650
+ NuoDB::Timestamp* field = results->getTimestamp(column);
793
651
  if (!results->wasNull())
794
652
  {
795
- double secs = ((double) field->getSeconds()) + (((double) field->getNanos()) / 1000000);
653
+ double secs = ((double) field->getSeconds()) + (((double) field->getNanos()) / NANOS_PER_SECOND);
796
654
  value = rb_funcall(rb_cTime, rb_intern("at"), 1, rb_float_new(secs)); // - nuodb_get_rb_timezone_offset()
797
655
  }
798
656
  break;
799
657
  }
800
658
  case NUOSQL_NUMERIC:
801
659
  {
802
- char const * field = results->getString(column);
660
+ char const* field = results->getString(column);
803
661
  if (!results->wasNull())
804
662
  {
805
663
  rb_require("bigdecimal");
@@ -812,13 +670,23 @@ nuodb_get_rb_value(int column, SqlType type, ResultSet * results)
812
670
  }
813
671
  default:
814
672
  {
815
- rb_raise(rb_eTypeError, "not a supported ruby type: %d", type);
673
+ rb_raise(rb_eTypeError, "Not a supported ruby type: %d", type);
816
674
  break;
817
675
  }
818
676
  }
819
677
  return value;
820
678
  }
821
679
 
680
+ static
681
+ NuoDB::ResultSetMetaData* getResultMetadata(nuodb_result_handle* result_handle)
682
+ {
683
+ if (!result_handle->resultMetaData && result_handle->pointer) {
684
+ result_handle->resultMetaData = result_handle->pointer->getMetaData();
685
+ }
686
+
687
+ return result_handle->resultMetaData;
688
+ }
689
+
822
690
  /*
823
691
  * call-seq:
824
692
  * result.columns -> ary
@@ -835,53 +703,26 @@ static VALUE
835
703
  nuodb_result_columns(VALUE self)
836
704
  {
837
705
  trace("nuodb_result_columns");
838
- nuodb_result_handle * handle = cast_handle<nuodb_result_handle>(self);
839
- if (handle != NULL && handle->pointer != NULL)
840
- {
706
+ nuodb_result_handle* handle = cast_handle<nuodb_result_handle>(self);
707
+ if (handle != NULL && handle->pointer != NULL) {
841
708
  VALUE columns = rb_iv_get(self, "@columns");
842
- if (NIL_P(columns))
843
- {
844
- try
845
- {
846
- ResultSetMetaData * result_metadata = handle->pointer->getMetaData();
847
- DatabaseMetaData * database_metadata = handle->connection->getMetaData();
709
+
710
+ if (NIL_P(columns)) {
711
+ try {
712
+ ResultSetMetaData* result_metadata = getResultMetadata(handle);
848
713
 
849
714
  VALUE array = rb_ary_new();
850
715
  rb_require("nuodb/column");
851
716
  VALUE column_klass = rb_const_get(m_nuodb, rb_intern("Column"));
852
717
 
853
718
  int column_count = result_metadata->getColumnCount();
854
- for (int column_index = 1; column_index < column_count + 1; ++column_index)
855
- {
856
- char const * schema_name = result_metadata->getSchemaName(column_index);
857
- char const * table_name = result_metadata->getTableName(column_index);
858
- char const * column_name = result_metadata->getColumnName(column_index);
859
-
860
- // args: [name, default, sql_type, null]
719
+ for (int column_index = 1; column_index < column_count + 1; ++column_index) {
861
720
  VALUE args[4];
862
721
 
863
722
  args[0] = rb_str_new2(result_metadata->getColumnLabel(column_index));
864
-
865
- ResultSet * database_metadata_results = database_metadata->getColumns(NULL,
866
- schema_name, table_name, column_name);
867
-
868
- if(database_metadata_results->next())
869
- {
870
- try
871
- {
872
- args[1] = nuodb_get_rb_value(database_metadata_results->findColumn("COLUMN_DEF"),
873
- (SqlType) result_metadata->getColumnType(column_index), database_metadata_results);
874
- }
875
- catch (SQLException & e)
876
- {
877
- args[1] = Qnil;
878
- }
879
- }
880
- else
881
- {
882
- args[1] = Qnil;
883
- }
884
- database_metadata_results->close();
723
+
724
+ //Can't issue database metadata queries as that will close out the current transaction due to a bug
725
+ args[1] = Qnil;
885
726
 
886
727
  args[2] = nuodb_map_sql_type(result_metadata->getColumnType(column_index));
887
728
  args[3] = result_metadata->isNullable(column_index) ? Qtrue : Qfalse;
@@ -893,24 +734,40 @@ nuodb_result_columns(VALUE self)
893
734
  rb_iv_set(self, "@columns", array);
894
735
 
895
736
  return array;
896
- }
897
- catch (SQLException & e)
898
- {
737
+ } catch (SQLException & e) {
899
738
  rb_raise_nuodb_error(e.getSqlcode(), "Failed to create column info: %s", e.getText());
900
739
  }
901
- }
902
- else
903
- {
740
+ } else {
904
741
  return columns;
905
742
  }
906
- }
907
- else
908
- {
743
+ } else {
909
744
  rb_raise(rb_eArgError, "invalid state: result handle nil");
910
745
  }
911
746
  return Qnil;
912
747
  }
913
748
 
749
+ static
750
+ void nuodb_populate_row_metadata(nuodb_result_handle* result_handle)
751
+ {
752
+ if (!result_handle->pointer || result_handle->types != NULL) {
753
+ return;
754
+ }
755
+ trace("populating row metadata");
756
+
757
+ NuoDB::ResultSetMetaData* metadata = getResultMetadata(result_handle);
758
+ assert(metadata != NULL);
759
+
760
+ int32_t column_count = metadata->getColumnCount();
761
+ result_handle->columnCount = column_count;
762
+ result_handle->types = ALLOC_N(SqlType, column_count);
763
+
764
+ for (int32_t column = 1; column < column_count + 1; column++) {
765
+ SqlType type = (SqlType) metadata->getColumnType(column);
766
+ result_handle->types[column-1] = type;
767
+ }
768
+
769
+ }
770
+
914
771
  /*
915
772
  * call-seq:
916
773
  * result.rows -> ary
@@ -932,25 +789,24 @@ static VALUE
932
789
  nuodb_result_rows(VALUE self)
933
790
  {
934
791
  trace("nuodb_result_rows");
935
- nuodb_result_handle * handle = cast_handle<nuodb_result_handle>(self);
936
- if (handle != NULL && handle->pointer != NULL)
937
- {
792
+ nuodb_result_handle* handle = cast_handle<nuodb_result_handle>(self);
793
+
794
+ if (handle != NULL && handle->pointer != NULL) {
795
+
938
796
  VALUE rows = rb_iv_get(self, "@rows");
939
- if (NIL_P(rows))
940
- {
941
- try
942
- {
797
+
798
+ if (NIL_P(rows)) {
799
+ try {
800
+ nuodb_populate_row_metadata(handle);
943
801
  rows = rb_ary_new();
944
802
 
945
- while (handle->pointer->next())
946
- {
803
+ while (handle->pointer->next()) {
804
+
947
805
  VALUE row = rb_ary_new();
948
806
 
949
- NuoDB::ResultSetMetaData * metadata = handle->pointer->getMetaData();
950
- int32_t column_count = metadata->getColumnCount();
951
- for (int32_t column = 1; column < column_count + 1; column++)
952
- {
953
- SqlType type = (SqlType) metadata->getColumnType(column);
807
+ //remember, SQL result set columns are 1-indexed
808
+ for (int32_t column = 1; column < handle->columnCount + 1; column++) {
809
+ SqlType type = handle->types[column - 1];
954
810
  rb_ary_push(row, nuodb_get_rb_value(column, type, handle->pointer));
955
811
  }
956
812
 
@@ -958,16 +814,12 @@ nuodb_result_rows(VALUE self)
958
814
  }
959
815
 
960
816
  rb_iv_set(self, "@rows", rows);
961
- }
962
- catch (SQLException & e)
963
- {
817
+ } catch (SQLException & e) {
964
818
  rb_raise_nuodb_error(e.getSqlcode(), "Failed to create a rows array: %s", e.getText());
965
819
  }
966
820
  }
967
821
  return rows;
968
- }
969
- else
970
- {
822
+ } else {
971
823
  rb_raise(rb_eArgError, "invalid state: result handle nil");
972
824
  }
973
825
  return Qnil;
@@ -992,7 +844,7 @@ static VALUE
992
844
  nuodb_result_each(VALUE self)
993
845
  {
994
846
  trace("nuodb_result_each");
995
- nuodb_result_handle * handle = cast_handle<nuodb_result_handle>(self);
847
+ nuodb_result_handle* handle = cast_handle<nuodb_result_handle>(self);
996
848
  if (handle != NULL && handle->pointer != NULL)
997
849
  {
998
850
  VALUE rows = rb_iv_get(self, "@rows");
@@ -1038,59 +890,43 @@ void nuodb_define_result_api()
1038
890
  //------------------------------------------------------------------------------
1039
891
 
1040
892
  static
1041
- VALUE nuodb_statement_free_protect(VALUE value)
893
+ void nuodb_statement_mark(void* ptr)
1042
894
  {
1043
- trace("nuodb_statement_free_protect");
1044
- nuodb_statement_handle * handle = reinterpret_cast<nuodb_statement_handle*>(value);
1045
- if (handle != NULL)
1046
- {
1047
- if (handle->pointer != NULL)
1048
- {
1049
- try
1050
- {
1051
- log(INFO, "closing statement");
1052
- handle->pointer->close();
1053
- handle->pointer = NULL;
1054
- }
1055
- catch (SQLException & e)
1056
- {
1057
- rb_raise_nuodb_error(e.getSqlcode(), "Failed to successfully close statement: %s", e.getText());
1058
- }
1059
- }
1060
- }
1061
- return Qnil;
895
+ trace("nuodb_statement_mark");
896
+
897
+ nuodb_statement_handle* handle = static_cast<nuodb_statement_handle *>(ptr);
898
+ rb_gc_mark(handle->connection);
1062
899
  }
1063
900
 
1064
901
  static
1065
- void nuodb_statement_free(void * ptr)
902
+ void nuodb_statement_free(void* ptr)
1066
903
  {
1067
904
  trace("nuodb_statement_free");
1068
- if (ptr != NULL)
1069
- {
1070
- int exception = 0;
1071
- rb_protect(nuodb_statement_free_protect, reinterpret_cast<VALUE>(ptr), &exception);
1072
- if (exception)
1073
- {
1074
- rb_jump_tag(exception);
905
+ nuodb_statement_handle* handle = (nuodb_statement_handle*)ptr;
906
+
907
+ if (handle && handle->pointer) {
908
+ NuoDB::SQLException* err = handle_free(handle, handle->connection_handle);
909
+
910
+ if (err) {
911
+ //Not ok to raise an error during GC
912
+ //rb_raise_nuodb_error(err->getSqlcode(), "Failed to successfully close statement: %s", err->getText());
913
+ log(ERROR, "Failed to successfully close statement");
914
+ log(ERROR, err->getText());
1075
915
  }
1076
916
  }
917
+
1077
918
  }
1078
919
 
1079
920
  static
1080
- void nuodb_statement_mark(void * ptr)
921
+ void nuodb_statement_cleanup(nuodb_handle* handle)
1081
922
  {
1082
- trace("nuodb_statement_mark");
923
+ nuodb_statement_handle* statementHandle = (nuodb_statement_handle*)handle;
1083
924
 
1084
- nuodb_statement_handle * handle = static_cast<nuodb_statement_handle *>(ptr);
1085
- rb_gc_mark(handle->parent);
925
+ if (statementHandle && statementHandle->pointer) {
926
+ statementHandle->pointer->close();
927
+ }
1086
928
  }
1087
929
 
1088
- static
1089
- void nuodb_statement_decr_reference_count(void * ptr)
1090
- {
1091
- trace("nuodb_statement_decr_reference_count");
1092
- decr_reference_count(static_cast<nuodb_statement_handle *>(ptr));
1093
- }
1094
930
 
1095
931
  /*
1096
932
  * call-seq:
@@ -1102,39 +938,9 @@ static
1102
938
  VALUE nuodb_statement_finish(VALUE self)
1103
939
  {
1104
940
  trace("nuodb_statement_finish");
1105
- nuodb_statement_handle * handle = cast_handle<nuodb_statement_handle>(self);//reinterpret_cast<nuodb_statement_handle*>(value);
941
+ nuodb_statement_handle* handle = cast_handle<nuodb_statement_handle>(self);//reinterpret_cast<nuodb_statement_handle*>(value);
1106
942
  nuodb_statement_free(handle);
1107
- // if (handle != NULL)
1108
- // {
1109
- // if (handle->pointer != NULL)
1110
- // {
1111
- // try
1112
- // {
1113
- // log(INFO, "closing statement");
1114
- // handle->pointer->close();
1115
- // handle->pointer = NULL;
1116
- // }
1117
- // catch (SQLException & e)
1118
- // {
1119
- // rb_raise_nuodb_error(e.getSqlcode(), "Failed to successfully close statement: %s", e.getText());
1120
- // }
1121
- // }
1122
- // }
1123
943
  return Qnil;
1124
- //
1125
- // if (ENABLE_CLOSE_HOOK)
1126
- // {
1127
- // nuodb_statement_handle * handle = cast_handle<nuodb_statement_handle>(self);
1128
- // if (handle != NULL && handle->pointer != NULL)
1129
- // {
1130
- // nuodb_statement_decr_reference_count(handle);
1131
- // }
1132
- // else
1133
- // {
1134
- // rb_raise(rb_eArgError, "invalid state: statement handle nil");
1135
- // }
1136
- // }
1137
- // return Qnil;
1138
944
  }
1139
945
 
1140
946
  static
@@ -1142,33 +948,28 @@ VALUE nuodb_statement_initialize(VALUE parent)
1142
948
  {
1143
949
  trace("nuodb_statement_initialize");
1144
950
 
1145
- nuodb_connection_handle * parent_handle = cast_handle<nuodb_connection_handle>(parent);
1146
- if (parent_handle != NULL && parent_handle->pointer != NULL)
1147
- {
1148
- NuoDB::Statement * statement = NULL;
1149
- try
1150
- {
951
+ nuodb_connection_handle* parent_handle = cast_handle<nuodb_connection_handle>(parent);
952
+
953
+ if (parent_handle != NULL && parent_handle->pointer != NULL) {
954
+ NuoDB::Statement* statement = NULL;
955
+ try {
1151
956
  statement = parent_handle->pointer->createStatement();
1152
- }
1153
- catch (SQLException & e)
1154
- {
957
+ } catch (SQLException & e) {
1155
958
  log(ERROR, "rb_raise");
1156
959
  rb_raise_nuodb_error(e.getSqlcode(), "Failed to create statement: %s", e.getText());
1157
960
  }
1158
961
 
1159
- nuodb_statement_handle * handle = ALLOC(nuodb_statement_handle);
962
+ trace("alloc");
963
+ nuodb_statement_handle* handle = ALLOC(nuodb_statement_handle);
964
+ handle_init(handle, parent_handle, 1, nuodb_statement_cleanup);
965
+ add_child(parent_handle, handle);
1160
966
 
1161
- handle->free_func = RUBY_DATA_FUNC(&nuodb_statement_free);
1162
- handle->atomic = 0;
1163
- handle->parent = parent;
1164
- handle->parent_handle = parent_handle;
967
+ handle->connection = parent;
968
+ handle->connection_handle = parent_handle;
1165
969
  handle->pointer = statement;
1166
- incr_reference_count(handle);
1167
- assert(handle->atomic = 1);
1168
- VALUE self = Data_Wrap_Struct(nuodb_statement_klass, nuodb_statement_mark, nuodb_statement_decr_reference_count, handle);
970
+ VALUE self = Data_Wrap_Struct(nuodb_statement_klass, nuodb_statement_mark, nuodb_statement_free, handle);
1169
971
  if (!rb_block_given_p()) {
1170
972
  trace("nuodb_statement_initialize: no block");
1171
- track_ref_count("ALLOC STMT S", cast_handle<nuodb_handle>(self));
1172
973
  return self;
1173
974
  }
1174
975
 
@@ -1184,17 +985,13 @@ VALUE nuodb_statement_initialize(VALUE parent)
1184
985
 
1185
986
  trace("nuodb_statement_initialize: auto finish");
1186
987
 
1187
- if (exception)
1188
- {
988
+ if (exception) {
989
+ //@TODO - don't we need to free memory here?
1189
990
  rb_jump_tag(exception);
1190
- }
1191
- else
1192
- {
991
+ } else {
1193
992
  return result;
1194
993
  }
1195
- }
1196
- else
1197
- {
994
+ } else {
1198
995
  rb_raise(rb_eArgError, "invalid state: statement handle nil");
1199
996
  }
1200
997
  return Qnil;
@@ -1218,7 +1015,7 @@ VALUE nuodb_statement_execute(VALUE self, VALUE sql)
1218
1015
  rb_raise(rb_eTypeError, "wrong sql argument type %s (String expected)", rb_class2name(CLASS_OF(sql)));
1219
1016
  }
1220
1017
 
1221
- nuodb_statement_handle * handle = cast_handle<nuodb_statement_handle>(self);
1018
+ nuodb_statement_handle* handle = cast_handle<nuodb_statement_handle>(self);
1222
1019
  if (handle != NULL && handle->pointer != NULL)
1223
1020
  {
1224
1021
  try
@@ -1249,7 +1046,7 @@ VALUE nuodb_statement_update_count(VALUE self)
1249
1046
  {
1250
1047
  trace("nuodb_statement_update_count");
1251
1048
 
1252
- nuodb_statement_handle * handle = cast_handle<nuodb_statement_handle>(self);
1049
+ nuodb_statement_handle* handle = cast_handle<nuodb_statement_handle>(self);
1253
1050
  if (handle != NULL && handle->pointer != NULL)
1254
1051
  {
1255
1052
  try
@@ -1278,12 +1075,20 @@ static VALUE nuodb_statement_results(VALUE self)
1278
1075
  {
1279
1076
  trace("nuodb_statement_results");
1280
1077
 
1281
- nuodb_statement_handle * handle = cast_handle<nuodb_statement_handle>(self);
1078
+ nuodb_statement_handle* handle = cast_handle<nuodb_statement_handle>(self);
1282
1079
  if (handle != NULL && handle->pointer != NULL)
1283
1080
  {
1284
1081
  try
1285
1082
  {
1286
- return nuodb_result_alloc(self, handle->pointer->getResultSet(), handle->pointer->getConnection());
1083
+ VALUE ruby_handle = nuodb_result_init(self, handle->pointer->getResultSet(), handle->pointer->getConnection());
1084
+ nuodb_result_handle* our_result_handle = cast_handle<nuodb_result_handle>(ruby_handle);
1085
+
1086
+ assert(our_result_handle != NULL);
1087
+ assert(our_result_handle->prepStmt == NULL);
1088
+ assert(our_result_handle->stmt == NULL);
1089
+
1090
+ our_result_handle->stmt = handle;
1091
+ return ruby_handle;
1287
1092
  }
1288
1093
  catch (SQLException & e)
1289
1094
  {
@@ -1308,26 +1113,27 @@ static VALUE nuodb_statement_generated_keys(VALUE self)
1308
1113
  {
1309
1114
  trace("nuodb_statement_generated_keys");
1310
1115
 
1311
- nuodb_statement_handle * handle = cast_handle<nuodb_statement_handle>(self);
1312
- if (handle != NULL && handle->pointer != NULL)
1313
- {
1314
- try
1315
- {
1116
+ nuodb_statement_handle* handle = cast_handle<nuodb_statement_handle>(self);
1117
+ if (handle != NULL && handle->pointer != NULL) {
1118
+ try {
1316
1119
  // this hack should not have been necessary; it should never have
1317
1120
  // returned null, this is a product defect.
1318
- ResultSet * results = handle->pointer->getGeneratedKeys();
1319
- if (results != NULL)
1320
- {
1321
- return nuodb_result_alloc(self, results, handle->pointer->getConnection());
1121
+ ResultSet* results = handle->pointer->getGeneratedKeys();
1122
+ if (results != NULL) {
1123
+ VALUE ruby_handle = nuodb_result_init(self, results, handle->pointer->getConnection());
1124
+ nuodb_result_handle* our_result_handle = cast_handle<nuodb_result_handle>(ruby_handle);
1125
+
1126
+ assert(our_result_handle != NULL);
1127
+ assert(our_result_handle->prepStmt == NULL);
1128
+ assert(our_result_handle->stmt == NULL);
1129
+
1130
+ our_result_handle->stmt = handle;
1131
+ return ruby_handle;
1322
1132
  }
1323
- }
1324
- catch (SQLException & e)
1325
- {
1133
+ } catch (SQLException & e) {
1326
1134
  rb_raise_nuodb_error(e.getSqlcode(), "Failed to get the generated keys for the statement: %s", e.getText());
1327
1135
  }
1328
- }
1329
- else
1330
- {
1136
+ } else {
1331
1137
  rb_raise(rb_eArgError, "invalid state: statement handle nil");
1332
1138
  }
1333
1139
  return Qnil;
@@ -1360,60 +1166,40 @@ void nuodb_define_statement_api()
1360
1166
  //------------------------------------------------------------------------------
1361
1167
 
1362
1168
  static
1363
- VALUE nuodb_prepared_statement_free_protect(VALUE value)
1169
+ void nuodb_prepared_statement_free(void* ptr)
1364
1170
  {
1365
- trace("nuodb_prepared_statement_free_protect");
1366
- nuodb_prepared_statement_handle * handle = reinterpret_cast<nuodb_prepared_statement_handle *>(value);
1367
- track_ref_count("PS FREE PROTECT", handle);
1368
- if (handle != NULL)
1369
- {
1370
- if (handle->pointer != NULL)
1371
- {
1372
- try
1373
- {
1374
- log(INFO, "closing prepared statement");
1375
- handle->pointer->close();
1376
- handle->pointer = NULL;
1377
- }
1378
- catch (SQLException & e)
1379
- {
1380
- rb_raise_nuodb_error(e.getSqlcode(), "Failed to successfully close statement: %s", e.getText());
1381
- }
1171
+ trace("nuodb_prepared_statement_free");
1172
+
1173
+ if (ptr != NULL) {
1174
+ nuodb_prepared_statement_handle* handle = (nuodb_prepared_statement_handle*)ptr;
1175
+ NuoDB::SQLException* err = handle_free(handle, handle->connection_handle);
1176
+
1177
+ if (err) {
1178
+ //Not ok to raise a ruby error during GC
1179
+ //rb_raise_nuodb_error(err->getSqlcode(), "Failed to successfully close prepared statement: %s", err->getText());
1180
+ log(ERROR, "Failed to successfully close prepared statement");
1181
+ log(ERROR, err->getText());
1382
1182
  }
1383
1183
  }
1384
- return Qnil;
1385
1184
  }
1386
1185
 
1387
1186
  static
1388
- void nuodb_prepared_statement_free(void * ptr)
1187
+ void nuodb_prepared_statement_cleanup(nuodb_handle* handle)
1389
1188
  {
1390
- trace("nuodb_prepared_statement_free");
1189
+ nuodb_prepared_statement_handle* prepHandle = (nuodb_prepared_statement_handle*)prepHandle;
1391
1190
 
1392
- if (ptr != NULL)
1393
- {
1394
- int exception = 0;
1395
- rb_protect(nuodb_prepared_statement_free_protect, reinterpret_cast<VALUE>(ptr), &exception);
1396
- if (exception)
1397
- {
1398
- rb_jump_tag(exception);
1399
- }
1191
+ if (prepHandle && prepHandle->pointer) {
1192
+ prepHandle->pointer->close();
1400
1193
  }
1401
1194
  }
1402
1195
 
1403
1196
  static
1404
- void nuodb_prepared_statement_mark(void * ptr)
1197
+ void nuodb_prepared_statement_mark(void* ptr)
1405
1198
  {
1406
1199
  trace("nuodb_prepared_statement_mark");
1407
1200
 
1408
- nuodb_prepared_statement_handle * handle = static_cast<nuodb_prepared_statement_handle *>(ptr);
1409
- rb_gc_mark(handle->parent);
1410
- }
1411
-
1412
- static
1413
- void nuodb_prepared_statement_decr_reference_count(nuodb_handle * handle)
1414
- {
1415
- trace("nuodb_prepared_statement_decr_reference_count");
1416
- decr_reference_count(handle);
1201
+ nuodb_prepared_statement_handle* handle = (nuodb_prepared_statement_handle *)ptr;
1202
+ rb_gc_mark(handle->connection);
1417
1203
  }
1418
1204
 
1419
1205
  /*
@@ -1426,41 +1212,9 @@ static
1426
1212
  VALUE nuodb_prepared_statement_finish(VALUE self)
1427
1213
  {
1428
1214
  trace("nuodb_prepared_statement_finish");
1429
- nuodb_prepared_statement_handle * handle = cast_handle<nuodb_prepared_statement_handle>(self);//reinterpret_cast<nuodb_prepared_statement_handle *>(value);
1430
- track_ref_count("FINISH PSTMT", handle);
1215
+ nuodb_prepared_statement_handle* handle = cast_handle<nuodb_prepared_statement_handle>(self);//reinterpret_cast<nuodb_prepared_statement_handle *>(value);
1431
1216
  nuodb_prepared_statement_free(handle);
1432
- // if (handle != NULL)
1433
- // {
1434
- // if (handle->pointer != NULL)
1435
- // {
1436
- // try
1437
- // {
1438
- // track_ref_count("CLOSE PSTMT", handle);
1439
- // log(INFO, "closing prepared statement");
1440
- // handle->pointer->close();
1441
- // handle->pointer = NULL;
1442
- // }
1443
- // catch (SQLException & e)
1444
- // {
1445
- // rb_raise_nuodb_error(e.getSqlcode(), "Failed to successfully close statement: %s", e.getText());
1446
- // }
1447
- // }
1448
- // }
1449
1217
  return Qnil;
1450
- //
1451
- // if (ENABLE_CLOSE_HOOK)
1452
- // {
1453
- // nuodb_prepared_statement_handle * handle = cast_handle<nuodb_prepared_statement_handle>(self);
1454
- // if (handle != NULL && handle->pointer != NULL)
1455
- // {
1456
- // nuodb_prepared_statement_decr_reference_count(handle);
1457
- // }
1458
- // else
1459
- // {
1460
- // rb_raise(rb_eArgError, "invalid state: prepared statement handle nil");
1461
- // }
1462
- // }
1463
- // return Qnil;
1464
1218
  }
1465
1219
 
1466
1220
  static
@@ -1468,34 +1222,30 @@ VALUE nuodb_prepared_statement_initialize(VALUE parent, VALUE sql)
1468
1222
  {
1469
1223
  trace("nuodb_prepared_statement_initialize");
1470
1224
 
1471
- if (TYPE(sql) != T_STRING)
1472
- {
1225
+ if (TYPE(sql) != T_STRING) {
1473
1226
  rb_raise(rb_eTypeError, "wrong sql argument type %s (String expected)", rb_class2name(CLASS_OF(sql)));
1474
1227
  }
1475
1228
 
1476
- nuodb_connection_handle * parent_handle = cast_handle<nuodb_connection_handle>(parent);
1477
- if (parent_handle != NULL && parent_handle->pointer != NULL)
1478
- {
1479
- NuoDB::PreparedStatement * statement = NULL;
1480
- try
1481
- {
1229
+ nuodb_connection_handle* parent_handle = cast_handle<nuodb_connection_handle>(parent);
1230
+
1231
+ if (parent_handle != NULL && parent_handle->pointer != NULL) {
1232
+ NuoDB::PreparedStatement* statement = NULL;
1233
+ try {
1482
1234
  statement = parent_handle->pointer->prepareStatement(StringValueCStr(sql),
1483
1235
  NuoDB::RETURN_GENERATED_KEYS);
1484
- }
1485
- catch (SQLException & e)
1486
- {
1236
+ } catch (SQLException & e) {
1487
1237
  rb_raise_nuodb_error(e.getSqlcode(), "Failed to create prepared statement (%s): %s", sql, e.getText());
1488
1238
  }
1489
1239
 
1490
- nuodb_prepared_statement_handle * handle = ALLOC(struct nuodb_prepared_statement_handle);
1491
- handle->free_func = RUBY_DATA_FUNC(&nuodb_prepared_statement_free);
1492
- handle->atomic = 0;
1493
- handle->parent = parent;
1494
- handle->parent_handle = parent_handle;
1240
+ trace("alloc");
1241
+ nuodb_prepared_statement_handle* handle = ALLOC(struct nuodb_prepared_statement_handle);
1242
+ handle_init(handle, parent_handle, 1, nuodb_prepared_statement_cleanup);
1243
+ add_child(parent_handle, handle);
1244
+
1245
+ handle->connection = parent;
1246
+ handle->connection_handle = parent_handle;
1495
1247
  handle->pointer = statement;
1496
- incr_reference_count(handle);
1497
- assert(handle->atomic == 1);
1498
- VALUE self = Data_Wrap_Struct(nuodb_prepared_statement_klass, nuodb_prepared_statement_mark, nuodb_prepared_statement_decr_reference_count, handle);
1248
+ VALUE self = Data_Wrap_Struct(nuodb_prepared_statement_klass, nuodb_prepared_statement_mark, nuodb_prepared_statement_free, handle);
1499
1249
 
1500
1250
  if (!rb_block_given_p()) {
1501
1251
  trace("nuodb_prepared_statement_initialize: no block");
@@ -1515,24 +1265,20 @@ VALUE nuodb_prepared_statement_initialize(VALUE parent, VALUE sql)
1515
1265
 
1516
1266
  trace("nuodb_prepared_statement_initialize: auto finish");
1517
1267
 
1518
- if (exception)
1519
- {
1268
+ if (exception) {
1269
+ //@TODO - don't we have to free memory?
1520
1270
  rb_jump_tag(exception);
1521
- }
1522
- else
1523
- {
1271
+ } else {
1524
1272
  return result;
1525
1273
  }
1526
- }
1527
- else
1528
- {
1274
+ } else {
1529
1275
  rb_raise(rb_eArgError, "invalid state: prepared statement handle nil");
1530
1276
  }
1531
1277
  return Qnil;
1532
1278
  }
1533
1279
 
1534
1280
  static
1535
- void raise_unsupported_type_at_index(char const * type_name, int32_t index)
1281
+ void raise_unsupported_type_at_index(char const* type_name, int32_t index)
1536
1282
  {
1537
1283
  rb_raise(rb_eTypeError, "unsupported type %s at %d", type_name, index);
1538
1284
  }
@@ -1559,7 +1305,7 @@ VALUE nuodb_prepared_statement_bind_param(VALUE self, VALUE param, VALUE value)
1559
1305
  }
1560
1306
  int32_t index = NUM2UINT(param);
1561
1307
 
1562
- NuoDB::PreparedStatement * statement = cast_pointer_member<
1308
+ NuoDB::PreparedStatement* statement = cast_pointer_member<
1563
1309
  nuodb_prepared_statement_handle, NuoDB::PreparedStatement>(self);
1564
1310
 
1565
1311
  try
@@ -1576,7 +1322,7 @@ VALUE nuodb_prepared_statement_bind_param(VALUE self, VALUE param, VALUE value)
1576
1322
  case T_STRING: // 0x05
1577
1323
  {
1578
1324
  log(DEBUG, "supported: T_STRING");
1579
- char const * real_value = RSTRING_PTR(value);
1325
+ char const* real_value = RSTRING_PTR(value);
1580
1326
  statement->setString(index, real_value);
1581
1327
  }
1582
1328
  break;
@@ -1614,7 +1360,7 @@ VALUE nuodb_prepared_statement_bind_param(VALUE self, VALUE param, VALUE value)
1614
1360
  VALUE sec = rb_funcall(value, rb_intern("tv_sec"), 0);
1615
1361
  //VALUE offset = rb_funcall(value, rb_intern("utc_offset"), 0);
1616
1362
  VALUE usec = rb_funcall(value, rb_intern("tv_usec"), 0);
1617
- SqlTimestamp sqlTimestamp(NUM2INT(sec), NUM2INT(usec) * 1000); // + NUM2INT(offset)
1363
+ SqlTimestamp sqlTimestamp(NUM2INT(sec), NUM2INT(usec) * NANOS_PER_MICRO); // + NUM2INT(offset)
1618
1364
  statement->setTimestamp(index, &sqlTimestamp);
1619
1365
  break;
1620
1366
  }
@@ -1626,7 +1372,7 @@ VALUE nuodb_prepared_statement_bind_param(VALUE self, VALUE param, VALUE value)
1626
1372
  VALUE sec = rb_funcall(time, rb_intern("tv_sec"), 0);
1627
1373
  //VALUE offset = rb_funcall(time, rb_intern("utc_offset"), 0);
1628
1374
  VALUE usec = rb_funcall(time, rb_intern("tv_usec"), 0);
1629
- SqlTimestamp sqlTimestamp(NUM2LONG(sec), NUM2INT(usec) * 1000);// + NUM2INT(offset)
1375
+ SqlTimestamp sqlTimestamp(NUM2LONG(sec), NUM2INT(usec) * NANOS_PER_MICRO);// + NUM2INT(offset)
1630
1376
  statement->setTimestamp(index, &sqlTimestamp);
1631
1377
  break;
1632
1378
  }
@@ -1711,7 +1457,7 @@ VALUE nuodb_prepared_statement_bind_params(VALUE self, VALUE array)
1711
1457
  {
1712
1458
  trace("nuodb_prepared_statement_bind_params");
1713
1459
 
1714
- nuodb_prepared_statement_handle * handle = cast_handle<nuodb_prepared_statement_handle>(self);
1460
+ nuodb_prepared_statement_handle* handle = cast_handle<nuodb_prepared_statement_handle>(self);
1715
1461
  if (handle != NULL && handle->pointer != NULL)
1716
1462
  {
1717
1463
  for (int i = 0; i < RARRAY_LEN(array); ++i)
@@ -1741,7 +1487,7 @@ VALUE nuodb_prepared_statement_execute(VALUE self)
1741
1487
  {
1742
1488
  trace("nuodb_prepared_statement_execute");
1743
1489
 
1744
- nuodb_prepared_statement_handle * handle = cast_handle<nuodb_prepared_statement_handle>(self);
1490
+ nuodb_prepared_statement_handle* handle = cast_handle<nuodb_prepared_statement_handle>(self);
1745
1491
  if (handle != NULL && handle->pointer != NULL)
1746
1492
  {
1747
1493
  try
@@ -1771,7 +1517,7 @@ VALUE nuodb_prepared_statement_update_count(VALUE self)
1771
1517
  {
1772
1518
  trace("nuodb_prepared_statement_update_count");
1773
1519
 
1774
- nuodb_prepared_statement_handle * handle = cast_handle<nuodb_prepared_statement_handle>(self);
1520
+ nuodb_prepared_statement_handle* handle = cast_handle<nuodb_prepared_statement_handle>(self);
1775
1521
  if (handle != NULL && handle->pointer != NULL)
1776
1522
  {
1777
1523
  try
@@ -1800,20 +1546,22 @@ static VALUE nuodb_prepared_statement_results(VALUE self)
1800
1546
  {
1801
1547
  trace("nuodb_prepared_statement_results");
1802
1548
 
1803
- nuodb_prepared_statement_handle * handle = cast_handle<nuodb_prepared_statement_handle>(self);
1804
- if (handle != NULL && handle->pointer != NULL)
1805
- {
1806
- try
1807
- {
1808
- return nuodb_result_alloc(self, handle->pointer->getResultSet(), handle->pointer->getConnection());
1809
- }
1810
- catch (SQLException & e)
1811
- {
1549
+ nuodb_prepared_statement_handle* handle = cast_handle<nuodb_prepared_statement_handle>(self);
1550
+ if (handle != NULL && handle->pointer != NULL) {
1551
+ try {
1552
+ VALUE ruby_handle = nuodb_result_init(self, handle->pointer->getResultSet(), handle->pointer->getConnection());
1553
+ nuodb_result_handle* our_result_handle = cast_handle<nuodb_result_handle>(ruby_handle);
1554
+
1555
+ assert(our_result_handle != NULL);
1556
+ assert(our_result_handle->prepStmt == NULL);
1557
+ assert(our_result_handle->stmt == NULL);
1558
+
1559
+ our_result_handle->prepStmt = handle;
1560
+ return ruby_handle;
1561
+ } catch (SQLException & e) {
1812
1562
  rb_raise_nuodb_error(e.getSqlcode(), "Failed to get the result set for the prepared statement: %s", e.getText());
1813
1563
  }
1814
- }
1815
- else
1816
- {
1564
+ } else {
1817
1565
  rb_raise(rb_eArgError, "invalid state: prepared statement handle nil");
1818
1566
  }
1819
1567
  return Qnil;
@@ -1830,26 +1578,27 @@ static VALUE nuodb_prepared_statement_generated_keys(VALUE self)
1830
1578
  {
1831
1579
  trace("nuodb_prepared_statement_generated_keys");
1832
1580
 
1833
- nuodb_prepared_statement_handle * handle = cast_handle<nuodb_prepared_statement_handle>(self);
1834
- if (handle != NULL && handle->pointer != NULL)
1835
- {
1836
- try
1837
- {
1581
+ nuodb_prepared_statement_handle* handle = cast_handle<nuodb_prepared_statement_handle>(self);
1582
+ if (handle != NULL && handle->pointer != NULL) {
1583
+ try {
1838
1584
  // this hack should not have been necessary; it should never have
1839
1585
  // returned null, this is a product defect.
1840
- ResultSet * results = handle->pointer->getGeneratedKeys();
1841
- if (results != NULL)
1842
- {
1843
- return nuodb_result_alloc(self, results, handle->pointer->getConnection());
1586
+ ResultSet* results = handle->pointer->getGeneratedKeys();
1587
+ if (results != NULL) {
1588
+ VALUE ruby_handle = nuodb_result_init(self, results, handle->pointer->getConnection());
1589
+ nuodb_result_handle* our_result_handle = cast_handle<nuodb_result_handle>(ruby_handle);
1590
+
1591
+ assert(our_result_handle != NULL);
1592
+ assert(our_result_handle->prepStmt == NULL);
1593
+ assert(our_result_handle->stmt == NULL);
1594
+
1595
+ our_result_handle->prepStmt = handle;
1596
+ return ruby_handle;
1844
1597
  }
1845
- }
1846
- catch (SQLException & e)
1847
- {
1598
+ } catch (SQLException & e) {
1848
1599
  rb_raise_nuodb_error(e.getSqlcode(), "Failed to get the generated keys for the prepared statement: %s", e.getText());
1849
1600
  }
1850
- }
1851
- else
1852
- {
1601
+ } else {
1853
1602
  rb_raise(rb_eArgError, "invalid state: prepared statement handle nil");
1854
1603
  }
1855
1604
  return Qnil;
@@ -1888,56 +1637,38 @@ void nuodb_define_prepared_statement_api()
1888
1637
  */
1889
1638
 
1890
1639
  static
1891
- VALUE nuodb_connection_free_protect(VALUE value)
1640
+ void nuodb_connection_free(void* ptr)
1892
1641
  {
1893
- trace("nuodb_connection_free_protect");
1642
+ trace("nuodb_connection_free");
1643
+ if (ptr != NULL) {
1644
+ nuodb_connection_handle* handle = (nuodb_connection_handle*)ptr;
1645
+ NuoDB::SQLException* err = handle_free(handle, NULL);
1894
1646
 
1895
- nuodb_connection_handle * handle = reinterpret_cast<nuodb_connection_handle *>(value);
1896
- track_ref_count("FREE CONN CHECK", handle);
1897
- if (handle != NULL)
1898
- {
1899
- track_ref_count("FREE CONN", handle);
1900
- if (handle->pointer != NULL)
1901
- {
1902
- try
1903
- {
1904
- track_ref_count("CLOSE CONN", handle);
1905
- log(INFO, "closing connection");
1906
- handle->pointer->close();
1907
- handle->pointer = NULL;
1908
- }
1909
- catch (SQLException & e)
1910
- {
1911
- log(DEBUG, "rb_raise");
1912
- rb_raise_nuodb_error(e.getSqlcode(), "Failed to successfully close connection: %s", e.getText());
1913
- }
1647
+ if (err) {
1648
+ //Not ok to raise a ruby exception during GC
1649
+ //rb_raise_nuodb_error(err->getSqlcode(), "Failed to successfully close connection: %s", err->getText());
1650
+ log(ERROR, "Failed to successfully close connection");
1651
+ log(ERROR, err->getText());
1914
1652
  }
1915
1653
  }
1916
- return Qnil;
1917
1654
  }
1918
1655
 
1919
1656
  static
1920
- void nuodb_connection_free(void * ptr)
1657
+ void nuodb_connection_cleanup(nuodb_handle* handle)
1921
1658
  {
1922
- trace("nuodb_connection_free");
1923
- if (ptr != NULL)
1924
- {
1925
- int exception = 0;
1926
- rb_protect(nuodb_connection_free_protect, reinterpret_cast<VALUE>(ptr), &exception);
1927
- if (exception)
1928
- {
1929
- rb_jump_tag(exception);
1930
- }
1659
+ nuodb_connection_handle* connectionHandle = (nuodb_connection_handle*)handle;
1660
+
1661
+ if (connectionHandle && connectionHandle->pointer) {
1662
+ connectionHandle->pointer->close();
1931
1663
  }
1932
1664
  }
1933
1665
 
1934
1666
  static
1935
- void nuodb_connection_mark(void * ptr)
1667
+ void nuodb_connection_mark(void* ptr)
1936
1668
  {
1937
1669
  trace("nuodb_connection_mark");
1938
1670
 
1939
- nuodb_connection_handle * handle = static_cast<nuodb_connection_handle *>(ptr);
1940
- track_ref_count("MARK CONN", handle);
1671
+ nuodb_connection_handle* handle = (nuodb_connection_handle *)ptr;
1941
1672
 
1942
1673
  rb_gc_mark(handle->database);
1943
1674
  rb_gc_mark(handle->username);
@@ -1945,38 +1676,28 @@ void nuodb_connection_mark(void * ptr)
1945
1676
  rb_gc_mark(handle->schema);
1946
1677
  }
1947
1678
 
1948
- static
1949
- void nuodb_connection_decr_reference_count(nuodb_handle * handle)
1950
- {
1951
- trace("nuodb_connection_decr_reference_count");
1952
- decr_reference_count(handle);
1953
- }
1954
-
1955
1679
  static
1956
1680
  VALUE nuodb_connection_alloc(VALUE klass)
1957
1681
  {
1958
1682
  trace("nuodb_connection_alloc");
1959
1683
 
1960
- nuodb_connection_handle * handle = ALLOC(struct nuodb_connection_handle);
1684
+ trace("alloc");
1685
+ nuodb_connection_handle* handle = ALLOC(struct nuodb_connection_handle);
1686
+ handle_init(handle, NULL, 4, nuodb_connection_cleanup);
1961
1687
  handle->database = Qnil;
1962
1688
  handle->username = Qnil;
1963
1689
  handle->password = Qnil;
1964
1690
  handle->schema = Qnil;
1965
1691
  handle->timezone = Qnil;
1966
1692
 
1967
- handle->free_func = RUBY_DATA_FUNC(&nuodb_connection_free);
1968
- handle->atomic = 0;
1969
- handle->parent = Qnil;
1970
- handle->parent_handle = 0;
1971
1693
  handle->pointer = 0;
1972
- incr_reference_count(handle);
1973
1694
 
1974
1695
  print_address("[ALLOC] connection", handle);
1975
1696
 
1976
- return Data_Wrap_Struct(klass, nuodb_connection_mark, nuodb_connection_decr_reference_count, handle);
1697
+ return Data_Wrap_Struct(klass, nuodb_connection_mark, nuodb_connection_free, handle);
1977
1698
  }
1978
1699
 
1979
- static void internal_connection_connect_or_raise(nuodb_connection_handle * handle)
1700
+ static void internal_connection_connect_or_raise(nuodb_connection_handle* handle)
1980
1701
  {
1981
1702
  trace("internal_connection_connect_or_raise");
1982
1703
 
@@ -1985,7 +1706,7 @@ static void internal_connection_connect_or_raise(nuodb_connection_handle * handl
1985
1706
  try
1986
1707
  {
1987
1708
  handle->pointer = Connection::create();
1988
- Properties * props = handle->pointer->allocProperties();
1709
+ Properties* props = handle->pointer->allocProperties();
1989
1710
  props->putValue("user", StringValueCStr(handle->username));
1990
1711
  props->putValue("password", StringValueCStr(handle->password));
1991
1712
  props->putValue("schema", StringValueCStr(handle->schema));
@@ -2010,7 +1731,7 @@ static void internal_connection_connect_or_raise(nuodb_connection_handle * handl
2010
1731
  try
2011
1732
  {
2012
1733
  handle->pointer = Connection::create();
2013
- Properties * props = handle->pointer->allocProperties();
1734
+ Properties* props = handle->pointer->allocProperties();
2014
1735
  props->putValue("user", StringValueCStr(handle->username));
2015
1736
  props->putValue("password", StringValueCStr(handle->password));
2016
1737
  if (!NIL_P(handle->timezone))
@@ -2045,7 +1766,7 @@ static VALUE nuodb_connection_commit(VALUE self)
2045
1766
  {
2046
1767
  trace("nuodb_connection_commit");
2047
1768
 
2048
- nuodb_connection_handle * handle = cast_handle<nuodb_connection_handle>(self);
1769
+ nuodb_connection_handle* handle = cast_handle<nuodb_connection_handle>(self);
2049
1770
  if (handle != NULL && handle->pointer != NULL)
2050
1771
  {
2051
1772
  try
@@ -2073,44 +1794,9 @@ static VALUE nuodb_connection_commit(VALUE self)
2073
1794
  static VALUE nuodb_connection_disconnect(VALUE self)
2074
1795
  {
2075
1796
  trace("nuodb_connection_disconnect");
2076
- nuodb_connection_handle * handle = cast_handle<nuodb_connection_handle>(self);//;
2077
- track_ref_count("CONN DISCONNECT", handle);
1797
+ nuodb_connection_handle* handle = cast_handle<nuodb_connection_handle>(self);//;
2078
1798
  nuodb_connection_free(handle);
2079
- // if (handle != NULL)
2080
- // {
2081
- // track_ref_count("FREE CONN", handle);
2082
- // if (handle->pointer != NULL)
2083
- // {
2084
- // try
2085
- // {
2086
- // track_ref_count("CLOSE CONN", handle);
2087
- // handle->pointer->close();
2088
- // handle->pointer = NULL;
2089
- // }
2090
- // catch (SQLException & e)
2091
- // {
2092
- // log(DEBUG, "rb_raise");
2093
- // rb_raise_nuodb_error(e.getSqlcode(), "Failed to successfully close connection: %s", e.getText());
2094
- // }
2095
- // }
2096
- // }
2097
1799
  return Qnil;
2098
- //
2099
- //
2100
- //
2101
- // if (ENABLE_CLOSE_HOOK)
2102
- // {
2103
- // nuodb_connection_handle * handle = cast_handle<nuodb_connection_handle>(self);
2104
- // if (handle != NULL && handle->pointer != NULL)
2105
- // {
2106
- // nuodb_connection_decr_reference_count(handle);
2107
- // }
2108
- // else
2109
- // {
2110
- // rb_raise(rb_eArgError, "invalid state: connection handle nil");
2111
- // }
2112
- // }
2113
- // return Qnil;
2114
1800
  }
2115
1801
 
2116
1802
  /*
@@ -2126,7 +1812,7 @@ static VALUE nuodb_connection_ping(VALUE self)
2126
1812
  {
2127
1813
  trace("nuodb_connection_ping");
2128
1814
 
2129
- nuodb_connection_handle * handle = cast_handle<nuodb_connection_handle>(self);
1815
+ nuodb_connection_handle* handle = cast_handle<nuodb_connection_handle>(self);
2130
1816
  if (handle != NULL && handle->pointer != NULL)
2131
1817
  {
2132
1818
  try
@@ -2197,7 +1883,7 @@ static VALUE nuodb_connection_rollback(VALUE self)
2197
1883
  {
2198
1884
  trace("nuodb_connection_rollback");
2199
1885
 
2200
- nuodb_connection_handle * handle = cast_handle<nuodb_connection_handle>(self);
1886
+ nuodb_connection_handle* handle = cast_handle<nuodb_connection_handle>(self);
2201
1887
  if (handle != NULL && handle->pointer != NULL)
2202
1888
  {
2203
1889
  try
@@ -2234,7 +1920,7 @@ static VALUE nuodb_connection_autocommit_set(VALUE self, VALUE value)
2234
1920
  {
2235
1921
  trace("nuodb_connection_autocommit_set");
2236
1922
 
2237
- nuodb_connection_handle * handle = cast_handle<nuodb_connection_handle>(self);
1923
+ nuodb_connection_handle* handle = cast_handle<nuodb_connection_handle>(self);
2238
1924
  if (handle != NULL && handle->pointer != NULL)
2239
1925
  {
2240
1926
  bool auto_commit = !(RB_TYPE_P(value, T_FALSE) || RB_TYPE_P(value, T_NIL));
@@ -2270,7 +1956,7 @@ static VALUE nuodb_connection_autocommit_get(VALUE self)
2270
1956
  {
2271
1957
  trace("nuodb_connection_autocommit_get");
2272
1958
 
2273
- nuodb_connection_handle * handle = cast_handle<nuodb_connection_handle>(self);
1959
+ nuodb_connection_handle* handle = cast_handle<nuodb_connection_handle>(self);
2274
1960
  if (handle != NULL && handle->pointer != NULL)
2275
1961
  {
2276
1962
  try
@@ -2322,7 +2008,7 @@ static VALUE nuodb_connection_initialize(VALUE self, VALUE hash)
2322
2008
  rb_raise(rb_eTypeError, "wrong argument type %s (Hash expected)", rb_class2name(CLASS_OF(hash)));
2323
2009
  }
2324
2010
 
2325
- nuodb_connection_handle * handle = cast_handle<nuodb_connection_handle>(self);
2011
+ nuodb_connection_handle* handle = cast_handle<nuodb_connection_handle>(self);
2326
2012
  if (NIL_P(handle->database))
2327
2013
  {
2328
2014
  VALUE value = rb_hash_aref(hash, sym_database);
@@ -2417,42 +2103,6 @@ static VALUE nuodb_connection_initialize(VALUE self, VALUE hash)
2417
2103
  return Qnil;
2418
2104
  }
2419
2105
 
2420
- ///*
2421
- // * call-seq:
2422
- // * tables(schema = nil) -> Results
2423
- // *
2424
- // * Retrieves a result set containing the tables associated to the specified schema,
2425
- // * or if the specified schema is nil, return a result set of tables for the schema
2426
- // * associated with the connection.
2427
- // */
2428
- //static VALUE nuodb_connection_tables(VALUE self, VALUE schema)
2429
- //{
2430
- // trace("nuodb_connection_tables");
2431
- //
2432
- // nuodb_connection_handle * handle = cast_handle<nuodb_connection_handle>(self);
2433
- // if (handle != NULL && handle->pointer != NULL)
2434
- // {
2435
- // if (schema == Qnil)
2436
- // {
2437
- // schema = handle->schema;
2438
- // }
2439
- //// char const * sql = "SELECT tablename FROM system.tables WHERE schema = ?"
2440
- //// try
2441
- //// {
2442
- //// return nuodb_result_alloc(self, handle->pointer->getGeneratedKeys());
2443
- //// }
2444
- //// catch (SQLException & e)
2445
- //// {
2446
- //// rb_raise_nuodb_error(e.getSqlcode(), "Failed to get the tables keys for the schema: %s", e.getText());
2447
- //// }
2448
- // }
2449
- // else
2450
- // {
2451
- // rb_raise(rb_eArgError, "invalid state: connection handle nil");
2452
- // }
2453
- // return Qnil;
2454
- //}
2455
-
2456
2106
  void nuodb_define_connection_api()
2457
2107
  {
2458
2108
  /*