sqlite3 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -16,12 +16,15 @@ begin
16
16
  gem.add_development_dependency "test-unit", ">= 2.0"
17
17
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
18
18
  gem.post_install_message = <<-EOM
19
-
20
- WARNING!
21
-
19
+ ==== WARNING ===================================================================
22
20
  This is an early alpha version of SQLite3/Ruby FFI bindings!
23
- If you need native, production ready bindings install sqlite3-ruby instead.
21
+ Currently we support Ruby 1.9 ONLY.
22
+
23
+ If you need native bindings for Ruby 1.8 - install sqlite3-ruby instead.
24
+ You may need to uninstall this sqlite3 gem as well.
24
25
 
26
+ Thank you for installing sqlite3 gem! Suggestions: qoobaa@gmail.com
27
+ ================================================================================
25
28
  EOM
26
29
  end
27
30
  rescue LoadError
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.2
1
+ 0.0.3
@@ -1 +1,16 @@
1
+ # start (required by translator)
2
+ require "time"
3
+ require "date"
4
+ # end
5
+
6
+ require "ffi"
7
+
8
+ require "sqlite3/constants"
9
+ require "sqlite3/errors"
10
+ require "sqlite3/pragmas"
11
+ require "sqlite3/statement"
12
+ require "sqlite3/translator"
13
+ require "sqlite3/resultset"
14
+ require "sqlite3/value"
15
+ require "sqlite3/encoding"
1
16
  require "sqlite3/database"
@@ -1,10 +1,3 @@
1
- require "sqlite3/constants"
2
- require "sqlite3/errors"
3
- require "sqlite3/pragmas"
4
- require "sqlite3/statement"
5
- require "sqlite3/translator"
6
- require "sqlite3/value"
7
-
8
1
  module SQLite3
9
2
 
10
3
  # The Database class encapsulates a single connection to a SQLite3 database.
@@ -64,38 +57,41 @@ module SQLite3
64
57
  # database.
65
58
  attr_accessor :type_translation
66
59
 
60
+ # Encoding used to comunicate with database.
61
+ attr_reader :encoding
62
+
67
63
  # Create a new Database object that opens the given file. If utf16
68
64
  # is +true+, the filename is interpreted as a UTF-16 encoded string.
69
65
  #
70
66
  # By default, the new database will return result rows as arrays
71
67
  # (#results_as_hash) and has type translation disabled (#type_translation=).
72
68
  def initialize(file_name, options = {})
73
- utf16 = options.fetch(:utf16, false)
69
+ @encoding = Encoding.find(options.fetch(:encoding, "utf-8"))
70
+
74
71
  load_driver(options[:driver])
75
72
 
76
73
  @statement_factory = options[:statement_factory] || Statement
77
74
 
78
- result, @handle = @driver.open(file_name, utf16)
75
+ result, @handle = @driver.open(file_name, Encoding.utf_16?(@encoding))
79
76
  Error.check(result, self, "could not open database")
80
77
 
81
78
  @closed = false
82
- @results_as_hash = options.fetch(:results_as_hash,false)
83
- @type_translation = options.fetch(:type_translation,false)
79
+ @results_as_hash = options.fetch(:results_as_hash, false)
80
+ @type_translation = options.fetch(:type_translation, false)
84
81
  @translator = nil
85
82
  @transaction_active = false
86
83
  end
87
84
 
88
85
  # Return +true+ if the string is a valid (ie, parsable) SQL statement, and
89
- # +false+ otherwise. If +utf16+ is +true+, then the string is a UTF-16
90
- # character string.
91
- def complete?(string, utf16 = false)
92
- @driver.complete?(string, utf16)
86
+ # +false+ otherwise
87
+ def complete?(string)
88
+ @driver.complete?(string)
93
89
  end
94
90
 
95
91
  # Return a string describing the last error to have occurred with this
96
92
  # database.
97
- def errmsg(utf16 = false)
98
- @driver.errmsg(@handle, utf16)
93
+ def errmsg
94
+ @driver.errmsg(@handle)
99
95
  end
100
96
 
101
97
  # Return an integer representing the last error to have occurred with this
@@ -128,30 +124,13 @@ module SQLite3
128
124
  @closed
129
125
  end
130
126
 
131
- # Installs (or removes) a block that will be invoked for every SQL
132
- # statement executed. The block receives a two parameters: the +data+
133
- # argument, and the SQL statement executed. If the block is +nil+,
134
- # any existing tracer will be uninstalled.
135
- def trace(data = nil, &block)
136
- @driver.trace(@handle, data, &block)
137
- end
138
-
139
- # Installs (or removes) a block that will be invoked for every access
140
- # to the database. If the block returns 0 (or +nil+), the statement
141
- # is allowed to proceed. Returning 1 causes an authorization error to
142
- # occur, and returning 2 causes the access to be silently denied.
143
- def authorizer(data = nil, &block)
144
- result = @driver.set_authorizer(@handle, data, &block)
145
- Error.check(result, self)
146
- end
147
-
148
127
  # Returns a Statement object representing the given SQL. This does not
149
128
  # execute the statement; it merely prepares the statement for execution.
150
129
  #
151
130
  # The Statement can then be executed using Statement#execute.
152
131
  #
153
132
  def prepare(sql)
154
- stmt = @statement_factory.new(self, sql)
133
+ stmt = @statement_factory.new(self, sql, Encoding.utf_16?(@encoding))
155
134
  if block_given?
156
135
  begin
157
136
  yield stmt
@@ -296,20 +275,6 @@ module SQLite3
296
275
  @driver.interrupt(@handle)
297
276
  end
298
277
 
299
- # Register a busy handler with this database instance. When a requested
300
- # resource is busy, this handler will be invoked. If the handler returns
301
- # +false+, the operation will be aborted; otherwise, the resource will
302
- # be requested again.
303
- #
304
- # The handler will be invoked with the name of the resource that was
305
- # busy, and the number of times it has been retried.
306
- #
307
- # See also the mutually exclusive #busy_timeout.
308
- def busy_handler(data = nil, &block) # :yields: data, retries
309
- result = @driver.busy_handler(@handle, data, &block)
310
- Error.check(result, self)
311
- end
312
-
313
278
  # Indicates that if a request for a resource terminates because that
314
279
  # resource is busy, SQLite should sleep and retry for up to the indicated
315
280
  # number of milliseconds. By default, SQLite does not retry
@@ -322,210 +287,6 @@ module SQLite3
322
287
  Error.check(result, self)
323
288
  end
324
289
 
325
- # Creates a new function for use in SQL statements. It will be added as
326
- # +name+, with the given +arity+. (For variable arity functions, use
327
- # -1 for the arity.)
328
- #
329
- # The block should accept at least one parameter--the FunctionProxy
330
- # instance that wraps this function invocation--and any other
331
- # arguments it needs (up to its arity).
332
- #
333
- # The block does not return a value directly. Instead, it will invoke
334
- # the FunctionProxy#set_result method on the +func+ parameter and
335
- # indicate the return value that way.
336
- #
337
- # Example:
338
- #
339
- # db.create_function("maim", 1) do |func, value|
340
- # if value.nil?
341
- # func.result = nil
342
- # else
343
- # func.result = value.split(//).sort.join
344
- # end
345
- # end
346
- #
347
- # puts db.get_first_value("select maim(name) from table")
348
- def create_function(name, arity, text_rep = Constants::TextRep::ANY, &block) # :yields: func, *args
349
- # begin
350
- callback = proc do |func, *args|
351
- begin
352
- block.call(FunctionProxy.new(@driver, func), *args.map { |v| Value.new(self, v) })
353
- rescue StandardError, Exception => e
354
- @driver.result_error(func, "#{e.message} (#{e.class})", -1)
355
- end
356
- end
357
-
358
- result = @driver.create_function(@handle, name, arity, text_rep, nil, callback, nil, nil)
359
- Error.check(result, self)
360
-
361
- self
362
- end
363
-
364
- # Creates a new aggregate function for use in SQL statements. Aggregate
365
- # functions are functions that apply over every row in the result set,
366
- # instead of over just a single row. (A very common aggregate function
367
- # is the "count" function, for determining the number of rows that match
368
- # a query.)
369
- #
370
- # The new function will be added as +name+, with the given +arity+. (For
371
- # variable arity functions, use -1 for the arity.)
372
- #
373
- # The +step+ parameter must be a proc object that accepts as its first
374
- # parameter a FunctionProxy instance (representing the function
375
- # invocation), with any subsequent parameters (up to the function's arity).
376
- # The +step+ callback will be invoked once for each row of the result set.
377
- #
378
- # The +finalize+ parameter must be a +proc+ object that accepts only a
379
- # single parameter, the FunctionProxy instance representing the current
380
- # function invocation. It should invoke FunctionProxy#set_result to
381
- # store the result of the function.
382
- #
383
- # Example:
384
- #
385
- # db.create_aggregate("lengths", 1) do
386
- # step do |func, value|
387
- # func[:total] ||= 0
388
- # func[:total] += (value ? value.length : 0)
389
- # end
390
- #
391
- # finalize do |func|
392
- # func.set_result(func[:total] || 0)
393
- # end
394
- # end
395
- #
396
- # puts db.get_first_value("select lengths(name) from table")
397
- #
398
- # See also #create_aggregate_handler for a more object-oriented approach to
399
- # aggregate functions.
400
- def create_aggregate(name, arity, step = nil, finalize = nil, text_rep = Constants::TextRep::ANY, &block)
401
- # begin
402
- if block
403
- proxy = AggregateDefinitionProxy.new
404
- proxy.instance_eval(&block)
405
- step ||= proxy.step_callback
406
- finalize ||= proxy.finalize_callback
407
- end
408
-
409
- step_callback = proc do |func, *args|
410
- ctx = @driver.aggregate_context(func)
411
- unless ctx[:__error]
412
- begin
413
- step.call(FunctionProxy.new(@driver, func, ctx), *args.map { |v| Value.new(self, v) })
414
- rescue Exception => e
415
- ctx[:__error] = e
416
- end
417
- end
418
- end
419
-
420
- finalize_callback = proc do |func|
421
- ctx = @driver.aggregate_context(func)
422
- unless ctx[:__error]
423
- begin
424
- finalize.call(FunctionProxy.new(@driver, func, ctx))
425
- rescue Exception => e
426
- @driver.result_error(func, "#{e.message} (#{e.class})", -1)
427
- end
428
- else
429
- e = ctx[:__error]
430
- @driver.result_error(func, "#{e.message} (#{e.class})", -1)
431
- end
432
- end
433
-
434
- result = @driver.create_function(@handle, name, arity, text_rep, nil, nil, step_callback, finalize_callback)
435
- Error.check(result, self)
436
-
437
- self
438
- end
439
-
440
- # This is another approach to creating an aggregate function (see
441
- # #create_aggregate). Instead of explicitly specifying the name,
442
- # callbacks, arity, and type, you specify a factory object
443
- # (the "handler") that knows how to obtain all of that information. The
444
- # handler should respond to the following messages:
445
- #
446
- # +arity+:: corresponds to the +arity+ parameter of #create_aggregate. This
447
- # message is optional, and if the handler does not respond to it,
448
- # the function will have an arity of -1.
449
- # +name+:: this is the name of the function. The handler _must_ implement
450
- # this message.
451
- # +new+:: this must be implemented by the handler. It should return a new
452
- # instance of the object that will handle a specific invocation of
453
- # the function.
454
- #
455
- # The handler instance (the object returned by the +new+ message, described
456
- # above), must respond to the following messages:
457
- #
458
- # +step+:: this is the method that will be called for each step of the
459
- # aggregate function's evaluation. It should implement the same
460
- # signature as the +step+ callback for #create_aggregate.
461
- # +finalize+:: this is the method that will be called to finalize the
462
- # aggregate function's evaluation. It should implement the
463
- # same signature as the +finalize+ callback for
464
- # #create_aggregate.
465
- #
466
- # Example:
467
- #
468
- # class LengthsAggregateHandler
469
- # def self.arity; 1; end
470
- #
471
- # def initialize
472
- # @total = 0
473
- # end
474
- #
475
- # def step(ctx, name)
476
- # @total += (name ? name.length : 0)
477
- # end
478
- #
479
- # def finalize(ctx)
480
- # ctx.set_result(@total)
481
- # end
482
- # end
483
- #
484
- # db.create_aggregate_handler(LengthsAggregateHandler)
485
- # puts db.get_first_value("select lengths(name) from A")
486
- def create_aggregate_handler(handler)
487
- arity = -1
488
- text_rep = Constants::TextRep::ANY
489
-
490
- arity = handler.arity if handler.respond_to?(:arity)
491
- text_rep = handler.text_rep if handler.respond_to?(:text_rep)
492
- name = handler.name
493
-
494
- step = proc do |func,*args|
495
- ctx = @driver.aggregate_context(func)
496
- unless ctx[:__error]
497
- ctx[:handler] ||= handler.new
498
- begin
499
- ctx[:handler].step(FunctionProxy.new(@driver, func, ctx), *args.map{|v| Value.new(self,v)})
500
- rescue Exception, StandardError => e
501
- ctx[:__error] = e
502
- end
503
- end
504
- end
505
-
506
- finalize = proc do |func|
507
- ctx = @driver.aggregate_context(func)
508
- unless ctx[:__error]
509
- ctx[:handler] ||= handler.new
510
- begin
511
- ctx[:handler].finalize(FunctionProxy.new(@driver, func, ctx))
512
- rescue Exception => e
513
- ctx[:__error] = e
514
- end
515
- end
516
-
517
- if ctx[:__error]
518
- e = ctx[:__error]
519
- @driver.sqlite3_result_error(func, "#{e.message} (#{e.class})", -1)
520
- end
521
- end
522
-
523
- result = @driver.create_function(@handle, name, arity, text_rep, nil, nil, step, finalize)
524
- Error.check(result, self)
525
-
526
- self
527
- end
528
-
529
290
  # Begins a new transaction. Note that nested transactions are not allowed
530
291
  # by SQLite, so attempting to nest a transaction will result in a runtime
531
292
  # exception.
@@ -586,6 +347,8 @@ module SQLite3
586
347
  @transaction_active
587
348
  end
588
349
 
350
+ private
351
+
589
352
  # Loads the corresponding driver, or if it is nil, attempts to locate a
590
353
  # suitable driver.
591
354
  def load_driver(driver)
@@ -611,93 +374,7 @@ module SQLite3
611
374
 
612
375
  @driver = driver.new
613
376
  end
614
- private :load_driver
615
-
616
- # A helper class for dealing with custom functions (see #create_function,
617
- # #create_aggregate, and #create_aggregate_handler). It encapsulates the
618
- # opaque function object that represents the current invocation. It also
619
- # provides more convenient access to the API functions that operate on
620
- # the function object.
621
- #
622
- # This class will almost _always_ be instantiated indirectly, by working
623
- # with the create methods mentioned above.
624
- class FunctionProxy
625
-
626
- # Create a new FunctionProxy that encapsulates the given +func+ object.
627
- # If context is non-nil, the functions context will be set to that. If
628
- # it is non-nil, it must quack like a Hash. If it is nil, then none of
629
- # the context functions will be available.
630
- def initialize(driver, func, context = nil)
631
- @driver = driver
632
- @func = func
633
- @context = context
634
- end
635
-
636
- # Calls #set_result to set the result of this function.
637
- def result=(result)
638
- set_result(result)
639
- end
640
-
641
- # Set the result of the function to the given value. The function will
642
- # then return this value.
643
- def set_result(result, utf16 = false)
644
- @driver.result_text(@func, result, utf16)
645
- end
646
-
647
- # Set the result of the function to the given error message.
648
- # The function will then return that error.
649
- def set_error(error)
650
- @driver.result_error(@func, error.to_s, -1)
651
- end
652
-
653
- # (Only available to aggregate functions.) Returns the number of rows
654
- # that the aggregate has processed so far. This will include the current
655
- # row, and so will always return at least 1.
656
- def count
657
- ensure_aggregate!
658
- @driver.aggregate_count(@func)
659
- end
660
-
661
- # Returns the value with the given key from the context. This is only
662
- # available to aggregate functions.
663
- def [](key)
664
- ensure_aggregate!
665
- @context[key]
666
- end
667
-
668
- # Sets the value with the given key in the context. This is only
669
- # available to aggregate functions.
670
- def []=(key, value)
671
- ensure_aggregate!
672
- @context[key] = value
673
- end
674
-
675
- # A function for performing a sanity check, to ensure that the function
676
- # being invoked is an aggregate function. This is implied by the
677
- # existence of the context variable.
678
- def ensure_aggregate!
679
- unless @context
680
- raise MisuseException, "function is not an aggregate"
681
- end
682
- end
683
- private :ensure_aggregate!
684
-
685
- end
686
-
687
- # A proxy used for defining the callbacks to an aggregate function.
688
- class AggregateDefinitionProxy # :nodoc:
689
- attr_reader :step_callback, :finalize_callback
690
-
691
- def step(&block)
692
- @step_callback = block
693
- end
694
-
695
- def finalize(&block)
696
- @finalize_callback = block
697
- end
698
- end
699
377
 
700
378
  end
701
-
702
379
  end
703
380