sqlite3 0.0.7 → 0.0.8

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/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