nuodb 1.0.2 → 1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.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
  /*