sqlite3 1.3.5 → 1.3.13

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,14 +6,29 @@ require 'mkmf'
6
6
 
7
7
  RbConfig::MAKEFILE_CONFIG['CC'] = ENV['CC'] if ENV['CC']
8
8
 
9
- # --with-sqlite3-{dir,include,lib}
10
- dir_config("sqlite3")
11
9
 
12
- # prioritize local builds
13
- if enable_config("local", false)
14
- $LDFLAGS = ENV.fetch("LDFLAGS", nil)
10
+
11
+ ldflags = cppflags = nil
12
+ if RbConfig::CONFIG["host_os"] =~ /darwin/
13
+ begin
14
+ brew_prefix = `brew --prefix sqlite3`.chomp
15
+ ldflags = "#{brew_prefix}/lib"
16
+ cppflags = "#{brew_prefix}/include"
17
+ pkg_conf = "#{brew_prefix}/lib/pkgconfig"
18
+
19
+ # pkg_config should be less error prone than parsing compiler
20
+ # commandline options, but we need to set default ldflags and cpp flags
21
+ # in case the user doesn't have pkg-config installed
22
+ ENV['PKG_CONFIG_PATH'] ||= pkg_conf
23
+ rescue
24
+ end
15
25
  end
16
26
 
27
+ pkg_config("sqlite3")
28
+
29
+ # --with-sqlite3-{dir,include,lib}
30
+ dir_config("sqlite3", cppflags, ldflags)
31
+
17
32
  if RbConfig::CONFIG["host_os"] =~ /mswin/
18
33
  $CFLAGS << ' -W3'
19
34
  end
@@ -24,24 +39,33 @@ def asplode missing
24
39
  "http://www.sqlite.org/ first."
25
40
  else
26
41
  abort <<-error
27
- #{missing} is missing. Try 'port install sqlite3 +universal'
28
- or 'yum install sqlite-devel' and check your shared library search path (the
42
+ #{missing} is missing. Try 'brew install sqlite3',
43
+ 'yum install sqlite-devel' or 'apt-get install libsqlite3-dev'
44
+ and check your shared library search path (the
29
45
  location where your sqlite3 shared library is located).
30
46
  error
31
47
  end
32
48
  end
33
49
 
34
50
  asplode('sqlite3.h') unless find_header 'sqlite3.h'
51
+ find_library 'pthread', 'pthread_create' # 1.8 support. *shrug*
35
52
  asplode('sqlite3') unless find_library 'sqlite3', 'sqlite3_libversion_number'
36
53
 
37
54
  # Functions defined in 1.9 but not 1.8
38
55
  have_func('rb_proc_arity')
39
56
 
57
+ # Functions defined in 2.1 but not 2.0
58
+ have_func('rb_integer_pack')
59
+
40
60
  # These functions may not be defined
41
61
  have_func('sqlite3_initialize')
42
62
  have_func('sqlite3_backup_init')
43
63
  have_func('sqlite3_column_database_name')
44
64
  have_func('sqlite3_enable_load_extension')
45
65
  have_func('sqlite3_load_extension')
66
+ have_func('sqlite3_open_v2')
67
+ have_func('sqlite3_prepare_v2')
68
+ have_type('sqlite3_int64', 'sqlite3.h')
69
+ have_type('sqlite3_uint64', 'sqlite3.h')
46
70
 
47
71
  create_makefile('sqlite3/sqlite3_native')
@@ -3,11 +3,121 @@
3
3
  VALUE mSqlite3;
4
4
  VALUE cSqlite3Blob;
5
5
 
6
+ int bignum_to_int64(VALUE value, sqlite3_int64 *result)
7
+ {
8
+ #ifdef HAVE_RB_INTEGER_PACK
9
+ const int nails = 0;
10
+ int t = rb_integer_pack(value, result, 1, sizeof(*result), nails,
11
+ INTEGER_PACK_NATIVE_BYTE_ORDER|
12
+ INTEGER_PACK_2COMP);
13
+ switch (t) {
14
+ case -2: case +2:
15
+ return 0;
16
+ case +1:
17
+ if (!nails) {
18
+ if (*result < 0) return 0;
19
+ }
20
+ break;
21
+ case -1:
22
+ if (!nails) {
23
+ if (*result >= 0) return 0;
24
+ }
25
+ else {
26
+ *result += INT64_MIN;
27
+ }
28
+ break;
29
+ }
30
+ return 1;
31
+ #else
32
+ # ifndef RBIGNUM_LEN
33
+ # define RBIGNUM_LEN(x) RBIGNUM(x)->len
34
+ # endif
35
+ const long len = RBIGNUM_LEN(value);
36
+ if (len == 0) {
37
+ *result = 0;
38
+ return 1;
39
+ }
40
+ if (len > 63 / (SIZEOF_BDIGITS * CHAR_BIT) + 1) return 0;
41
+ if (len == 63 / (SIZEOF_BDIGITS * CHAR_BIT) + 1) {
42
+ const BDIGIT *digits = RBIGNUM_DIGITS(value);
43
+ BDIGIT blast = digits[len-1];
44
+ BDIGIT bmax = (BDIGIT)1UL << (63 % (CHAR_BIT * SIZEOF_BDIGITS));
45
+ if (blast > bmax) return 0;
46
+ if (blast == bmax) {
47
+ if (RBIGNUM_POSITIVE_P(value)) {
48
+ return 0;
49
+ }
50
+ else {
51
+ long i = len-1;
52
+ while (i) {
53
+ if (digits[--i]) return 0;
54
+ }
55
+ }
56
+ }
57
+ }
58
+ *result = (sqlite3_int64)NUM2LL(value);
59
+ return 1;
60
+ #endif
61
+ }
62
+
6
63
  static VALUE libversion(VALUE UNUSED(klass))
7
64
  {
8
65
  return INT2NUM(sqlite3_libversion_number());
9
66
  }
10
67
 
68
+ /* Returns the compile time setting of the SQLITE_THREADSAFE flag.
69
+ * See: https://www.sqlite.org/c3ref/threadsafe.html
70
+ */
71
+ static VALUE threadsafe_p(VALUE UNUSED(klass))
72
+ {
73
+ return INT2NUM(sqlite3_threadsafe());
74
+ }
75
+
76
+ void init_sqlite3_constants()
77
+ {
78
+ VALUE mSqlite3Constants;
79
+ VALUE mSqlite3Open;
80
+
81
+ mSqlite3Constants = rb_define_module_under(mSqlite3, "Constants");
82
+
83
+ /* sqlite3_open_v2 flags for Database::new */
84
+ mSqlite3Open = rb_define_module_under(mSqlite3Constants, "Open");
85
+
86
+ /* symbols = IO.readlines('sqlite3.h').map { |n| /\A#define\s+(SQLITE_OPEN_\w+)\s/ =~ n && $1 }.compact
87
+ * pad = symbols.map(&:length).max - 9
88
+ * symbols.each { |s| printf %Q{ rb_define_const(mSqlite3Open, %-#{pad}s INT2FIX(#{s}));\n}, '"' + s[12..-1] + '",' }
89
+ */
90
+ rb_define_const(mSqlite3Open, "READONLY", INT2FIX(SQLITE_OPEN_READONLY));
91
+ rb_define_const(mSqlite3Open, "READWRITE", INT2FIX(SQLITE_OPEN_READWRITE));
92
+ rb_define_const(mSqlite3Open, "CREATE", INT2FIX(SQLITE_OPEN_CREATE));
93
+ rb_define_const(mSqlite3Open, "DELETEONCLOSE", INT2FIX(SQLITE_OPEN_DELETEONCLOSE));
94
+ rb_define_const(mSqlite3Open, "EXCLUSIVE", INT2FIX(SQLITE_OPEN_EXCLUSIVE));
95
+ rb_define_const(mSqlite3Open, "MAIN_DB", INT2FIX(SQLITE_OPEN_MAIN_DB));
96
+ rb_define_const(mSqlite3Open, "TEMP_DB", INT2FIX(SQLITE_OPEN_TEMP_DB));
97
+ rb_define_const(mSqlite3Open, "TRANSIENT_DB", INT2FIX(SQLITE_OPEN_TRANSIENT_DB));
98
+ rb_define_const(mSqlite3Open, "MAIN_JOURNAL", INT2FIX(SQLITE_OPEN_MAIN_JOURNAL));
99
+ rb_define_const(mSqlite3Open, "TEMP_JOURNAL", INT2FIX(SQLITE_OPEN_TEMP_JOURNAL));
100
+ rb_define_const(mSqlite3Open, "SUBJOURNAL", INT2FIX(SQLITE_OPEN_SUBJOURNAL));
101
+ rb_define_const(mSqlite3Open, "MASTER_JOURNAL", INT2FIX(SQLITE_OPEN_MASTER_JOURNAL));
102
+ rb_define_const(mSqlite3Open, "NOMUTEX", INT2FIX(SQLITE_OPEN_NOMUTEX));
103
+ rb_define_const(mSqlite3Open, "FULLMUTEX", INT2FIX(SQLITE_OPEN_FULLMUTEX));
104
+ #ifdef SQLITE_OPEN_AUTOPROXY
105
+ /* SQLITE_VERSION_NUMBER>=3007002 */
106
+ rb_define_const(mSqlite3Open, "AUTOPROXY", INT2FIX(SQLITE_OPEN_AUTOPROXY));
107
+ rb_define_const(mSqlite3Open, "SHAREDCACHE", INT2FIX(SQLITE_OPEN_SHAREDCACHE));
108
+ rb_define_const(mSqlite3Open, "PRIVATECACHE", INT2FIX(SQLITE_OPEN_PRIVATECACHE));
109
+ rb_define_const(mSqlite3Open, "WAL", INT2FIX(SQLITE_OPEN_WAL));
110
+ #endif
111
+ #ifdef SQLITE_OPEN_URI
112
+ /* SQLITE_VERSION_NUMBER>=3007007 */
113
+ rb_define_const(mSqlite3Open, "URI", INT2FIX(SQLITE_OPEN_URI));
114
+ #endif
115
+ #ifdef SQLITE_OPEN_MEMORY
116
+ /* SQLITE_VERSION_NUMBER>=3007013 */
117
+ rb_define_const(mSqlite3Open, "MEMORY", INT2FIX(SQLITE_OPEN_MEMORY));
118
+ #endif
119
+ }
120
+
11
121
  void Init_sqlite3_native()
12
122
  {
13
123
  /*
@@ -28,6 +138,7 @@ void Init_sqlite3_native()
28
138
  sqlite3_initialize();
29
139
  #endif
30
140
 
141
+ init_sqlite3_constants();
31
142
  init_sqlite3_database();
32
143
  init_sqlite3_statement();
33
144
  #ifdef HAVE_SQLITE3_BACKUP_INIT
@@ -35,6 +146,7 @@ void Init_sqlite3_native()
35
146
  #endif
36
147
 
37
148
  rb_define_singleton_method(mSqlite3, "libversion", libversion, 0);
149
+ rb_define_singleton_method(mSqlite3, "threadsafe", threadsafe_p, 0);
38
150
  rb_define_const(mSqlite3, "SQLITE_VERSION", rb_str_new2(SQLITE_VERSION));
39
151
  rb_define_const(mSqlite3, "SQLITE_VERSION_NUMBER", INT2FIX(SQLITE_VERSION_NUMBER));
40
152
  }
@@ -12,15 +12,13 @@
12
12
  # define UNUSED(x) x
13
13
  #endif
14
14
 
15
- #ifndef RBIGNUM_LEN
16
- #define RBIGNUM_LEN(x) RBIGNUM(x)->len
17
- #endif
18
-
19
15
  #ifdef HAVE_RUBY_ENCODING_H
20
16
  #include <ruby/encoding.h>
21
17
 
18
+ #define USASCII_P(_obj) (rb_enc_get_index(_obj) == rb_usascii_encindex())
22
19
  #define UTF8_P(_obj) (rb_enc_get_index(_obj) == rb_utf8_encindex())
23
20
  #define UTF16_LE_P(_obj) (rb_enc_get_index(_obj) == rb_enc_find_index("UTF-16LE"))
21
+ #define UTF16_BE_P(_obj) (rb_enc_get_index(_obj) == rb_enc_find_index("UTF-16BE"))
24
22
  #define SQLITE3_UTF8_STR_NEW2(_obj) \
25
23
  (rb_enc_associate_index(rb_str_new2(_obj), rb_utf8_encindex()))
26
24
 
@@ -33,6 +31,14 @@
33
31
 
34
32
  #include <sqlite3.h>
35
33
 
34
+ #ifndef HAVE_TYPE_SQLITE3_INT64
35
+ typedef sqlite_int64 sqlite3_int64;
36
+ #endif
37
+
38
+ #ifndef HAVE_TYPE_SQLITE3_UINT64
39
+ typedef sqlite_uint64 sqlite3_uint64;
40
+ #endif
41
+
36
42
  extern VALUE mSqlite3;
37
43
  extern VALUE cSqlite3Blob;
38
44
 
@@ -41,4 +47,6 @@ extern VALUE cSqlite3Blob;
41
47
  #include <exception.h>
42
48
  #include <backup.h>
43
49
 
50
+ int bignum_to_int64(VALUE big, sqlite3_int64 *result);
51
+
44
52
  #endif
@@ -49,7 +49,11 @@ static VALUE initialize(VALUE self, VALUE db, VALUE sql)
49
49
  }
50
50
  #endif
51
51
 
52
+ #ifdef HAVE_SQLITE3_PREPARE_V2
52
53
  status = sqlite3_prepare_v2(
54
+ #else
55
+ status = sqlite3_prepare(
56
+ #endif
53
57
  db_ctx->db,
54
58
  (const char *)StringValuePtr(sql),
55
59
  (int)RSTRING_LEN(sql),
@@ -75,15 +79,12 @@ static VALUE initialize(VALUE self, VALUE db, VALUE sql)
75
79
  static VALUE sqlite3_rb_close(VALUE self)
76
80
  {
77
81
  sqlite3StmtRubyPtr ctx;
78
- sqlite3 * db;
79
82
 
80
83
  Data_Get_Struct(self, sqlite3StmtRuby, ctx);
81
84
 
82
85
  REQUIRE_OPEN_STMT(ctx);
83
86
 
84
- db = sqlite3_db_handle(ctx->st);
85
- CHECK(db, sqlite3_finalize(ctx->st));
86
-
87
+ sqlite3_finalize(ctx->st);
87
88
  ctx->st = NULL;
88
89
 
89
90
  return self;
@@ -111,7 +112,6 @@ static VALUE step(VALUE self)
111
112
  VALUE list;
112
113
  #ifdef HAVE_RUBY_ENCODING_H
113
114
  rb_encoding * internal_encoding;
114
- int enc_index;
115
115
  #endif
116
116
 
117
117
  Data_Get_Struct(self, sqlite3StmtRuby, ctx);
@@ -123,8 +123,7 @@ static VALUE step(VALUE self)
123
123
  #ifdef HAVE_RUBY_ENCODING_H
124
124
  {
125
125
  VALUE db = rb_iv_get(self, "@connection");
126
- VALUE encoding = rb_funcall(db, rb_intern("encoding"), 0);
127
- enc_index = NIL_P(encoding) ? rb_utf8_encindex() : rb_to_encoding_index(encoding);
126
+ rb_funcall(db, rb_intern("encoding"), 0);
128
127
  internal_encoding = rb_default_internal_encoding();
129
128
  }
130
129
  #endif
@@ -154,7 +153,7 @@ static VALUE step(VALUE self)
154
153
  (long)sqlite3_column_bytes(stmt, i)
155
154
  );
156
155
  #ifdef HAVE_RUBY_ENCODING_H
157
- rb_enc_associate_index(str, enc_index);
156
+ rb_enc_associate_index(str, rb_utf8_encindex());
158
157
  if(internal_encoding)
159
158
  str = rb_str_export_to_enc(str, internal_encoding);
160
159
  #endif
@@ -184,6 +183,8 @@ static VALUE step(VALUE self)
184
183
  return Qnil;
185
184
  break;
186
185
  default:
186
+ sqlite3_reset(stmt);
187
+ ctx->done_p = 0;
187
188
  CHECK(sqlite3_db_handle(ctx->st), value);
188
189
  }
189
190
 
@@ -236,15 +237,22 @@ static VALUE bind_param(VALUE self, VALUE key, VALUE value)
236
237
  SQLITE_TRANSIENT
237
238
  );
238
239
  } else {
240
+
241
+
239
242
  #ifdef HAVE_RUBY_ENCODING_H
240
- if(!UTF8_P(value)) {
241
- VALUE db = rb_iv_get(self, "@connection");
242
- VALUE encoding = rb_funcall(db, rb_intern("encoding"), 0);
243
- rb_encoding * enc = rb_to_encoding(encoding);
244
- value = rb_str_export_to_enc(value, enc);
243
+ if (UTF16_LE_P(value) || UTF16_BE_P(value)) {
244
+ status = sqlite3_bind_text16(
245
+ ctx->st,
246
+ index,
247
+ (const char *)StringValuePtr(value),
248
+ (int)RSTRING_LEN(value),
249
+ SQLITE_TRANSIENT
250
+ );
251
+ } else {
252
+ if (!UTF8_P(value) || !USASCII_P(value)) {
253
+ value = rb_str_encode(value, rb_enc_from_encoding(rb_utf8_encoding()), 0, Qnil);
245
254
  }
246
255
  #endif
247
-
248
256
  status = sqlite3_bind_text(
249
257
  ctx->st,
250
258
  index,
@@ -252,13 +260,18 @@ static VALUE bind_param(VALUE self, VALUE key, VALUE value)
252
260
  (int)RSTRING_LEN(value),
253
261
  SQLITE_TRANSIENT
254
262
  );
263
+ #ifdef HAVE_RUBY_ENCODING_H
264
+ }
265
+ #endif
255
266
  }
256
267
  break;
257
- case T_BIGNUM:
258
- if (RBIGNUM_LEN(value) * SIZEOF_BDIGITS <= 8) {
259
- status = sqlite3_bind_int64(ctx->st, index, (sqlite3_int64)NUM2LL(value));
268
+ case T_BIGNUM: {
269
+ sqlite3_int64 num64;
270
+ if (bignum_to_int64(value, &num64)) {
271
+ status = sqlite3_bind_int64(ctx->st, index, num64);
260
272
  break;
261
273
  }
274
+ }
262
275
  case T_FLOAT:
263
276
  status = sqlite3_bind_double(ctx->st, index, NUM2DBL(value));
264
277
  break;
@@ -287,12 +300,11 @@ static VALUE bind_param(VALUE self, VALUE key, VALUE value)
287
300
  static VALUE reset_bang(VALUE self)
288
301
  {
289
302
  sqlite3StmtRubyPtr ctx;
290
- int status;
291
303
 
292
304
  Data_Get_Struct(self, sqlite3StmtRuby, ctx);
293
305
  REQUIRE_OPEN_STMT(ctx);
294
306
 
295
- status = sqlite3_reset(ctx->st);
307
+ sqlite3_reset(ctx->st);
296
308
 
297
309
  ctx->done_p = 0;
298
310
 
@@ -307,12 +319,11 @@ static VALUE reset_bang(VALUE self)
307
319
  static VALUE clear_bindings(VALUE self)
308
320
  {
309
321
  sqlite3StmtRubyPtr ctx;
310
- int status;
311
322
 
312
323
  Data_Get_Struct(self, sqlite3StmtRuby, ctx);
313
324
  REQUIRE_OPEN_STMT(ctx);
314
325
 
315
- status = sqlite3_clear_bindings(ctx->st);
326
+ sqlite3_clear_bindings(ctx->st);
316
327
 
317
328
  ctx->done_p = 0;
318
329
 
@@ -359,7 +370,7 @@ static VALUE column_name(VALUE self, VALUE index)
359
370
 
360
371
  name = sqlite3_column_name(ctx->st, (int)NUM2INT(index));
361
372
 
362
- if(name) return rb_str_new2(name);
373
+ if(name) return SQLITE3_UTF8_STR_NEW2(name);
363
374
  return Qnil;
364
375
  }
365
376
 
data/faq/faq.yml CHANGED
@@ -331,7 +331,7 @@
331
331
  p obj == h
332
332
  </pre>
333
333
 
334
- - "How do insert binary data into the database?": >-
334
+ - "How do I insert binary data into the database?": >-
335
335
  Use blobs. Blobs are new features of SQLite3. You have to use bind
336
336
  variables to make it work:
337
337
 
data/lib/sqlite3.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # support multiple ruby version (fat binaries under windows)
2
2
  begin
3
- RUBY_VERSION =~ /(\d+.\d+)/
3
+ RUBY_VERSION =~ /(\d+\.\d+)/
4
4
  require "sqlite3/#{$1}/sqlite3_native"
5
5
  rescue LoadError
6
6
  require 'sqlite3/sqlite3_native'
@@ -8,3 +8,8 @@ end
8
8
 
9
9
  require 'sqlite3/database'
10
10
  require 'sqlite3/version'
11
+
12
+ module SQLite3
13
+ # Was sqlite3 compiled with thread safety on?
14
+ def self.threadsafe?; threadsafe > 0; end
15
+ end
@@ -94,10 +94,17 @@ in version 2.0.0.
94
94
  begin
95
95
  yield stmt
96
96
  ensure
97
- stmt.close
97
+ stmt.close unless stmt.closed?
98
98
  end
99
99
  end
100
100
 
101
+ # Returns the filename for the database named +db_name+. +db_name+ defaults
102
+ # to "main". Main return `nil` or an empty string if the database is
103
+ # temporary or in-memory.
104
+ def filename db_name = 'main'
105
+ db_filename db_name
106
+ end
107
+
101
108
  # Executes the given SQL statement. If additional parameters are given,
102
109
  # they are treated as bind variables, and are bound to the placeholders in
103
110
  # the query.
@@ -113,10 +120,6 @@ in version 2.0.0.
113
120
  # See also #execute2, #query, and #execute_batch for additional ways of
114
121
  # executing statements.
115
122
  def execute sql, bind_vars = [], *args, &block
116
- # FIXME: This is a terrible hack and should be removed but is required
117
- # for older versions of rails
118
- hack = Object.const_defined?(:ActiveRecord) && sql =~ /^PRAGMA index_list/
119
-
120
123
  if bind_vars.nil? || !args.empty?
121
124
  if args.empty?
122
125
  bind_vars = []
@@ -147,12 +150,7 @@ Support for bind parameters as *args will be removed in 2.0.0.
147
150
  else
148
151
  if @results_as_hash
149
152
  stmt.map { |row|
150
- h = type_translation ? row : ordered_map_for(columns, row)
151
-
152
- # FIXME UGH TERRIBLE HACK!
153
- h['unique'] = h['unique'].to_s if hack
154
-
155
- h
153
+ type_translation ? row : ordered_map_for(columns, row)
156
154
  }
157
155
  else
158
156
  stmt.to_a
@@ -221,22 +219,25 @@ Support for this behavior will be removed in version 2.0.0.
221
219
  sql = sql.strip
222
220
  until sql.empty? do
223
221
  prepare( sql ) do |stmt|
224
- # FIXME: this should probably use sqlite3's api for batch execution
225
- # This implementation requires stepping over the results.
226
- if bind_vars.length == stmt.bind_parameter_count
227
- stmt.bind_params(bind_vars)
222
+ unless stmt.closed?
223
+ # FIXME: this should probably use sqlite3's api for batch execution
224
+ # This implementation requires stepping over the results.
225
+ if bind_vars.length == stmt.bind_parameter_count
226
+ stmt.bind_params(bind_vars)
227
+ end
228
+ stmt.step
228
229
  end
229
- stmt.step
230
230
  sql = stmt.remainder.strip
231
231
  end
232
232
  end
233
+ # FIXME: we should not return `nil` as a success return value
233
234
  nil
234
235
  end
235
236
 
236
237
  # This is a convenience method for creating a statement, binding
237
238
  # paramters to it, and calling execute:
238
239
  #
239
- # result = db.query( "select * from foo where a=?", 5 )
240
+ # result = db.query( "select * from foo where a=?", [5])
240
241
  # # is the same as
241
242
  # result = db.prepare( "select * from foo where a=?" ).execute( 5 )
242
243
  #
@@ -250,7 +251,7 @@ Support for this behavior will be removed in version 2.0.0.
250
251
  if args.empty?
251
252
  bind_vars = []
252
253
  else
253
- bind_vars = [nil] + args
254
+ bind_vars = [bind_vars] + args
254
255
  end
255
256
 
256
257
  warn(<<-eowarn) if $VERBOSE
@@ -392,6 +393,9 @@ Support for this will be removed in version 2.0.0.
392
393
 
393
394
  def finalize
394
395
  super(@ctx)
396
+ result = @ctx.result
397
+ @ctx = FunctionProxy.new
398
+ result
395
399
  end
396
400
  })
397
401
  proxy.ctx = FunctionProxy.new
@@ -428,6 +432,7 @@ Support for this will be removed in version 2.0.0.
428
432
  #
429
433
  # class LengthsAggregateHandler
430
434
  # def self.arity; 1; end
435
+ # def self.name; 'lengths'; end
431
436
  #
432
437
  # def initialize
433
438
  # @total = 0
@@ -446,21 +451,28 @@ Support for this will be removed in version 2.0.0.
446
451
  # puts db.get_first_value( "select lengths(name) from A" )
447
452
  def create_aggregate_handler( handler )
448
453
  proxy = Class.new do
449
- def initialize handler
450
- @handler = handler
451
- @fp = FunctionProxy.new
454
+ def initialize klass
455
+ @klass = klass
456
+ @fp = FunctionProxy.new
452
457
  end
453
458
 
454
459
  def step( *args )
455
- @handler.step(@fp, *args)
460
+ instance.step(@fp, *args)
456
461
  end
457
462
 
458
463
  def finalize
459
- @handler.finalize @fp
464
+ instance.finalize @fp
465
+ @instance = nil
460
466
  @fp.result
461
467
  end
468
+
469
+ private
470
+
471
+ def instance
472
+ @instance ||= @klass.new
473
+ end
462
474
  end
463
- define_aggregator(handler.name, proxy.new(handler.new))
475
+ define_aggregator(handler.name, proxy.new(handler))
464
476
  self
465
477
  end
466
478