amalgalite 1.8.0-x64-mingw-ucrt
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CONTRIBUTING.md +60 -0
- data/HISTORY.md +386 -0
- data/LICENSE +31 -0
- data/Manifest.txt +105 -0
- data/README.md +62 -0
- data/Rakefile +27 -0
- data/TODO.md +57 -0
- data/bin/amalgalite-pack +147 -0
- data/examples/a.rb +9 -0
- data/examples/blob.rb +88 -0
- data/examples/bootstrap.rb +36 -0
- data/examples/define_aggregate.rb +75 -0
- data/examples/define_function.rb +104 -0
- data/examples/fts5.rb +152 -0
- data/examples/gem-db.rb +94 -0
- data/examples/require_me.rb +11 -0
- data/examples/requires.rb +42 -0
- data/examples/schema-info.rb +34 -0
- data/ext/amalgalite/c/amalgalite.c +355 -0
- data/ext/amalgalite/c/amalgalite.h +151 -0
- data/ext/amalgalite/c/amalgalite_blob.c +240 -0
- data/ext/amalgalite/c/amalgalite_constants.c +1432 -0
- data/ext/amalgalite/c/amalgalite_database.c +1188 -0
- data/ext/amalgalite/c/amalgalite_requires_bootstrap.c +282 -0
- data/ext/amalgalite/c/amalgalite_statement.c +649 -0
- data/ext/amalgalite/c/extconf.rb +71 -0
- data/ext/amalgalite/c/gen_constants.rb +353 -0
- data/ext/amalgalite/c/notes.txt +134 -0
- data/ext/amalgalite/c/sqlite3.c +243616 -0
- data/ext/amalgalite/c/sqlite3.h +12894 -0
- data/ext/amalgalite/c/sqlite3_options.h +4 -0
- data/ext/amalgalite/c/sqlite3ext.h +705 -0
- data/lib/amalgalite/3.1/amalgalite.so +0 -0
- data/lib/amalgalite/aggregate.rb +73 -0
- data/lib/amalgalite/blob.rb +186 -0
- data/lib/amalgalite/boolean.rb +42 -0
- data/lib/amalgalite/busy_timeout.rb +47 -0
- data/lib/amalgalite/column.rb +99 -0
- data/lib/amalgalite/core_ext/kernel/require.rb +21 -0
- data/lib/amalgalite/csv_table_importer.rb +75 -0
- data/lib/amalgalite/database.rb +933 -0
- data/lib/amalgalite/function.rb +61 -0
- data/lib/amalgalite/index.rb +43 -0
- data/lib/amalgalite/memory_database.rb +15 -0
- data/lib/amalgalite/packer.rb +231 -0
- data/lib/amalgalite/paths.rb +80 -0
- data/lib/amalgalite/profile_tap.rb +131 -0
- data/lib/amalgalite/progress_handler.rb +21 -0
- data/lib/amalgalite/requires.rb +151 -0
- data/lib/amalgalite/schema.rb +225 -0
- data/lib/amalgalite/sqlite3/constants.rb +95 -0
- data/lib/amalgalite/sqlite3/database/function.rb +48 -0
- data/lib/amalgalite/sqlite3/database/status.rb +68 -0
- data/lib/amalgalite/sqlite3/status.rb +60 -0
- data/lib/amalgalite/sqlite3/version.rb +55 -0
- data/lib/amalgalite/sqlite3.rb +6 -0
- data/lib/amalgalite/statement.rb +421 -0
- data/lib/amalgalite/table.rb +91 -0
- data/lib/amalgalite/taps/console.rb +27 -0
- data/lib/amalgalite/taps/io.rb +74 -0
- data/lib/amalgalite/taps.rb +2 -0
- data/lib/amalgalite/trace_tap.rb +35 -0
- data/lib/amalgalite/type_map.rb +63 -0
- data/lib/amalgalite/type_maps/default_map.rb +166 -0
- data/lib/amalgalite/type_maps/storage_map.rb +38 -0
- data/lib/amalgalite/type_maps/text_map.rb +21 -0
- data/lib/amalgalite/version.rb +8 -0
- data/lib/amalgalite/view.rb +26 -0
- data/lib/amalgalite.rb +51 -0
- data/spec/aggregate_spec.rb +158 -0
- data/spec/amalgalite_spec.rb +4 -0
- data/spec/blob_spec.rb +78 -0
- data/spec/boolean_spec.rb +24 -0
- data/spec/busy_handler.rb +157 -0
- data/spec/data/iso-3166-country.txt +242 -0
- data/spec/data/iso-3166-schema.sql +22 -0
- data/spec/data/iso-3166-subcountry.txt +3995 -0
- data/spec/data/make-iso-db.sh +12 -0
- data/spec/database_spec.rb +505 -0
- data/spec/default_map_spec.rb +92 -0
- data/spec/function_spec.rb +78 -0
- data/spec/integeration_spec.rb +97 -0
- data/spec/iso_3166_database.rb +58 -0
- data/spec/json_spec.rb +24 -0
- data/spec/packer_spec.rb +60 -0
- data/spec/paths_spec.rb +28 -0
- data/spec/progress_handler_spec.rb +91 -0
- data/spec/requires_spec.rb +54 -0
- data/spec/rtree_spec.rb +66 -0
- data/spec/schema_spec.rb +131 -0
- data/spec/spec_helper.rb +48 -0
- data/spec/sqlite3/constants_spec.rb +108 -0
- data/spec/sqlite3/database_status_spec.rb +36 -0
- data/spec/sqlite3/status_spec.rb +22 -0
- data/spec/sqlite3/version_spec.rb +28 -0
- data/spec/sqlite3_spec.rb +53 -0
- data/spec/statement_spec.rb +168 -0
- data/spec/storage_map_spec.rb +38 -0
- data/spec/tap_spec.rb +57 -0
- data/spec/text_map_spec.rb +20 -0
- data/spec/type_map_spec.rb +14 -0
- data/spec/version_spec.rb +8 -0
- data/tasks/custom.rake +101 -0
- data/tasks/default.rake +244 -0
- data/tasks/extension.rake +28 -0
- data/tasks/this.rb +208 -0
- metadata +325 -0
@@ -0,0 +1,151 @@
|
|
1
|
+
require 'amalgalite'
|
2
|
+
require 'pathname'
|
3
|
+
require 'zlib'
|
4
|
+
require 'amalgalite/packer'
|
5
|
+
|
6
|
+
module Amalgalite
|
7
|
+
#
|
8
|
+
# Requires encapsulates requiring items from the database
|
9
|
+
#
|
10
|
+
class Requires
|
11
|
+
class << self
|
12
|
+
def load_path_db_connections
|
13
|
+
@load_path_db_connections ||= {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def load_path
|
17
|
+
@load_path ||= []
|
18
|
+
end
|
19
|
+
|
20
|
+
#
|
21
|
+
# Allocate a database connection to the given filename. For
|
22
|
+
# file databases, this means giving the same connection
|
23
|
+
# back if you ask for a connection to the same file.
|
24
|
+
# For in-memory databases, you get a new one each time.
|
25
|
+
#
|
26
|
+
def db_connection_to( dbfile_name )
|
27
|
+
if dbfile_name == ":memory:"
|
28
|
+
return ::Amalgalite::Database.new( dbfile_name )
|
29
|
+
else
|
30
|
+
unless connection = load_path_db_connections[ dbfile_name ]
|
31
|
+
connection = ::Amalgalite::Database.new( dbfile_name )
|
32
|
+
load_path_db_connections[dbfile_name] = connection
|
33
|
+
end
|
34
|
+
return connection
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
#
|
39
|
+
# Setting a class level variable as a flag to know what we are currently
|
40
|
+
# in the middle of requiring
|
41
|
+
#
|
42
|
+
def requiring
|
43
|
+
@requiring ||= []
|
44
|
+
end
|
45
|
+
|
46
|
+
def require( filename )
|
47
|
+
if load_path.empty? then
|
48
|
+
raise ::LoadError, "Amalgalite load path is empty -- #{filename}"
|
49
|
+
elsif $LOADED_FEATURES.include?( filename ) then
|
50
|
+
return false
|
51
|
+
elsif Requires.requiring.include?( filename ) then
|
52
|
+
return false
|
53
|
+
else
|
54
|
+
Requires.requiring << filename
|
55
|
+
load_path.each do |lp|
|
56
|
+
if lp.require( filename ) then
|
57
|
+
Requires.requiring.delete( filename )
|
58
|
+
return true
|
59
|
+
end
|
60
|
+
end
|
61
|
+
Requires.requiring.delete( filename )
|
62
|
+
raise ::LoadError, "amalgalite has no such file to load -- #{filename}"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
attr_reader :dbfile_name
|
68
|
+
attr_reader :table_name
|
69
|
+
attr_reader :filename_column
|
70
|
+
attr_reader :contents_column
|
71
|
+
attr_reader :compressed_column
|
72
|
+
attr_reader :db_connection
|
73
|
+
|
74
|
+
def initialize( opts = {} )
|
75
|
+
@dbfile_name = opts[:dbfile_name] || Bootstrap::DEFAULT_DB
|
76
|
+
@table_name = opts[:table_name] || Bootstrap::DEFAULT_TABLE
|
77
|
+
@filename_column = opts[:filename_column] || Bootstrap::DEFAULT_FILENAME_COLUMN
|
78
|
+
@contents_column = opts[:contents_column] || Bootstrap::DEFAULT_CONTENTS_COLUMN
|
79
|
+
@compressed_column = opts[:compressed_column] || Bootstrap::DEFAULT_COMPRESSED_COLUMN
|
80
|
+
@db_connection = Requires.db_connection_to( dbfile_name )
|
81
|
+
Requires.load_path << self
|
82
|
+
end
|
83
|
+
|
84
|
+
#
|
85
|
+
# return the sql to find the file contents for a file in this requires
|
86
|
+
#
|
87
|
+
def sql
|
88
|
+
@sql ||= "SELECT #{filename_column}, #{compressed_column}, #{contents_column} FROM #{table_name} WHERE #{filename_column} = ?"
|
89
|
+
end
|
90
|
+
|
91
|
+
#
|
92
|
+
# load a file in this database table. This will check and see if the
|
93
|
+
# file is already required. If it isn't it will select the contents
|
94
|
+
# associated with the row identified by the filename and eval those contents
|
95
|
+
# within the context of TOPLEVEL_BINDING. The filename is then appended to
|
96
|
+
# $LOADED_FEATURES.
|
97
|
+
#
|
98
|
+
# if the file was required then true is returned, otherwise false
|
99
|
+
#
|
100
|
+
def require( filename )
|
101
|
+
if $LOADED_FEATURES.include?( filename ) then
|
102
|
+
return false
|
103
|
+
else
|
104
|
+
begin
|
105
|
+
filename = filename.gsub(/\.rb\Z/,'')
|
106
|
+
|
107
|
+
contents = file_contents(filename)
|
108
|
+
|
109
|
+
if contents
|
110
|
+
eval( contents, TOPLEVEL_BINDING, filename )
|
111
|
+
$LOADED_FEATURES << filename
|
112
|
+
return true
|
113
|
+
else
|
114
|
+
return false
|
115
|
+
end
|
116
|
+
rescue => e
|
117
|
+
raise ::LoadError, "Failure loading #{filename} from #{dbfile_name} : #{e}"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
#
|
123
|
+
# Return the contents of the named file.
|
124
|
+
#
|
125
|
+
def file_contents(filename)
|
126
|
+
rows = db_connection.execute(sql, filename)
|
127
|
+
if rows.size > 0 then
|
128
|
+
row = rows.first
|
129
|
+
|
130
|
+
contents = row[contents_column].to_s
|
131
|
+
if row[compressed_column] then
|
132
|
+
contents = ::Amalgalite::Packer.gunzip( contents )
|
133
|
+
end
|
134
|
+
|
135
|
+
return contents
|
136
|
+
else
|
137
|
+
return nil
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
|
142
|
+
#
|
143
|
+
# Import an SQL dump into the fake file system.
|
144
|
+
#
|
145
|
+
def import(sql)
|
146
|
+
db_connection.import(sql)
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
end
|
151
|
+
require 'amalgalite/core_ext/kernel/require'
|
@@ -0,0 +1,225 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2008 Jeremy Hinegardner
|
3
|
+
# All rights reserved. See LICENSE and/or COPYING for details.
|
4
|
+
#++
|
5
|
+
|
6
|
+
require 'amalgalite/table'
|
7
|
+
require 'amalgalite/index'
|
8
|
+
require 'amalgalite/column'
|
9
|
+
require 'amalgalite/view'
|
10
|
+
|
11
|
+
module Amalgalite
|
12
|
+
#
|
13
|
+
# An object view of the schema in the SQLite database. If the schema changes
|
14
|
+
# after this class is created, it has no knowledge of that.
|
15
|
+
#
|
16
|
+
class Schema
|
17
|
+
|
18
|
+
# The internal database that this schema is for. Most of the time this will
|
19
|
+
# be 'main' for the main database. For the temp tables, this will be 'temp'
|
20
|
+
# and for any attached databsae, this is the name of attached database.
|
21
|
+
attr_reader :catalog
|
22
|
+
|
23
|
+
# The schema_version at the time this schema was taken.
|
24
|
+
attr_reader :schema_version
|
25
|
+
|
26
|
+
# The Amalagalite::Database this schema is associated with.
|
27
|
+
attr_reader :db
|
28
|
+
|
29
|
+
#
|
30
|
+
# Create a new instance of Schema
|
31
|
+
#
|
32
|
+
def initialize( db, catalog = 'main', master_table = 'sqlite_master' )
|
33
|
+
@db = db
|
34
|
+
@catalog = catalog
|
35
|
+
@schema_version = nil
|
36
|
+
@tables = {}
|
37
|
+
@views = {}
|
38
|
+
@master_table = master_table
|
39
|
+
|
40
|
+
if @master_table == 'sqlite_master' then
|
41
|
+
@temp_schema = ::Amalgalite::Schema.new( db, 'temp', 'sqlite_temp_master')
|
42
|
+
else
|
43
|
+
@temp_schema = nil
|
44
|
+
end
|
45
|
+
load_schema!
|
46
|
+
end
|
47
|
+
|
48
|
+
def catalog_master_table
|
49
|
+
"#{catalog}.#{@master_table}"
|
50
|
+
end
|
51
|
+
|
52
|
+
def temporary?
|
53
|
+
catalog == "temp"
|
54
|
+
end
|
55
|
+
|
56
|
+
def dirty?()
|
57
|
+
return true if (@schema_version != self.current_version)
|
58
|
+
return false unless @temp_schema
|
59
|
+
return @temp_schema.dirty?
|
60
|
+
end
|
61
|
+
|
62
|
+
def current_version
|
63
|
+
@db.first_value_from("PRAGMA #{catalog}.schema_version")
|
64
|
+
end
|
65
|
+
|
66
|
+
#
|
67
|
+
# load the schema from the database
|
68
|
+
def load_schema!
|
69
|
+
load_tables
|
70
|
+
load_views
|
71
|
+
if @temp_schema then
|
72
|
+
@temp_schema.load_schema!
|
73
|
+
end
|
74
|
+
@schema_version = self.current_version
|
75
|
+
nil
|
76
|
+
end
|
77
|
+
|
78
|
+
##
|
79
|
+
# return the tables, reloading if dirty.
|
80
|
+
# If there is a temp table and a normal table with the same name, then the
|
81
|
+
# temp table is the one that is returned in the hash.
|
82
|
+
def tables
|
83
|
+
load_schema! if dirty?
|
84
|
+
t = @tables
|
85
|
+
if @temp_schema then
|
86
|
+
t = @tables.merge( @temp_schema.tables )
|
87
|
+
end
|
88
|
+
return t
|
89
|
+
end
|
90
|
+
|
91
|
+
##
|
92
|
+
# load all the tables
|
93
|
+
#
|
94
|
+
def load_tables
|
95
|
+
@tables = {}
|
96
|
+
@db.execute("SELECT tbl_name FROM #{catalog_master_table} WHERE type = 'table' AND name != 'sqlite_sequence'") do |table_info|
|
97
|
+
table = load_table( table_info['tbl_name'] )
|
98
|
+
table.indexes = load_indexes( table )
|
99
|
+
@tables[table.name] = table
|
100
|
+
end
|
101
|
+
return @tables
|
102
|
+
end
|
103
|
+
|
104
|
+
##
|
105
|
+
# Load a single table
|
106
|
+
def load_table( table_name )
|
107
|
+
rows = @db.execute("SELECT tbl_name, sql FROM #{catalog_master_table} WHERE type = 'table' AND tbl_name = ?", table_name)
|
108
|
+
table_info = rows.first
|
109
|
+
table = nil
|
110
|
+
if table_info then
|
111
|
+
table = Amalgalite::Table.new( table_info['tbl_name'], table_info['sql'] )
|
112
|
+
table.schema = self
|
113
|
+
table.columns = load_columns( table )
|
114
|
+
table.indexes = load_indexes( table )
|
115
|
+
@tables[table.name] = table
|
116
|
+
end
|
117
|
+
return table
|
118
|
+
end
|
119
|
+
|
120
|
+
##
|
121
|
+
# load all the indexes for a particular table
|
122
|
+
#
|
123
|
+
def load_indexes( table )
|
124
|
+
indexes = {}
|
125
|
+
|
126
|
+
@db.prepare("SELECT name, sql FROM #{catalog_master_table} WHERE type ='index' and tbl_name = $name") do |idx_stmt|
|
127
|
+
idx_stmt.execute( "$name" => table.name) do |idx_info|
|
128
|
+
indexes[idx_info['name']] = Amalgalite::Index.new( idx_info['name'], idx_info['sql'], table )
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
@db.execute("PRAGMA index_list( #{@db.quote(table.name)} );") do |idx_list|
|
133
|
+
idx = indexes[idx_list['name']]
|
134
|
+
|
135
|
+
# temporary indexes do not show up in the previous list
|
136
|
+
if idx.nil? then
|
137
|
+
idx = Amalgalite::Index.new( idx_list['name'], nil, table )
|
138
|
+
indexes[idx_list['name']] = idx
|
139
|
+
end
|
140
|
+
|
141
|
+
idx.sequence_number = idx_list['seq']
|
142
|
+
idx.unique = Boolean.to_bool( idx_list['unique'] )
|
143
|
+
|
144
|
+
@db.execute("PRAGMA index_info( #{@db.quote(idx.name)} );") do |col_info|
|
145
|
+
idx.columns << table.columns[col_info['name']]
|
146
|
+
end
|
147
|
+
end
|
148
|
+
return indexes
|
149
|
+
end
|
150
|
+
|
151
|
+
##
|
152
|
+
# load all the columns for a particular table
|
153
|
+
#
|
154
|
+
def load_columns( table )
|
155
|
+
cols = {}
|
156
|
+
idx = 0
|
157
|
+
@db.execute("PRAGMA #{catalog}.table_info(#{@db.quote(table.name)})") do |row|
|
158
|
+
col = Amalgalite::Column.new( catalog, table.name, row['name'], row['cid'])
|
159
|
+
|
160
|
+
col.default_value = row['dflt_value']
|
161
|
+
|
162
|
+
col.declared_data_type = row['type']
|
163
|
+
col.not_null_constraint = row['notnull']
|
164
|
+
col.primary_key = row['pk']
|
165
|
+
|
166
|
+
# need to remove leading and trailing ' or " from the default value
|
167
|
+
if col.default_value and col.default_value.kind_of?( String ) and ( col.default_value.length >= 2 ) then
|
168
|
+
fc = col.default_value[0].chr
|
169
|
+
lc = col.default_value[-1].chr
|
170
|
+
if fc == lc and ( fc == "'" || fc == '"' ) then
|
171
|
+
col.default_value = col.default_value[1..-2]
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
unless table.temporary? then
|
176
|
+
# get more exact information
|
177
|
+
@db.api.table_column_metadata( catalog, table.name, col.name ).each_pair do |key, value|
|
178
|
+
col.send("#{key}=", value)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
col.schema = self
|
182
|
+
cols[col.name] = col
|
183
|
+
idx += 1
|
184
|
+
end
|
185
|
+
return cols
|
186
|
+
end
|
187
|
+
|
188
|
+
##
|
189
|
+
# return the views, reloading if dirty
|
190
|
+
#
|
191
|
+
# If there is a temp view, and a regular view of the same name, then the
|
192
|
+
# temporary view is the one that is returned in the hash.
|
193
|
+
#
|
194
|
+
def views
|
195
|
+
reload_schema! if dirty?
|
196
|
+
v = @views
|
197
|
+
if @temp_schema then
|
198
|
+
v = @views.merge( @temp_schema.views )
|
199
|
+
end
|
200
|
+
return v
|
201
|
+
end
|
202
|
+
|
203
|
+
##
|
204
|
+
# load a single view
|
205
|
+
#
|
206
|
+
def load_view( name )
|
207
|
+
rows = @db.execute("SELECT name, sql FROM #{catalog_master_table} WHERE type = 'view' AND name = ?", name )
|
208
|
+
view_info = rows.first
|
209
|
+
view = Amalgalite::View.new( view_info['name'], view_info['sql'] )
|
210
|
+
view.schema = self
|
211
|
+
return view
|
212
|
+
end
|
213
|
+
|
214
|
+
##
|
215
|
+
# load all the views for the database
|
216
|
+
#
|
217
|
+
def load_views
|
218
|
+
@db.execute("SELECT name, sql FROM #{catalog_master_table} WHERE type = 'view'") do |view_info|
|
219
|
+
view = load_view( view_info['name'] )
|
220
|
+
@views[view.name] = view
|
221
|
+
end
|
222
|
+
return @views
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2008 Jeremy Hinegardner
|
3
|
+
# All rights reserved. See LICENSE and/or COPYING for details.
|
4
|
+
#++
|
5
|
+
module Amalgalite::SQLite3
|
6
|
+
module Constants
|
7
|
+
module Helpers
|
8
|
+
#
|
9
|
+
# convert an integer value into the string representation of the associated
|
10
|
+
# constant. this is a helper method used by some of the other modules
|
11
|
+
#
|
12
|
+
def name_from_value( value )
|
13
|
+
unless defined? @const_map_from_value
|
14
|
+
@const_map_from_value = {}
|
15
|
+
constants.each do |const_name|
|
16
|
+
c_int = const_get( const_name )
|
17
|
+
@const_map_from_value[c_int] = const_name.to_s
|
18
|
+
end
|
19
|
+
end
|
20
|
+
return @const_map_from_value[ value ]
|
21
|
+
end
|
22
|
+
|
23
|
+
#
|
24
|
+
# convert a string into the constant value. This is helper method used by
|
25
|
+
# some of the other modules
|
26
|
+
#
|
27
|
+
def value_from_name( name )
|
28
|
+
unless defined? @const_map_from_name
|
29
|
+
@const_map_from_name = {}
|
30
|
+
constants.each do |const_name|
|
31
|
+
c_int = const_get( const_name )
|
32
|
+
@const_map_from_name[ const_name.to_s ] = c_int
|
33
|
+
end
|
34
|
+
end
|
35
|
+
return @const_map_from_name[ name.upcase ]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
##
|
41
|
+
# DataType defines the namespace for all possible SQLite data types.
|
42
|
+
#
|
43
|
+
module DataType
|
44
|
+
extend Helpers
|
45
|
+
end
|
46
|
+
|
47
|
+
##
|
48
|
+
# Open defines the namespace for all possible flags to the Database.open
|
49
|
+
# method
|
50
|
+
#
|
51
|
+
module Open
|
52
|
+
extend Helpers
|
53
|
+
end
|
54
|
+
|
55
|
+
##
|
56
|
+
# Status defines the namespace for all the possible status flags for
|
57
|
+
# Amalgalite::SQLite3::Status objects
|
58
|
+
#
|
59
|
+
module Status
|
60
|
+
extend Helpers
|
61
|
+
end
|
62
|
+
|
63
|
+
##
|
64
|
+
# DBStatus defines the namespace for all the possible status codes for the
|
65
|
+
# Amalgalite::SQlite3::Database::Status objects.
|
66
|
+
#
|
67
|
+
module DBStatus
|
68
|
+
extend Helpers
|
69
|
+
end
|
70
|
+
|
71
|
+
##
|
72
|
+
# ResultCode defines the namespace for all possible result codes from an
|
73
|
+
# SQLite API call.
|
74
|
+
#
|
75
|
+
module ResultCode
|
76
|
+
extend Helpers
|
77
|
+
end # end ResultCode
|
78
|
+
|
79
|
+
##
|
80
|
+
# Config defines the namespace for all possible parameter for the
|
81
|
+
# sqlite config API.
|
82
|
+
#
|
83
|
+
module Config
|
84
|
+
extend Helpers
|
85
|
+
end
|
86
|
+
|
87
|
+
##
|
88
|
+
# StatementStatus defines the namespace for all the possible status codes
|
89
|
+
# for the SQLite prepared statements
|
90
|
+
#
|
91
|
+
module StatementStatus
|
92
|
+
extend Helpers
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Amalgalite::SQLite3
|
2
|
+
class Database
|
3
|
+
##
|
4
|
+
# A wrapper around a proc for use as an SQLite Ddatabase fuction
|
5
|
+
#
|
6
|
+
# f = Function.new( 'md5', lambda { |x| Digest::MD5.hexdigest( x.to_s ) } )
|
7
|
+
#
|
8
|
+
class Function
|
9
|
+
|
10
|
+
# the name of the function, and how it will be called in SQL
|
11
|
+
attr_reader :name
|
12
|
+
|
13
|
+
# The unique signature of this function. This is used to determin if the
|
14
|
+
# function is already registered or not
|
15
|
+
#
|
16
|
+
def self.signature( name, arity )
|
17
|
+
"#{name}/#{arity}"
|
18
|
+
end
|
19
|
+
|
20
|
+
# Initialize with the name and the Proc
|
21
|
+
#
|
22
|
+
def initialize( name, _proc )
|
23
|
+
@name = name
|
24
|
+
@function = _proc
|
25
|
+
end
|
26
|
+
|
27
|
+
# The unique signature of this function
|
28
|
+
#
|
29
|
+
def signature
|
30
|
+
@signature ||= Function.signature( name, arity )
|
31
|
+
end
|
32
|
+
alias :to_s :signature
|
33
|
+
|
34
|
+
# The arity of SQL function, -1 means it is takes a variable number of
|
35
|
+
# arguments.
|
36
|
+
#
|
37
|
+
def arity
|
38
|
+
@function.arity
|
39
|
+
end
|
40
|
+
|
41
|
+
# Invoke the proc
|
42
|
+
#
|
43
|
+
def call( *args )
|
44
|
+
@function.call( *args )
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'amalgalite/sqlite3/constants'
|
2
|
+
module Amalgalite::SQLite3
|
3
|
+
class Database
|
4
|
+
#
|
5
|
+
# A Stat represents a single Database Status code and its current highwater mark.
|
6
|
+
#
|
7
|
+
# Some stats may not have a current or a highwater value, in those cases
|
8
|
+
# the associated _has_current?_ or _has_highwater?_ method returns false and the
|
9
|
+
# _current_ or _highwater_ method also returns +nil+.
|
10
|
+
#
|
11
|
+
class Stat
|
12
|
+
attr_reader :name
|
13
|
+
attr_reader :code
|
14
|
+
|
15
|
+
def initialize( api_db, name )
|
16
|
+
@name = name
|
17
|
+
@code = ::Amalgalite::SQLite3::Constants::DBStatus.value_from_name( name )
|
18
|
+
@current = nil
|
19
|
+
@highwater = nil
|
20
|
+
@api_db = api_db
|
21
|
+
end
|
22
|
+
|
23
|
+
def current
|
24
|
+
update!
|
25
|
+
return @current
|
26
|
+
end
|
27
|
+
|
28
|
+
def highwater
|
29
|
+
update!
|
30
|
+
return @highwater
|
31
|
+
end
|
32
|
+
|
33
|
+
#
|
34
|
+
# reset the given stat's highwater mark. This will also populate the
|
35
|
+
# _@current_ and _@highwater_ instance variables
|
36
|
+
#
|
37
|
+
def reset!
|
38
|
+
update!( true )
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
#
|
43
|
+
# Top level Status object holding all the Stat objects indicating the DBStatus
|
44
|
+
# of the SQLite3 C library.
|
45
|
+
#
|
46
|
+
class DBStatus
|
47
|
+
::Amalgalite::SQLite3::Constants::DBStatus.constants.each do |const_name|
|
48
|
+
method_name = const_name.downcase
|
49
|
+
module_eval( <<-code, __FILE__, __LINE__ )
|
50
|
+
def #{method_name}
|
51
|
+
@#{method_name} ||= Amalgalite::SQLite3::Database::Stat.new( self.api_db, '#{method_name}' )
|
52
|
+
end
|
53
|
+
code
|
54
|
+
end
|
55
|
+
|
56
|
+
attr_reader :api_db
|
57
|
+
|
58
|
+
def initialize( api_db )
|
59
|
+
@api_db = api_db
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# return the DBstatus object for the sqlite database
|
64
|
+
def status
|
65
|
+
@status ||= DBStatus.new( self )
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'amalgalite/sqlite3/constants'
|
2
|
+
module Amalgalite::SQLite3
|
3
|
+
|
4
|
+
#
|
5
|
+
# A Stat represents a single Status code and its current highwater mark.
|
6
|
+
#
|
7
|
+
# Some stats may not have a current or a highwater value, in those cases
|
8
|
+
# the associated _has_current?_ or _has_highwater?_ method returns false and the
|
9
|
+
# _current_ or _highwater_ method also returns +nil+.
|
10
|
+
#
|
11
|
+
class Stat
|
12
|
+
attr_reader :name
|
13
|
+
attr_reader :code
|
14
|
+
|
15
|
+
def initialize( name )
|
16
|
+
@name = name
|
17
|
+
@code = ::Amalgalite::SQLite3::Constants::Status.value_from_name( name )
|
18
|
+
@current = nil
|
19
|
+
@highwater = nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def current
|
23
|
+
update!
|
24
|
+
return @current
|
25
|
+
end
|
26
|
+
|
27
|
+
def highwater
|
28
|
+
update!
|
29
|
+
return @highwater
|
30
|
+
end
|
31
|
+
|
32
|
+
#
|
33
|
+
# reset the given stat's highwater mark. This will also populate the
|
34
|
+
# _@current_ and _@highwater_ instance variables
|
35
|
+
#
|
36
|
+
def reset!
|
37
|
+
update!( true )
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
#
|
42
|
+
# Top level Status object holding all the Stat objects indicating the Status
|
43
|
+
# of the SQLite3 C library.
|
44
|
+
#
|
45
|
+
class Status
|
46
|
+
::Amalgalite::SQLite3::Constants::Status.constants.each do |const_name|
|
47
|
+
method_name = const_name.downcase
|
48
|
+
module_eval( <<-code, __FILE__, __LINE__ )
|
49
|
+
def #{method_name}
|
50
|
+
@#{method_name} ||= Amalgalite::SQLite3::Stat.new( '#{method_name}' )
|
51
|
+
end
|
52
|
+
code
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# return the status object for the sqlite database
|
57
|
+
def self.status
|
58
|
+
@status ||= Status.new
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2008 Jeremy Hinegardner
|
3
|
+
# All rights reserved. See LICENSE and/or COPYING for details.
|
4
|
+
#++
|
5
|
+
module Amalgalite
|
6
|
+
module SQLite3
|
7
|
+
module Version
|
8
|
+
# Sqlite3 version number is equal to
|
9
|
+
# MAJOR * 1_000_000 + MINOR * 1_000 + RELEASE
|
10
|
+
|
11
|
+
# major version number of the SQLite C library
|
12
|
+
MAJOR = (to_i / 1_000_000).freeze
|
13
|
+
|
14
|
+
# minor version number of the SQLite C library
|
15
|
+
MINOR = ((to_i % 1_000_000) / 1_000).freeze
|
16
|
+
|
17
|
+
# release version number of the SQLite C library
|
18
|
+
RELEASE = (to_i % 1_000).freeze
|
19
|
+
|
20
|
+
#
|
21
|
+
# call-seq:
|
22
|
+
# Amalgalite::SQLite3::Version.to_a -> [ MAJOR, MINOR, RELEASE ]
|
23
|
+
#
|
24
|
+
# Return the SQLite C library version number as an array of MAJOR, MINOR,
|
25
|
+
# RELEASE
|
26
|
+
#
|
27
|
+
def self.to_a
|
28
|
+
[ MAJOR, MINOR, RELEASE ]
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.compiled_matches_runtime?
|
32
|
+
self.compiled_version == self.runtime_version
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Version of SQLite that ships with Amalgalite
|
37
|
+
VERSION = Version.to_s.freeze
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
unless Amalgalite::SQLite3::Version.compiled_matches_runtime? then
|
42
|
+
warn <<eom
|
43
|
+
You are seeing something odd. The compiled version of SQLite that
|
44
|
+
is embedded in this extension is for some reason, not being used.
|
45
|
+
The version in the extension is #{Amalgalite::SQLite3::Version.compiled_version} and the version that
|
46
|
+
as been loaded as a shared library is #{Amalgalite::SQLite3::Version.runtime_version}. These versions
|
47
|
+
should be the same, but they are not.
|
48
|
+
|
49
|
+
One known issue is if you are using this libary in conjunction with
|
50
|
+
Hitimes on Mac OS X. You should make sure that "require 'amalgalite'"
|
51
|
+
appears before "require 'hitimes'" in your ruby code.
|
52
|
+
|
53
|
+
This is a non-trivial problem, and I am working on it.
|
54
|
+
eom
|
55
|
+
end
|