sqlite3 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -3,7 +3,7 @@
3
3
  Description goes here.
4
4
 
5
5
  == Note on Patches/Pull Requests
6
-
6
+
7
7
  * Fork the project.
8
8
  * Make your feature addition or bug fix.
9
9
  * Add tests for it. This is important so I don't break it in a
@@ -15,4 +15,4 @@ Description goes here.
15
15
 
16
16
  == Copyright
17
17
 
18
- Copyright (c) 2009 Jakub Kuźma. See LICENSE for details.
18
+ Copyright (c) 2010 Jakub Kuźma. See LICENSE for details.
data/Rakefile CHANGED
@@ -12,7 +12,7 @@ begin
12
12
  gem.email = "qoobaa@gmail.com"
13
13
  gem.homepage = "http://github.com/qoobaa/sqlite3"
14
14
  gem.authors = ["Jakub Kuźma"]
15
- gem.add_dependency "ffi", ">= 0.5.1"
15
+ gem.add_dependency "ffi", ">= 0.6.0"
16
16
  gem.add_development_dependency "test-unit", ">= 2.0"
17
17
  gem.add_development_dependency "activerecord", ">= 2.3.5"
18
18
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.7
1
+ 0.0.8
data/lib/sqlite3.rb CHANGED
@@ -1,6 +1,9 @@
1
1
  require "ffi"
2
2
 
3
+ require "sqlite3/api"
4
+ require "sqlite3/driver"
3
5
  require "sqlite3/constants"
6
+ require "sqlite3/extensions"
4
7
  require "sqlite3/errors"
5
8
  require "sqlite3/pragmas"
6
9
  require "sqlite3/statement"
@@ -0,0 +1,52 @@
1
+ module SQLite3
2
+ module API
3
+ extend FFI::Library
4
+
5
+ lib_paths = Array(ENV["SQLITE3_LIB"] || Dir["/{opt,usr}/{,local/}lib{,64}/libsqlite3.{dylib,so*}"])
6
+ fallback_names = ["libsqlite3", "sqlite3"]
7
+ ffi_lib(lib_paths + fallback_names)
8
+
9
+ attach_function :sqlite3_bind_blob, [:pointer, :int, :pointer, :int, :pointer], :int
10
+ attach_function :sqlite3_bind_double, [:pointer, :int, :double], :int
11
+ attach_function :sqlite3_bind_int, [:pointer, :int, :int], :int
12
+ attach_function :sqlite3_bind_int64, [:pointer, :int, :int64], :int
13
+ attach_function :sqlite3_bind_null, [:pointer, :int], :int
14
+ attach_function :sqlite3_bind_parameter_index, [:pointer, :string], :int
15
+ attach_function :sqlite3_bind_text, [:pointer, :int, :string, :int, :pointer], :int
16
+ attach_function :sqlite3_bind_text16, [:pointer, :int, :pointer, :int, :pointer], :int
17
+ attach_function :sqlite3_busy_timeout, [:pointer, :int], :int
18
+ attach_function :sqlite3_changes, [:pointer], :int
19
+ attach_function :sqlite3_close, [:pointer], :int
20
+ attach_function :sqlite3_column_blob, [:pointer, :int], :pointer
21
+ attach_function :sqlite3_column_bytes, [:pointer, :int], :int
22
+ attach_function :sqlite3_column_bytes16, [:pointer, :int], :int
23
+ attach_function :sqlite3_column_count, [:pointer], :int
24
+ attach_function :sqlite3_column_decltype, [:pointer, :int], :string
25
+ attach_function :sqlite3_column_double, [:pointer, :int], :double
26
+ attach_function :sqlite3_column_int64, [:pointer, :int], :int64
27
+ attach_function :sqlite3_column_name, [:pointer, :int], :string
28
+ attach_function :sqlite3_column_text, [:pointer, :int], :string
29
+ attach_function :sqlite3_column_text16, [:pointer, :int], :pointer
30
+ attach_function :sqlite3_column_type, [:pointer, :int], :int
31
+ attach_function :sqlite3_data_count, [:pointer], :int
32
+ attach_function :sqlite3_errcode, [:pointer], :int
33
+ attach_function :sqlite3_errmsg, [:pointer], :string
34
+ attach_function :sqlite3_errmsg16, [:pointer], :pointer
35
+ attach_function :sqlite3_finalize, [:pointer], :int
36
+ attach_function :sqlite3_last_insert_rowid, [:pointer], :int64
37
+ attach_function :sqlite3_libversion, [], :string
38
+ attach_function :sqlite3_open, [:string, :pointer], :int
39
+ attach_function :sqlite3_open16, [:pointer, :pointer], :int
40
+ attach_function :sqlite3_prepare, [:pointer, :string, :int, :pointer, :pointer], :int
41
+ attach_function :sqlite3_reset, [:pointer], :int
42
+ attach_function :sqlite3_step, [:pointer], :int
43
+
44
+ begin
45
+ attach_function :sqlite3_enable_load_extension, [:pointer, :int], :int
46
+ attach_function :sqlite3_load_extension, [:pointer, :string, :string, :string], :int
47
+ EXTENSION_SUPPORT = true
48
+ rescue FFI::NotFoundError
49
+ EXTENSION_SUPPORT = false
50
+ end
51
+ end
52
+ end
@@ -29,6 +29,7 @@ module SQLite3
29
29
  # hashes, then the results will all be indexible by field name.
30
30
  class Database
31
31
  include Pragmas
32
+ include Extensions
32
33
 
33
34
  class << self
34
35
 
@@ -64,7 +65,7 @@ module SQLite3
64
65
  def initialize(file_name, options = {})
65
66
  @encoding = Encoding.find(options.fetch(:encoding, "utf-8"))
66
67
 
67
- load_driver(options[:driver])
68
+ @driver = Driver.new
68
69
 
69
70
  @statement_factory = options[:statement_factory] || Statement
70
71
 
@@ -275,34 +276,5 @@ module SQLite3
275
276
  def transaction_active?
276
277
  @transaction_active
277
278
  end
278
-
279
- private
280
-
281
- # Loads the corresponding driver, or if it is nil, attempts to locate a
282
- # suitable driver.
283
- def load_driver(driver)
284
- case driver
285
- when Class
286
- # do nothing--use what was given
287
- when Symbol, String
288
- require "sqlite3/driver/#{driver.to_s.downcase}/driver"
289
- driver = SQLite3::Driver.const_get(driver)::Driver
290
- else
291
- ["FFI"].each do |d|
292
- begin
293
- require "sqlite3/driver/#{d.downcase}/driver"
294
- driver = SQLite3::Driver.const_get(d)::Driver
295
- break
296
- rescue SyntaxError
297
- raise
298
- rescue ScriptError, Exception, NameError
299
- end
300
- end
301
- raise "no driver for sqlite3 found" unless driver
302
- end
303
-
304
- @driver = driver.new
305
- end
306
-
307
279
  end
308
280
  end
@@ -0,0 +1,134 @@
1
+ module SQLite3
2
+ class Driver
3
+ TRANSIENT = FFI::Pointer.new(-1)
4
+
5
+ def open(filename, utf_16 = false)
6
+ handle = FFI::MemoryPointer.new(:pointer)
7
+ if utf_16
8
+ filename = filename.encode(Encoding.utf_16native)
9
+ result = API.sqlite3_open16(c_string(filename), handle)
10
+ else
11
+ filename = filename.encode(Encoding.utf_8)
12
+ result = API.sqlite3_open(filename, handle)
13
+ end
14
+ [result, handle.get_pointer(0)]
15
+ end
16
+
17
+ def errmsg(db, utf_16 = false)
18
+ if utf_16
19
+ ptr = API.sqlite3_errmsg16(db)
20
+ get_string_utf_16(ptr).force_encoding(Encoding.utf_16native)
21
+ else
22
+ API.sqlite3_errmsg(db).force_encoding(Encoding.utf_8)
23
+ end
24
+ end
25
+
26
+ def prepare(db, sql)
27
+ handle = FFI::MemoryPointer.new(:pointer)
28
+ remainder = FFI::MemoryPointer.new(:pointer)
29
+
30
+ if Encoding.utf_16?(sql)
31
+ str = c_string(sql)
32
+ result = API.sqlite3_prepare16(db, str, str.bytesize, handle, remainder)
33
+ remainder_string = get_string_utf_16(remainder.get_pointer(0))
34
+ else
35
+ result = API.sqlite3_prepare(db, sql, sql.bytesize, handle, remainder)
36
+ remainder_string = remainder.get_pointer(0).get_string(0)
37
+ end
38
+
39
+ [result, handle.get_pointer(0), remainder_string]
40
+ end
41
+
42
+ def bind_string(stmt, index, value)
43
+ case value.encoding
44
+ when Encoding.utf_8, Encoding.us_ascii
45
+ API.sqlite3_bind_text(stmt, index, value, value.bytesize, TRANSIENT)
46
+ when Encoding.utf_16le, Encoding.utf_16be
47
+ value = add_byte_order_mask(value)
48
+ API.sqlite3_bind_text16(stmt, index, value, value.bytesize, TRANSIENT)
49
+ else
50
+ API.sqlite3_bind_blob(stmt, index, value, value.bytesize, TRANSIENT)
51
+ end
52
+ end
53
+
54
+ def column_blob(stmt, column)
55
+ blob = API.sqlite3_column_blob(stmt, column)
56
+ length = API.sqlite3_column_bytes(stmt, column)
57
+ blob.get_bytes(0, length) # free?
58
+ end
59
+
60
+ def column_text(stmt, column, utf_16 = false)
61
+ if utf_16
62
+ ptr = API.sqlite3_column_text16(stmt, column)
63
+ length = API.sqlite3_column_bytes16(stmt, column)
64
+ ptr.get_bytes(0, length).force_encoding(Encoding.utf_16native) # free?
65
+ else
66
+ API.sqlite3_column_text(stmt, column).force_encoding(Encoding.utf_8)
67
+ end
68
+ end
69
+
70
+ def extension_support?
71
+ API::EXTENSION_SUPPORT
72
+ end
73
+
74
+ def load_extension(db, name, entry_point = nil)
75
+ result = API.sqlite3_load_extension(db, name, entry_point, nil)
76
+ [result, nil]
77
+ end
78
+
79
+ def enable_load_extension(db, onoff = false)
80
+ API.sqlite3_enable_load_extension(db, (onoff ? 1 : 0))
81
+ end
82
+
83
+ def self.api_delegate(name)
84
+ define_method(name) { |*args| API.send("sqlite3_#{name}", *args) }
85
+ end
86
+
87
+ api_delegate :bind_double
88
+ api_delegate :bind_int
89
+ api_delegate :bind_int64
90
+ api_delegate :bind_null
91
+ api_delegate :bind_parameter_index
92
+ api_delegate :busy_timeout
93
+ api_delegate :changes
94
+ api_delegate :close
95
+ api_delegate :column_count
96
+ api_delegate :column_decltype
97
+ api_delegate :column_double
98
+ api_delegate :column_int64
99
+ api_delegate :column_name
100
+ api_delegate :column_type
101
+ api_delegate :data_count
102
+ api_delegate :errcode
103
+ api_delegate :finalize
104
+ api_delegate :last_insert_rowid
105
+ api_delegate :libversion
106
+ api_delegate :reset
107
+ api_delegate :step
108
+
109
+ private
110
+
111
+ def c_string(string)
112
+ if Encoding.utf_16?(string)
113
+ result = add_byte_order_mask(string)
114
+ terminate_string!(result)
115
+ else
116
+ string # FFI does the job
117
+ end
118
+ end
119
+
120
+ def add_byte_order_mask(string)
121
+ "\uFEFF".encode(string.encoding) + string
122
+ end
123
+
124
+ def terminate_string!(string)
125
+ string << "\0\0".force_encoding(string.encoding)
126
+ end
127
+
128
+ def get_string_utf_16(ptr)
129
+ length = 0
130
+ length += 2 until ptr.get_bytes(length, 2) == "\0\0"
131
+ ptr.get_bytes(0, length)
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,27 @@
1
+ module SQLite3
2
+ module Extensions
3
+ def enable_load_extension(onoff=true)
4
+ must_support_extensions!
5
+ result = @driver.enable_load_extension(@handle, onoff)
6
+ Error.check(result, self)
7
+ end
8
+
9
+ def disable_load_extension
10
+ must_support_extensions!
11
+ result = @driver.enable_load_extension(@handle, false)
12
+ Error.check(result, self)
13
+ end
14
+
15
+ def load_extension(name, entry_point=nil)
16
+ must_support_extensions!
17
+ result, message = @driver.load_extension(@handle, name, entry_point)
18
+ Error.check(result, self, message)
19
+ end
20
+
21
+ private
22
+
23
+ def must_support_extensions!
24
+ raise SQLite3::Exception, "extensions API not supported" unless @driver.extension_support?
25
+ end
26
+ end
27
+ end
data/sqlite3.gemspec ADDED
@@ -0,0 +1,89 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{sqlite3}
8
+ s.version = "0.0.8"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Jakub Kuźma"]
12
+ s.date = %q{2010-02-09}
13
+ s.description = %q{SQLite3 FFI bindings for Ruby 1.9}
14
+ s.email = %q{qoobaa@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "lib/sqlite3.rb",
27
+ "lib/sqlite3/api.rb",
28
+ "lib/sqlite3/constants.rb",
29
+ "lib/sqlite3/database.rb",
30
+ "lib/sqlite3/driver.rb",
31
+ "lib/sqlite3/encoding.rb",
32
+ "lib/sqlite3/errors.rb",
33
+ "lib/sqlite3/extensions.rb",
34
+ "lib/sqlite3/pragmas.rb",
35
+ "lib/sqlite3/resultset.rb",
36
+ "lib/sqlite3/statement.rb",
37
+ "sqlite3.gemspec",
38
+ "test/fixtures/SQLite.gif",
39
+ "test/helper.rb",
40
+ "test/test_active_record.rb",
41
+ "test/test_database_initialization.rb",
42
+ "test/test_database_queries_utf_16.rb",
43
+ "test/test_database_queries_utf_8.rb",
44
+ "test/test_statement.rb"
45
+ ]
46
+ s.homepage = %q{http://github.com/qoobaa/sqlite3}
47
+ s.post_install_message = %q{==== WARNING ===================================================================
48
+ This is an early alpha version of SQLite3/Ruby FFI bindings!
49
+ Currently we support Ruby 1.9 ONLY.
50
+
51
+ If you need native bindings for Ruby 1.8 - install sqlite3-ruby instead.
52
+ You may need to uninstall this sqlite3 gem as well.
53
+
54
+ Thank you for installing sqlite3 gem! Suggestions: qoobaa@gmail.com
55
+ ================================================================================
56
+ }
57
+ s.rdoc_options = ["--charset=UTF-8"]
58
+ s.require_paths = ["lib"]
59
+ s.rubygems_version = %q{1.3.5}
60
+ s.summary = %q{SQLite3 FFI bindings for Ruby 1.9}
61
+ s.test_files = [
62
+ "test/test_database_queries_utf_8.rb",
63
+ "test/test_statement.rb",
64
+ "test/test_active_record.rb",
65
+ "test/test_database_queries_utf_16.rb",
66
+ "test/test_database_initialization.rb",
67
+ "test/helper.rb"
68
+ ]
69
+
70
+ if s.respond_to? :specification_version then
71
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
72
+ s.specification_version = 3
73
+
74
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
75
+ s.add_runtime_dependency(%q<ffi>, [">= 0.6.0"])
76
+ s.add_development_dependency(%q<test-unit>, [">= 2.0"])
77
+ s.add_development_dependency(%q<activerecord>, [">= 2.3.5"])
78
+ else
79
+ s.add_dependency(%q<ffi>, [">= 0.6.0"])
80
+ s.add_dependency(%q<test-unit>, [">= 2.0"])
81
+ s.add_dependency(%q<activerecord>, [">= 2.3.5"])
82
+ end
83
+ else
84
+ s.add_dependency(%q<ffi>, [">= 0.6.0"])
85
+ s.add_dependency(%q<test-unit>, [">= 2.0"])
86
+ s.add_dependency(%q<activerecord>, [">= 2.3.5"])
87
+ end
88
+ end
89
+
data/test/helper.rb CHANGED
@@ -7,5 +7,7 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
7
  require "sqlite3"
8
8
 
9
9
  class Test::Unit::TestCase
10
-
10
+ def fixture(filename)
11
+ File.join(File.dirname(__FILE__), "fixtures", filename)
12
+ end
11
13
  end
@@ -21,9 +21,7 @@ class CreateUsers < ActiveRecord::Migration
21
21
  end
22
22
  end
23
23
 
24
- class User < ActiveRecord::Base
25
-
26
- end
24
+ class User < ActiveRecord::Base; end
27
25
 
28
26
  class TestActiveRecord < Test::Unit::TestCase
29
27
  def setup
@@ -54,7 +52,7 @@ class TestActiveRecord < Test::Unit::TestCase
54
52
 
55
53
  def test_user_create
56
54
  login = "bob"
57
- avatar = open("test/fixtures/SQLite.gif", "rb").read
55
+ avatar = open(fixture("SQLite.gif"), "rb").read
58
56
  login_count = 0
59
57
  ranking = 1.0
60
58
  active = true
@@ -146,4 +144,15 @@ class TestActiveRecord < Test::Unit::TestCase
146
144
  user.save!
147
145
  assert_equal 1, User.count
148
146
  end
147
+
148
+ def test_attribute_assignment
149
+ user = User.new
150
+ avatar = open(fixture("SQLite.gif"), "rb").read
151
+ user.avatar = avatar
152
+ user.avatar = nil
153
+ user.save!
154
+ user.avatar = avatar
155
+ user.reload
156
+ assert_equal 1, User.count
157
+ end
149
158
  end
@@ -0,0 +1,42 @@
1
+ require "helper"
2
+
3
+ class TestStatement < Test::Unit::TestCase
4
+ def setup
5
+ @db = SQLite3::Database.new(":memory:")
6
+ @db.execute("CREATE TABLE t1(id INTEGER PRIMARY KEY ASC, t TEXT, nu1 NUMERIC, i1 INTEGER, i2 INTEGER, no BLOB)")
7
+ @statement = @db.prepare("INSERT INTO t1 VALUES(:ID, :T, :NU1, :I1, :I2, :NO)")
8
+ end
9
+
10
+ def teardown
11
+ @statement.close
12
+ @db.close
13
+ end
14
+
15
+ test "bind param by name" do
16
+ @statement.bind_param("T", "test")
17
+ end
18
+
19
+
20
+ test "bind param by name with colon" do
21
+ @statement.bind_param(":T", "test")
22
+ end
23
+
24
+ test "bind param by number" do
25
+ @statement.bind_param(1, "test")
26
+ end
27
+
28
+ test "bind non existing param name" do
29
+ assert_raises(SQLite3::Exception) { @statement.bind_param(":NONEXISTING", "test") }
30
+ end
31
+
32
+ test "execute statement" do
33
+ @statement.execute
34
+ end
35
+
36
+ test "execute statement multiple times" do
37
+ @statement.bind_param("T", "test")
38
+ @statement.execute
39
+ @statement.bind_param("NU1", 500)
40
+ @statement.execute
41
+ end
42
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sqlite3
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - "Jakub Ku\xC5\xBAma"
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-02-04 00:00:00 +01:00
12
+ date: 2010-02-09 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -20,7 +20,7 @@ dependencies:
20
20
  requirements:
21
21
  - - ">="
22
22
  - !ruby/object:Gem::Version
23
- version: 0.5.1
23
+ version: 0.6.0
24
24
  version:
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: test-unit
@@ -59,21 +59,24 @@ files:
59
59
  - Rakefile
60
60
  - VERSION
61
61
  - lib/sqlite3.rb
62
+ - lib/sqlite3/api.rb
62
63
  - lib/sqlite3/constants.rb
63
64
  - lib/sqlite3/database.rb
64
- - lib/sqlite3/driver/ffi/api.rb
65
- - lib/sqlite3/driver/ffi/driver.rb
65
+ - lib/sqlite3/driver.rb
66
66
  - lib/sqlite3/encoding.rb
67
67
  - lib/sqlite3/errors.rb
68
+ - lib/sqlite3/extensions.rb
68
69
  - lib/sqlite3/pragmas.rb
69
70
  - lib/sqlite3/resultset.rb
70
71
  - lib/sqlite3/statement.rb
72
+ - sqlite3.gemspec
71
73
  - test/fixtures/SQLite.gif
72
74
  - test/helper.rb
73
75
  - test/test_active_record.rb
74
76
  - test/test_database_initialization.rb
75
77
  - test/test_database_queries_utf_16.rb
76
78
  - test/test_database_queries_utf_8.rb
79
+ - test/test_statement.rb
77
80
  has_rdoc: true
78
81
  homepage: http://github.com/qoobaa/sqlite3
79
82
  licenses: []
@@ -114,6 +117,7 @@ specification_version: 3
114
117
  summary: SQLite3 FFI bindings for Ruby 1.9
115
118
  test_files:
116
119
  - test/test_database_queries_utf_8.rb
120
+ - test/test_statement.rb
117
121
  - test/test_active_record.rb
118
122
  - test/test_database_queries_utf_16.rb
119
123
  - test/test_database_initialization.rb
@@ -1,47 +0,0 @@
1
- module SQLite3
2
- module Driver
3
- module FFI
4
-
5
- module API
6
- extend ::FFI::Library
7
-
8
- # TODO: cleanup
9
- ffi_lib "libsqlite3.dylib", "libsqlite3.so" "sqlite3.dll"
10
-
11
- attach_function :sqlite3_libversion, [], :string
12
- attach_function :sqlite3_open, [:string, :pointer], :int
13
- attach_function :sqlite3_open16, [:pointer, :pointer], :int
14
- attach_function :sqlite3_close, [:pointer], :int
15
- attach_function :sqlite3_errmsg, [:pointer], :string
16
- attach_function :sqlite3_errmsg16, [:pointer], :pointer
17
- attach_function :sqlite3_errcode, [:pointer], :int
18
- attach_function :sqlite3_prepare, [:pointer, :string, :int, :pointer, :pointer], :int
19
- attach_function :sqlite3_finalize, [:pointer], :int
20
- attach_function :sqlite3_step, [:pointer], :int
21
- attach_function :sqlite3_last_insert_rowid, [:pointer], :int64
22
- attach_function :sqlite3_changes, [:pointer], :int
23
- attach_function :sqlite3_busy_timeout, [:pointer, :int], :int
24
- attach_function :sqlite3_bind_blob, [:pointer, :int, :pointer, :int, :pointer], :int
25
- attach_function :sqlite3_bind_double, [:pointer, :int, :double], :int
26
- attach_function :sqlite3_bind_int, [:pointer, :int, :int], :int
27
- attach_function :sqlite3_bind_int64, [:pointer, :int, :int64], :int
28
- attach_function :sqlite3_bind_null, [:pointer, :int], :int
29
- attach_function :sqlite3_bind_text, [:pointer, :int, :string, :int, :pointer], :int
30
- attach_function :sqlite3_bind_text16, [:pointer, :int, :pointer, :int, :pointer], :int
31
- attach_function :sqlite3_column_count, [:pointer], :int
32
- attach_function :sqlite3_data_count, [:pointer], :int
33
- attach_function :sqlite3_column_blob, [:pointer, :int], :pointer
34
- attach_function :sqlite3_column_bytes, [:pointer, :int], :int
35
- attach_function :sqlite3_column_bytes16, [:pointer, :int], :int
36
- attach_function :sqlite3_column_decltype, [:pointer, :int], :string
37
- attach_function :sqlite3_column_double, [:pointer, :int], :double
38
- attach_function :sqlite3_column_int64, [:pointer, :int], :int64
39
- attach_function :sqlite3_column_name, [:pointer, :int], :string
40
- attach_function :sqlite3_column_text, [:pointer, :int], :string
41
- attach_function :sqlite3_column_text16, [:pointer, :int], :pointer
42
- attach_function :sqlite3_column_type, [:pointer, :int], :int
43
- end
44
-
45
- end
46
- end
47
- end
@@ -1,128 +0,0 @@
1
- require 'sqlite3/driver/ffi/api'
2
-
3
- module SQLite3
4
- module Driver
5
- module FFI
6
-
7
- class Driver
8
- TRANSIENT = ::FFI::Pointer.new(-1)
9
-
10
- def open(filename, utf_16 = false)
11
- handle = ::FFI::MemoryPointer.new(:pointer)
12
- if utf_16
13
- filename = filename.encode(Encoding.utf_16native)
14
- result = API.sqlite3_open16(c_string(filename), handle)
15
- else
16
- filename = filename.encode(Encoding.utf_8)
17
- result = API.sqlite3_open(filename, handle)
18
- end
19
- [result, handle.get_pointer(0)]
20
- end
21
-
22
- def errmsg(db, utf_16 = false)
23
- if utf_16
24
- ptr = API.sqlite3_errmsg16(db)
25
- get_string_utf_16(ptr).force_encoding(Encoding.utf_16native)
26
- else
27
- API.sqlite3_errmsg(db).force_encoding(Encoding.utf_8)
28
- end
29
- end
30
-
31
- def prepare(db, sql)
32
- handle = ::FFI::MemoryPointer.new(:pointer)
33
- remainder = ::FFI::MemoryPointer.new(:pointer)
34
-
35
- if Encoding.utf_16?(sql)
36
- str = c_string(sql)
37
- result = API.sqlite3_prepare16(db, str, str.bytesize, handle, remainder)
38
- remainder_string = get_string_utf_16(remainder.get_pointer(0))
39
- else
40
- result = API.sqlite3_prepare(db, sql, sql.bytesize, handle, remainder)
41
- remainder_string = remainder.get_pointer(0).get_string(0)
42
- end
43
-
44
- [result, handle.get_pointer(0), remainder_string]
45
- end
46
-
47
- def bind_string(stmt, index, value)
48
- case value.encoding
49
- when Encoding.utf_8, Encoding.us_ascii
50
- API.sqlite3_bind_text(stmt, index, value, value.bytesize, TRANSIENT)
51
- when Encoding.utf_16le, Encoding.utf_16be
52
- value = add_byte_order_mask(value)
53
- API.sqlite3_bind_text16(stmt, index, value, value.bytesize, TRANSIENT)
54
- else
55
- API.sqlite3_bind_blob(stmt, index, value, value.bytesize, TRANSIENT)
56
- end
57
- end
58
-
59
- def column_blob(stmt, column)
60
- blob = API.sqlite3_column_blob(stmt, column)
61
- length = API.sqlite3_column_bytes(stmt, column)
62
- blob.get_bytes(0, length) # free?
63
- end
64
-
65
- def column_text(stmt, column, utf_16 = false)
66
- if utf_16
67
- ptr = API.sqlite3_column_text16(stmt, column)
68
- length = API.sqlite3_column_bytes16(stmt, column)
69
- ptr.get_bytes(0, length).force_encoding(Encoding.utf_16native) # free?
70
- else
71
- API.sqlite3_column_text(stmt, column).force_encoding(Encoding.utf_8)
72
- end
73
- end
74
-
75
- def self.api_delegate(name)
76
- define_method(name) { |*args| API.send("sqlite3_#{name}", *args) }
77
- end
78
-
79
- api_delegate :column_name
80
- api_delegate :column_decltype
81
- api_delegate :bind_double
82
- api_delegate :bind_int
83
- api_delegate :bind_int64
84
- api_delegate :bind_null
85
- api_delegate :bind_parameter_index
86
- api_delegate :bind_parameter_name
87
- api_delegate :busy_timeout
88
- api_delegate :changes
89
- api_delegate :close
90
- api_delegate :column_count
91
- api_delegate :column_double
92
- api_delegate :column_int64
93
- api_delegate :column_type
94
- api_delegate :data_count
95
- api_delegate :errcode
96
- api_delegate :finalize
97
- api_delegate :last_insert_rowid
98
- api_delegate :libversion
99
- api_delegate :step
100
-
101
- private
102
-
103
- def c_string(string)
104
- if Encoding.utf_16?(string)
105
- result = add_byte_order_mask(string)
106
- terminate_string!(result)
107
- else
108
- string # FFI does the job
109
- end
110
- end
111
-
112
- def add_byte_order_mask(string)
113
- "\uFEFF".encode(string.encoding) + string
114
- end
115
-
116
- def terminate_string!(string)
117
- string << "\0\0".force_encoding(string.encoding)
118
- end
119
-
120
- def get_string_utf_16(ptr)
121
- length = 0
122
- length += 2 until ptr.get_bytes(length, 2) == "\0\0"
123
- ptr.get_bytes(0, length)
124
- end
125
- end
126
- end
127
- end
128
- end