sqlite3 1.3.5 → 1.3.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.rdoc +84 -0
- data/Gemfile +15 -0
- data/Manifest.txt +2 -0
- data/README.rdoc +29 -6
- data/ext/sqlite3/database.c +131 -27
- data/ext/sqlite3/extconf.rb +31 -7
- data/ext/sqlite3/sqlite3.c +112 -0
- data/ext/sqlite3/sqlite3_ruby.h +12 -4
- data/ext/sqlite3/statement.c +33 -22
- data/faq/faq.yml +1 -1
- data/lib/sqlite3.rb +6 -1
- data/lib/sqlite3/database.rb +36 -24
- data/lib/sqlite3/pragmas.rb +357 -49
- data/lib/sqlite3/resultset.rb +94 -25
- data/lib/sqlite3/statement.rb +13 -17
- data/lib/sqlite3/version.rb +2 -2
- data/setup.rb +2 -2
- data/tasks/gem.rake +12 -6
- data/tasks/native.rake +22 -7
- data/tasks/vendor_sqlite3.rake +69 -20
- data/test/helper.rb +17 -2
- data/test/test_backup.rb +2 -2
- data/test/test_collation.rb +1 -1
- data/test/test_database.rb +102 -7
- data/test/test_database_readonly.rb +10 -3
- data/test/test_deprecated.rb +8 -1
- data/test/test_encoding.rb +35 -1
- data/test/test_integration.rb +36 -15
- data/test/test_integration_open_close.rb +1 -1
- data/test/test_integration_pending.rb +2 -2
- data/test/test_integration_resultset.rb +6 -3
- data/test/test_integration_statement.rb +2 -2
- data/test/test_result_set.rb +37 -0
- data/test/test_sqlite3.rb +13 -1
- data/test/test_statement.rb +26 -4
- data/test/test_statement_execute.rb +1 -1
- metadata +125 -121
- data/.gemtest +0 -0
data/lib/sqlite3/resultset.rb
CHANGED
@@ -5,28 +5,66 @@ module SQLite3
|
|
5
5
|
|
6
6
|
# The ResultSet object encapsulates the enumerability of a query's output.
|
7
7
|
# It is a simple cursor over the data that the query returns. It will
|
8
|
-
# very rarely (if ever) be instantiated directly. Instead,
|
8
|
+
# very rarely (if ever) be instantiated directly. Instead, clients should
|
9
9
|
# obtain a ResultSet instance via Statement#execute.
|
10
10
|
class ResultSet
|
11
11
|
include Enumerable
|
12
12
|
|
13
|
-
|
14
|
-
# result. (ArrayFields is installed.)
|
15
|
-
class ArrayWithTypes < Array
|
13
|
+
class ArrayWithTypes < Array # :nodoc:
|
16
14
|
attr_accessor :types
|
17
15
|
end
|
18
16
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
17
|
+
class ArrayWithTypesAndFields < Array # :nodoc:
|
18
|
+
attr_writer :types
|
19
|
+
attr_writer :fields
|
20
|
+
|
21
|
+
def types
|
22
|
+
warn(<<-eowarn) if $VERBOSE
|
23
|
+
#{caller[0]} is calling #{self.class}#types. This method will be removed in
|
24
|
+
sqlite3 version 2.0.0, please call the `types` method on the SQLite3::ResultSet
|
25
|
+
object that created this object
|
26
|
+
eowarn
|
27
|
+
@types
|
28
|
+
end
|
29
|
+
|
30
|
+
def fields
|
31
|
+
warn(<<-eowarn) if $VERBOSE
|
32
|
+
#{caller[0]} is calling #{self.class}#fields. This method will be removed in
|
33
|
+
sqlite3 version 2.0.0, please call the `columns` method on the SQLite3::ResultSet
|
34
|
+
object that created this object
|
35
|
+
eowarn
|
36
|
+
@fields
|
37
|
+
end
|
24
38
|
end
|
25
39
|
|
26
40
|
# The class of which we return an object in case we want a Hash as
|
27
41
|
# result.
|
28
|
-
class
|
29
|
-
|
42
|
+
class HashWithTypesAndFields < Hash # :nodoc:
|
43
|
+
attr_writer :types
|
44
|
+
attr_writer :fields
|
45
|
+
|
46
|
+
def types
|
47
|
+
warn(<<-eowarn) if $VERBOSE
|
48
|
+
#{caller[0]} is calling #{self.class}#types. This method will be removed in
|
49
|
+
sqlite3 version 2.0.0, please call the `types` method on the SQLite3::ResultSet
|
50
|
+
object that created this object
|
51
|
+
eowarn
|
52
|
+
@types
|
53
|
+
end
|
54
|
+
|
55
|
+
def fields
|
56
|
+
warn(<<-eowarn) if $VERBOSE
|
57
|
+
#{caller[0]} is calling #{self.class}#fields. This method will be removed in
|
58
|
+
sqlite3 version 2.0.0, please call the `columns` method on the SQLite3::ResultSet
|
59
|
+
object that created this object
|
60
|
+
eowarn
|
61
|
+
@fields
|
62
|
+
end
|
63
|
+
|
64
|
+
def [] key
|
65
|
+
key = fields[key] if key.is_a? Numeric
|
66
|
+
super key
|
67
|
+
end
|
30
68
|
end
|
31
69
|
|
32
70
|
# Create a new ResultSet attached to the given database, using the
|
@@ -63,6 +101,10 @@ module SQLite3
|
|
63
101
|
# For hashes, the column names are the keys of the hash, and the column
|
64
102
|
# types are accessible via the +types+ property.
|
65
103
|
def next
|
104
|
+
if @db.results_as_hash
|
105
|
+
return next_hash
|
106
|
+
end
|
107
|
+
|
66
108
|
row = @stmt.step
|
67
109
|
return nil if @stmt.done?
|
68
110
|
|
@@ -72,33 +114,39 @@ module SQLite3
|
|
72
114
|
end
|
73
115
|
end
|
74
116
|
|
75
|
-
if
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
row = new_row
|
117
|
+
if row.respond_to?(:fields)
|
118
|
+
# FIXME: this can only happen if the translator returns something
|
119
|
+
# that responds to `fields`. Since we're removing the translator
|
120
|
+
# in 2.0, we can remove this branch in 2.0.
|
121
|
+
row = ArrayWithTypes.new(row)
|
81
122
|
else
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
end
|
87
|
-
row.fields = @stmt.columns
|
123
|
+
# FIXME: the `fields` and `types` methods are deprecated on this
|
124
|
+
# object for version 2.0, so we can safely remove this branch
|
125
|
+
# as well.
|
126
|
+
row = ArrayWithTypesAndFields.new(row)
|
88
127
|
end
|
89
128
|
|
129
|
+
row.fields = @stmt.columns
|
90
130
|
row.types = @stmt.types
|
91
131
|
row
|
92
132
|
end
|
93
133
|
|
94
134
|
# Required by the Enumerable mixin. Provides an internal iterator over the
|
95
135
|
# rows of the result set.
|
96
|
-
def each
|
136
|
+
def each
|
97
137
|
while node = self.next
|
98
138
|
yield node
|
99
139
|
end
|
100
140
|
end
|
101
141
|
|
142
|
+
# Provides an internal iterator over the rows of the result set where
|
143
|
+
# each row is yielded as a hash.
|
144
|
+
def each_hash
|
145
|
+
while node = next_hash
|
146
|
+
yield node
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
102
150
|
# Closes the statement that spawned this result set.
|
103
151
|
# <em>Use with caution!</em> Closing a result set will automatically
|
104
152
|
# close any other result sets that were spawned from the same statement.
|
@@ -121,6 +169,27 @@ module SQLite3
|
|
121
169
|
@stmt.columns
|
122
170
|
end
|
123
171
|
|
124
|
-
|
172
|
+
# Return the next row as a hash
|
173
|
+
def next_hash
|
174
|
+
row = @stmt.step
|
175
|
+
return nil if @stmt.done?
|
176
|
+
|
177
|
+
# FIXME: type translation is deprecated, so this can be removed
|
178
|
+
# in 2.0
|
179
|
+
if @db.type_translation
|
180
|
+
row = @stmt.types.zip(row).map do |type, value|
|
181
|
+
@db.translator.translate( type, value )
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
# FIXME: this can be switched to a regular hash in 2.0
|
186
|
+
row = HashWithTypesAndFields[*@stmt.columns.zip(row).flatten]
|
125
187
|
|
188
|
+
# FIXME: these methods are deprecated for version 2.0, so we can remove
|
189
|
+
# this code in 2.0
|
190
|
+
row.fields = @stmt.columns
|
191
|
+
row.types = @stmt.types
|
192
|
+
row
|
193
|
+
end
|
194
|
+
end
|
126
195
|
end
|
data/lib/sqlite3/statement.rb
CHANGED
@@ -120,23 +120,6 @@ module SQLite3
|
|
120
120
|
@types
|
121
121
|
end
|
122
122
|
|
123
|
-
# A convenience method for obtaining the metadata about the query. Note
|
124
|
-
# that this will actually execute the SQL, which means it can be a
|
125
|
-
# (potentially) expensive operation.
|
126
|
-
def get_metadata
|
127
|
-
@columns = []
|
128
|
-
@types = []
|
129
|
-
|
130
|
-
column_count.times do |column|
|
131
|
-
@columns << column_name(column)
|
132
|
-
@types << column_decltype(column)
|
133
|
-
end
|
134
|
-
|
135
|
-
@columns.freeze
|
136
|
-
@types.freeze
|
137
|
-
end
|
138
|
-
private :get_metadata
|
139
|
-
|
140
123
|
# Performs a sanity check to ensure that the statement is not
|
141
124
|
# closed. If it is, an exception is raised.
|
142
125
|
def must_be_open! # :nodoc:
|
@@ -144,5 +127,18 @@ module SQLite3
|
|
144
127
|
raise SQLite3::Exception, "cannot use a closed statement"
|
145
128
|
end
|
146
129
|
end
|
130
|
+
|
131
|
+
private
|
132
|
+
# A convenience method for obtaining the metadata about the query. Note
|
133
|
+
# that this will actually execute the SQL, which means it can be a
|
134
|
+
# (potentially) expensive operation.
|
135
|
+
def get_metadata
|
136
|
+
@columns = Array.new(column_count) do |column|
|
137
|
+
column_name column
|
138
|
+
end
|
139
|
+
@types = Array.new(column_count) do |column|
|
140
|
+
column_decltype column
|
141
|
+
end
|
142
|
+
end
|
147
143
|
end
|
148
144
|
end
|
data/lib/sqlite3/version.rb
CHANGED
data/setup.rb
CHANGED
@@ -102,7 +102,7 @@ end
|
|
102
102
|
|
103
103
|
class ConfigTable
|
104
104
|
|
105
|
-
c = ::
|
105
|
+
c = ::RbConfig::CONFIG
|
106
106
|
|
107
107
|
rubypath = c['bindir'] + '/' + c['ruby_install_name']
|
108
108
|
|
@@ -1219,7 +1219,7 @@ class Installer
|
|
1219
1219
|
raise InstallError, "no ruby extention exists: 'ruby #{$0} setup' first"
|
1220
1220
|
end
|
1221
1221
|
|
1222
|
-
DLEXT = /\.#{ ::
|
1222
|
+
DLEXT = /\.#{ ::RbConfig::CONFIG['DLEXT'] }\z/
|
1223
1223
|
|
1224
1224
|
def _ruby_extentions(dir)
|
1225
1225
|
Dir.open(dir) {|d|
|
data/tasks/gem.rake
CHANGED
@@ -6,23 +6,29 @@ rescue LoadError
|
|
6
6
|
require 'hoe'
|
7
7
|
end
|
8
8
|
|
9
|
-
Hoe.plugin :debugging, :doofus, :git
|
9
|
+
Hoe.plugin :debugging, :doofus, :git, :minitest, :bundler
|
10
10
|
|
11
11
|
HOE = Hoe.spec 'sqlite3' do
|
12
12
|
developer 'Jamis Buck', 'jamis@37signals.com'
|
13
13
|
developer 'Luis Lavena', 'luislavena@gmail.com'
|
14
14
|
developer 'Aaron Patterson', 'aaron@tenderlovemaking.com'
|
15
15
|
|
16
|
+
license "BSD-3"
|
17
|
+
|
16
18
|
self.readme_file = 'README.rdoc'
|
17
19
|
self.history_file = 'CHANGELOG.rdoc'
|
18
20
|
self.extra_rdoc_files = FileList['*.rdoc', 'ext/**/*.c']
|
19
21
|
|
20
|
-
|
21
|
-
|
22
|
-
|
22
|
+
require_ruby_version ">= 1.8.7"
|
23
|
+
require_rubygems_version ">= 1.3.5"
|
24
|
+
|
25
|
+
spec_extras[:extensions] = ["ext/sqlite3/extconf.rb"]
|
23
26
|
|
24
|
-
extra_dev_deps << ['rake-compiler', "~> 0.
|
25
|
-
extra_dev_deps << [
|
27
|
+
extra_dev_deps << ['rake-compiler', "~> 0.9.3"]
|
28
|
+
extra_dev_deps << ['rake-compiler-dock', "~> 0.5.2"]
|
29
|
+
extra_dev_deps << ["mini_portile", "~> 0.6.2"]
|
30
|
+
extra_dev_deps << ["minitest", "~> 5.0"]
|
31
|
+
extra_dev_deps << ["hoe-bundler", "~> 1.0"]
|
26
32
|
|
27
33
|
clean_globs.push('**/test.db')
|
28
34
|
end
|
data/tasks/native.rake
CHANGED
@@ -1,14 +1,24 @@
|
|
1
1
|
# use rake-compiler for building the extension
|
2
2
|
require 'rake/extensiontask'
|
3
|
+
require 'rake/extensioncompiler'
|
3
4
|
|
4
5
|
# NOTE: version used by cross compilation of Windows native extension
|
5
6
|
# It do not affect compilation under other operating systems
|
6
7
|
# The version indicated is the minimum DLL suggested for correct functionality
|
7
|
-
BINARY_VERSION = "3.
|
8
|
-
URL_VERSION = "
|
8
|
+
BINARY_VERSION = "3.8.11.1"
|
9
|
+
URL_VERSION = "3081101"
|
10
|
+
URL_PATH = "/2015"
|
11
|
+
|
12
|
+
task :devkit do
|
13
|
+
begin
|
14
|
+
require "devkit"
|
15
|
+
rescue LoadError => e
|
16
|
+
abort "Failed to activate RubyInstaller's DevKit required for compilation."
|
17
|
+
end
|
18
|
+
end
|
9
19
|
|
10
20
|
# build sqlite3_native C extension
|
11
|
-
Rake::ExtensionTask.new('sqlite3_native', HOE.spec) do |ext|
|
21
|
+
RUBY_EXTENSION = Rake::ExtensionTask.new('sqlite3_native', HOE.spec) do |ext|
|
12
22
|
# where to locate the extension
|
13
23
|
ext.ext_dir = 'ext/sqlite3'
|
14
24
|
|
@@ -23,11 +33,16 @@ Rake::ExtensionTask.new('sqlite3_native', HOE.spec) do |ext|
|
|
23
33
|
# define target for extension (supporting fat binaries)
|
24
34
|
RUBY_VERSION =~ /(\d+\.\d+)/
|
25
35
|
ext.lib_dir = "lib/sqlite3/#{$1}"
|
26
|
-
ext.config_options << "--enable-local"
|
27
36
|
else
|
28
|
-
|
29
|
-
|
30
|
-
|
37
|
+
|
38
|
+
# detect cross-compiler available
|
39
|
+
begin
|
40
|
+
Rake::ExtensionCompiler.mingw_host
|
41
|
+
ext.cross_compile = true
|
42
|
+
ext.cross_platform = ['i386-mswin32-60', 'i386-mingw32', 'x64-mingw32']
|
43
|
+
rescue RuntimeError
|
44
|
+
# noop
|
45
|
+
end
|
31
46
|
end
|
32
47
|
end
|
33
48
|
|
data/tasks/vendor_sqlite3.rake
CHANGED
@@ -2,47 +2,96 @@ require "rake/clean"
|
|
2
2
|
require "rake/extensioncompiler"
|
3
3
|
require "mini_portile"
|
4
4
|
|
5
|
-
|
5
|
+
CLOBBER.include("ports")
|
6
6
|
|
7
|
-
|
8
|
-
$recipes[:sqlite3].files << "http://sqlite.org/sqlite-autoconf-#{URL_VERSION}.tar.gz"
|
7
|
+
directory "ports"
|
9
8
|
|
10
|
-
|
11
|
-
|
9
|
+
def define_sqlite_task(platform, host)
|
10
|
+
recipe = MiniPortile.new "sqlite3", BINARY_VERSION
|
11
|
+
recipe.files << "http://sqlite.org#{URL_PATH}/sqlite-autoconf-#{URL_VERSION}.tar.gz"
|
12
|
+
recipe.host = host
|
12
13
|
|
13
|
-
desc "
|
14
|
-
task :sqlite3 => ["ports"] do |t|
|
15
|
-
recipe = $recipes[:sqlite3]
|
14
|
+
desc "Compile sqlite3 for #{platform} (#{host})"
|
15
|
+
task "ports:sqlite3:#{platform}" => ["ports"] do |t|
|
16
16
|
checkpoint = "ports/.#{recipe.name}-#{recipe.version}-#{recipe.host}.installed"
|
17
17
|
|
18
18
|
unless File.exist?(checkpoint)
|
19
19
|
cflags = "-O2 -DSQLITE_ENABLE_COLUMN_METADATA"
|
20
|
-
cflags << " -fPIC" if recipe.host.include?("x86_64")
|
20
|
+
cflags << " -fPIC" if recipe.host && recipe.host.include?("x86_64")
|
21
21
|
recipe.configure_options << "CFLAGS='#{cflags}'"
|
22
22
|
recipe.cook
|
23
23
|
touch checkpoint
|
24
24
|
end
|
25
|
-
|
26
|
-
recipe.activate
|
27
25
|
end
|
26
|
+
|
27
|
+
recipe
|
28
28
|
end
|
29
29
|
|
30
|
+
# native sqlite3 compilation
|
31
|
+
recipe = define_sqlite_task(RUBY_PLATFORM, RbConfig::CONFIG["host"])
|
32
|
+
|
33
|
+
# force compilation of sqlite3 when working natively under MinGW
|
30
34
|
if RUBY_PLATFORM =~ /mingw/
|
31
|
-
|
35
|
+
RUBY_EXTENSION.config_options << "--with-opt-dir=#{recipe.path}"
|
36
|
+
|
37
|
+
# also prepend DevKit into compilation phase
|
38
|
+
Rake::Task["compile"].prerequisites.unshift "devkit", "ports:sqlite3:#{RUBY_PLATFORM}"
|
39
|
+
Rake::Task["native"].prerequisites.unshift "devkit", "ports:sqlite3:#{RUBY_PLATFORM}"
|
32
40
|
end
|
33
41
|
|
42
|
+
# trick to test local compilation of sqlite3
|
34
43
|
if ENV["USE_MINI_PORTILE"] == "true"
|
35
|
-
|
44
|
+
# fake recipe so we can build a directory to it
|
45
|
+
recipe = MiniPortile.new "sqlite3", BINARY_VERSION
|
46
|
+
recipe.host = RbConfig::CONFIG["host"]
|
47
|
+
|
48
|
+
RUBY_EXTENSION.config_options << "--with-opt-dir=#{recipe.path}"
|
49
|
+
|
50
|
+
# compile sqlite3 first
|
51
|
+
Rake::Task["compile"].prerequisites.unshift "ports:sqlite3:#{RUBY_PLATFORM}"
|
36
52
|
end
|
37
53
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
54
|
+
# iterate over all cross-compilation platforms and define the proper
|
55
|
+
# sqlite3 recipe for it.
|
56
|
+
if RUBY_EXTENSION.cross_compile
|
57
|
+
config_path = File.expand_path("~/.rake-compiler/config.yml")
|
58
|
+
if File.exist?(config_path)
|
59
|
+
# obtains platforms from rake-compiler's config.yml
|
60
|
+
config_file = YAML.load_file(config_path)
|
61
|
+
|
62
|
+
Array(RUBY_EXTENSION.cross_platform).each do |platform|
|
63
|
+
# obtain platform from rbconfig file
|
64
|
+
config_key = config_file.keys.sort.find { |key|
|
65
|
+
key.start_with?("rbconfig-#{platform}-")
|
66
|
+
}
|
67
|
+
rbfile = config_file[config_key]
|
68
|
+
|
69
|
+
# skip if rbconfig cannot be read
|
70
|
+
next unless File.exist?(rbfile)
|
71
|
+
|
72
|
+
host = IO.read(rbfile).match(/CONFIG\["CC"\] = "(.*)"/)[1].sub(/\-gcc/, '')
|
73
|
+
recipe = define_sqlite_task(platform, host)
|
74
|
+
|
75
|
+
RUBY_EXTENSION.cross_config_options << {
|
76
|
+
platform => "--with-opt-dir=#{recipe.path}"
|
77
|
+
}
|
78
|
+
|
79
|
+
# pre-compile sqlite3 port when cross-compiling
|
80
|
+
task :cross => "ports:sqlite3:#{platform}"
|
81
|
+
end
|
82
|
+
else
|
83
|
+
warn "rake-compiler configuration doesn't exist, but is required for ports"
|
42
84
|
end
|
85
|
+
end
|
43
86
|
|
44
|
-
|
45
|
-
|
87
|
+
task :cross do
|
88
|
+
["CC", "CXX", "LDFLAGS", "CPPFLAGS", "RUBYOPT"].each do |var|
|
89
|
+
ENV.delete(var)
|
90
|
+
end
|
46
91
|
end
|
47
92
|
|
48
|
-
|
93
|
+
desc "Build windows binary gems per rake-compiler-dock."
|
94
|
+
task "gem:windows" do
|
95
|
+
require "rake_compiler_dock"
|
96
|
+
RakeCompilerDock.sh "bundle && rake cross native gem MAKE='nice make -j`nproc`'"
|
97
|
+
end
|