amalgalite 1.1.2-x86-mswin32 → 1.3.0-x86-mswin32
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.
- checksums.yaml +7 -0
- data/CONTRIBUTING.md +49 -0
- data/{HISTORY.rdoc → HISTORY.md} +96 -73
- data/LICENSE +2 -2
- data/Manifest.txt +104 -0
- data/README.md +73 -0
- data/Rakefile +25 -0
- data/TODO.md +50 -0
- data/ext/amalgalite/{amalgalite3.c → c/amalgalite.c} +12 -12
- data/ext/amalgalite/{amalgalite3.h → c/amalgalite.h} +5 -5
- data/ext/amalgalite/{amalgalite3_blob.c → c/amalgalite_blob.c} +2 -2
- data/ext/amalgalite/{amalgalite3_constants.c → c/amalgalite_constants.c} +2 -2
- data/ext/amalgalite/{amalgalite3_database.c → c/amalgalite_database.c} +49 -21
- data/ext/amalgalite/{amalgalite3_requires_bootstrap.c → c/amalgalite_requires_bootstrap.c} +131 -58
- data/ext/amalgalite/{amalgalite3_statement.c → c/amalgalite_statement.c} +2 -2
- data/ext/amalgalite/{extconf.rb → c/extconf.rb} +4 -4
- data/ext/amalgalite/{gen_constants.rb → c/gen_constants.rb} +3 -3
- data/ext/amalgalite/c/notes.txt +134 -0
- data/ext/amalgalite/{sqlite3.c → c/sqlite3.c} +94602 -80497
- data/ext/amalgalite/{sqlite3.h → c/sqlite3.h} +1047 -216
- data/ext/amalgalite/{sqlite3_options.h → c/sqlite3_options.h} +0 -0
- data/ext/amalgalite/{sqlite3ext.h → c/sqlite3ext.h} +40 -13
- data/lib/amalgalite.rb +13 -6
- data/lib/amalgalite/1.8/amalgalite.so +0 -0
- data/lib/amalgalite/1.9/amalgalite.so +0 -0
- data/lib/amalgalite/2.0/amalgalite.so +0 -0
- data/lib/amalgalite/column.rb +7 -5
- data/lib/amalgalite/database.rb +18 -10
- data/lib/amalgalite/packer.rb +5 -2
- data/lib/amalgalite/requires.rb +47 -16
- data/lib/amalgalite/schema.rb +63 -36
- data/lib/amalgalite/sqlite3/version.rb +0 -1
- data/lib/amalgalite/statement.rb +7 -5
- data/lib/amalgalite/table.rb +9 -8
- data/lib/amalgalite/type_maps/default_map.rb +0 -1
- data/lib/amalgalite/type_maps/storage_map.rb +0 -2
- data/lib/amalgalite/type_maps/text_map.rb +0 -1
- data/lib/amalgalite/version.rb +3 -32
- data/spec/aggregate_spec.rb +1 -1
- data/spec/amalgalite_spec.rb +1 -1
- data/spec/blob_spec.rb +1 -1
- data/spec/boolean_spec.rb +2 -1
- data/spec/busy_handler.rb +1 -1
- data/spec/database_spec.rb +16 -11
- data/spec/default_map_spec.rb +1 -1
- data/spec/function_spec.rb +1 -1
- data/spec/integeration_spec.rb +2 -1
- data/spec/packer_spec.rb +4 -4
- data/spec/paths_spec.rb +1 -1
- data/spec/progress_handler_spec.rb +4 -5
- data/spec/requires_spec.rb +36 -2
- data/spec/rtree_spec.rb +6 -5
- data/spec/schema_spec.rb +28 -20
- data/spec/spec_helper.rb +2 -7
- data/spec/sqlite3/constants_spec.rb +1 -1
- data/spec/sqlite3/database_status_spec.rb +4 -4
- data/spec/sqlite3/status_spec.rb +5 -5
- data/spec/sqlite3/version_spec.rb +7 -7
- data/spec/sqlite3_spec.rb +3 -3
- data/spec/statement_spec.rb +3 -4
- data/spec/storage_map_spec.rb +1 -1
- data/spec/tap_spec.rb +4 -4
- data/spec/text_map_spec.rb +1 -1
- data/spec/type_map_spec.rb +1 -1
- data/spec/version_spec.rb +2 -9
- data/tasks/custom.rake +99 -0
- data/tasks/default.rake +277 -0
- data/tasks/extension.rake +28 -202
- data/tasks/this.rb +209 -0
- metadata +102 -191
- data/README.rdoc +0 -54
- data/gemspec.rb +0 -63
- data/lib/amalgalite/1.8/amalgalite3.so +0 -0
- data/lib/amalgalite/1.9/amalgalite3.so +0 -0
- data/tasks/announce.rake +0 -44
- data/tasks/config.rb +0 -107
- data/tasks/distribution.rake +0 -77
- data/tasks/documentation.rake +0 -36
- data/tasks/rspec.rake +0 -30
- data/tasks/utils.rb +0 -80
File without changes
|
@@ -49,8 +49,10 @@ struct sqlite3_api_routines {
|
|
49
49
|
int (*busy_timeout)(sqlite3*,int ms);
|
50
50
|
int (*changes)(sqlite3*);
|
51
51
|
int (*close)(sqlite3*);
|
52
|
-
int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*,
|
53
|
-
|
52
|
+
int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*,
|
53
|
+
int eTextRep,const char*));
|
54
|
+
int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*,
|
55
|
+
int eTextRep,const void*));
|
54
56
|
const void * (*column_blob)(sqlite3_stmt*,int iCol);
|
55
57
|
int (*column_bytes)(sqlite3_stmt*,int iCol);
|
56
58
|
int (*column_bytes16)(sqlite3_stmt*,int iCol);
|
@@ -75,10 +77,18 @@ struct sqlite3_api_routines {
|
|
75
77
|
void * (*commit_hook)(sqlite3*,int(*)(void*),void*);
|
76
78
|
int (*complete)(const char*sql);
|
77
79
|
int (*complete16)(const void*sql);
|
78
|
-
int (*create_collation)(sqlite3*,const char*,int,void*,
|
79
|
-
|
80
|
-
int (*
|
81
|
-
|
80
|
+
int (*create_collation)(sqlite3*,const char*,int,void*,
|
81
|
+
int(*)(void*,int,const void*,int,const void*));
|
82
|
+
int (*create_collation16)(sqlite3*,const void*,int,void*,
|
83
|
+
int(*)(void*,int,const void*,int,const void*));
|
84
|
+
int (*create_function)(sqlite3*,const char*,int,int,void*,
|
85
|
+
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
|
86
|
+
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
87
|
+
void (*xFinal)(sqlite3_context*));
|
88
|
+
int (*create_function16)(sqlite3*,const void*,int,int,void*,
|
89
|
+
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
|
90
|
+
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
91
|
+
void (*xFinal)(sqlite3_context*));
|
82
92
|
int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*);
|
83
93
|
int (*data_count)(sqlite3_stmt*pStmt);
|
84
94
|
sqlite3 * (*db_handle)(sqlite3_stmt*);
|
@@ -123,16 +133,19 @@ struct sqlite3_api_routines {
|
|
123
133
|
void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*));
|
124
134
|
void (*result_value)(sqlite3_context*,sqlite3_value*);
|
125
135
|
void * (*rollback_hook)(sqlite3*,void(*)(void*),void*);
|
126
|
-
int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
|
136
|
+
int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
|
137
|
+
const char*,const char*),void*);
|
127
138
|
void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
|
128
139
|
char * (*snprintf)(int,char*,const char*,...);
|
129
140
|
int (*step)(sqlite3_stmt*);
|
130
|
-
int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
|
141
|
+
int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
|
142
|
+
char const**,char const**,int*,int*,int*);
|
131
143
|
void (*thread_cleanup)(void);
|
132
144
|
int (*total_changes)(sqlite3*);
|
133
145
|
void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*);
|
134
146
|
int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*);
|
135
|
-
void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,
|
147
|
+
void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,
|
148
|
+
sqlite_int64),void*);
|
136
149
|
void * (*user_data)(sqlite3_context*);
|
137
150
|
const void * (*value_blob)(sqlite3_value*);
|
138
151
|
int (*value_bytes)(sqlite3_value*);
|
@@ -154,15 +167,19 @@ struct sqlite3_api_routines {
|
|
154
167
|
int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
|
155
168
|
int (*clear_bindings)(sqlite3_stmt*);
|
156
169
|
/* Added by 3.4.1 */
|
157
|
-
int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*,
|
170
|
+
int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*,
|
171
|
+
void (*xDestroy)(void *));
|
158
172
|
/* Added by 3.5.0 */
|
159
173
|
int (*bind_zeroblob)(sqlite3_stmt*,int,int);
|
160
174
|
int (*blob_bytes)(sqlite3_blob*);
|
161
175
|
int (*blob_close)(sqlite3_blob*);
|
162
|
-
int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64,
|
176
|
+
int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64,
|
177
|
+
int,sqlite3_blob**);
|
163
178
|
int (*blob_read)(sqlite3_blob*,void*,int,int);
|
164
179
|
int (*blob_write)(sqlite3_blob*,const void*,int,int);
|
165
|
-
int (*create_collation_v2)(sqlite3*,const char*,int,void*,
|
180
|
+
int (*create_collation_v2)(sqlite3*,const char*,int,void*,
|
181
|
+
int(*)(void*,int,const void*,int,const void*),
|
182
|
+
void(*)(void*));
|
166
183
|
int (*file_control)(sqlite3*,const char*,int,void*);
|
167
184
|
sqlite3_int64 (*memory_highwater)(int);
|
168
185
|
sqlite3_int64 (*memory_used)(void);
|
@@ -198,7 +215,11 @@ struct sqlite3_api_routines {
|
|
198
215
|
int (*backup_step)(sqlite3_backup*,int);
|
199
216
|
const char *(*compileoption_get)(int);
|
200
217
|
int (*compileoption_used)(const char*);
|
201
|
-
int (*create_function_v2)(sqlite3*,const char*,int,int,void*,
|
218
|
+
int (*create_function_v2)(sqlite3*,const char*,int,int,void*,
|
219
|
+
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
|
220
|
+
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
221
|
+
void (*xFinal)(sqlite3_context*),
|
222
|
+
void(*xDestroy)(void*));
|
202
223
|
int (*db_config)(sqlite3*,int,...);
|
203
224
|
sqlite3_mutex *(*db_mutex)(sqlite3*);
|
204
225
|
int (*db_status)(sqlite3*,int,int*,int*,int);
|
@@ -212,6 +233,9 @@ struct sqlite3_api_routines {
|
|
212
233
|
int (*wal_autocheckpoint)(sqlite3*,int);
|
213
234
|
int (*wal_checkpoint)(sqlite3*,const char*);
|
214
235
|
void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*);
|
236
|
+
int (*blob_reopen)(sqlite3_blob*,sqlite3_int64);
|
237
|
+
int (*vtab_config)(sqlite3*,int op,...);
|
238
|
+
int (*vtab_on_conflict)(sqlite3*);
|
215
239
|
};
|
216
240
|
|
217
241
|
/*
|
@@ -412,6 +436,9 @@ struct sqlite3_api_routines {
|
|
412
436
|
#define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint
|
413
437
|
#define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint
|
414
438
|
#define sqlite3_wal_hook sqlite3_api->wal_hook
|
439
|
+
#define sqlite3_blob_reopen sqlite3_api->blob_reopen
|
440
|
+
#define sqlite3_vtab_config sqlite3_api->vtab_config
|
441
|
+
#define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict
|
415
442
|
#endif /* SQLITE_CORE */
|
416
443
|
|
417
444
|
#define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api = 0;
|
data/lib/amalgalite.rb
CHANGED
@@ -5,8 +5,8 @@
|
|
5
5
|
|
6
6
|
# check if sqlite3 has already been required. Amalgalite conflicts with system
|
7
7
|
# level sqlite3 libraries.
|
8
|
-
unless $LOADED_FEATURES.grep( /
|
9
|
-
raise LoadError, "amalgalite conflicts with sqlite3
|
8
|
+
unless $LOADED_FEATURES.grep( /\Asqlite3/ ).empty? then
|
9
|
+
raise LoadError, "amalgalite conflicts with sqlite3, please choose one or the other."
|
10
10
|
end
|
11
11
|
|
12
12
|
module Amalgalite
|
@@ -16,10 +16,17 @@ module Amalgalite
|
|
16
16
|
class Error < ::StandardError; end
|
17
17
|
end
|
18
18
|
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
|
19
|
+
# Load the binary extension, try loading one for the specific version of ruby
|
20
|
+
# and if that fails, then fall back to one in the top of the library.
|
21
|
+
# this is the method recommended by rake-compiler
|
22
|
+
begin
|
23
|
+
# this will be for windows
|
24
|
+
require "amalgalite/#{RUBY_VERSION.sub(/\.\d$/,'')}/amalgalite"
|
25
|
+
rescue LoadError
|
26
|
+
# everyone else.
|
27
|
+
require 'amalgalite/amalgalite'
|
28
|
+
end
|
29
|
+
|
23
30
|
|
24
31
|
require 'amalgalite/aggregate'
|
25
32
|
require 'amalgalite/blob'
|
Binary file
|
Binary file
|
Binary file
|
data/lib/amalgalite/column.rb
CHANGED
@@ -16,15 +16,17 @@ module Amalgalite
|
|
16
16
|
# the schema object this column is associated with
|
17
17
|
attr_accessor :schema
|
18
18
|
|
19
|
-
# the database name this column belongs to
|
19
|
+
# the database name this column belongs to. This will be 'main' for the main
|
20
|
+
# database, 'temp' for the temp database and whatever an attached database
|
21
|
+
# was attached as.
|
20
22
|
attr_accessor :db
|
21
23
|
|
22
|
-
# the column name
|
23
|
-
attr_accessor :name
|
24
|
-
|
25
24
|
# the table to which this column belongs
|
26
25
|
attr_accessor :table
|
27
26
|
|
27
|
+
# the column name
|
28
|
+
attr_accessor :name
|
29
|
+
|
28
30
|
# the default value of the column. This may not have a value and that
|
29
31
|
# either means that there is no default value, or one could not be
|
30
32
|
# determined.
|
@@ -47,8 +49,8 @@ module Amalgalite
|
|
47
49
|
#
|
48
50
|
def initialize( db, table, name, order)
|
49
51
|
@db = db
|
50
|
-
@name = name
|
51
52
|
@table = table
|
53
|
+
@name = name
|
52
54
|
@order = Float(order).to_i
|
53
55
|
@declared_data_type = nil
|
54
56
|
@default_value = nil
|
data/lib/amalgalite/database.rb
CHANGED
@@ -326,6 +326,14 @@ module Amalgalite
|
|
326
326
|
return count
|
327
327
|
end
|
328
328
|
|
329
|
+
##
|
330
|
+
# Execute a batch of statements via sqlite3_exec. This does the same as
|
331
|
+
# execute_batch, but doesn't update the statement statistics.
|
332
|
+
#
|
333
|
+
def import(sql)
|
334
|
+
@api.execute_batch(sql)
|
335
|
+
end
|
336
|
+
|
329
337
|
##
|
330
338
|
# clear all the current taps
|
331
339
|
#
|
@@ -486,11 +494,11 @@ module Amalgalite
|
|
486
494
|
##
|
487
495
|
# :call-seq:
|
488
496
|
# db.schema( dbname = "main" ) -> Schema
|
489
|
-
#
|
490
|
-
# Returns a Schema object
|
497
|
+
#
|
498
|
+
# Returns a Schema object containing the table and column structure of the
|
491
499
|
# database.
|
492
500
|
#
|
493
|
-
def schema( dbname = "main" )
|
501
|
+
def schema( dbname = "main" )
|
494
502
|
@schema ||= ::Amalgalite::Schema.new( self, dbname )
|
495
503
|
if @schema and @schema.dirty?
|
496
504
|
reload_schema!( dbname )
|
@@ -512,7 +520,7 @@ module Amalgalite
|
|
512
520
|
|
513
521
|
##
|
514
522
|
# Run a pragma command against the database
|
515
|
-
#
|
523
|
+
#
|
516
524
|
# Returns the result set of the pragma
|
517
525
|
def pragma( cmd, &block )
|
518
526
|
execute("PRAGMA #{cmd}", &block)
|
@@ -741,9 +749,9 @@ module Amalgalite
|
|
741
749
|
to_remove = possibles
|
742
750
|
end
|
743
751
|
|
744
|
-
to_remove.each do |
|
745
|
-
@api.remove_function(
|
746
|
-
@functions.delete(
|
752
|
+
to_remove.each do |db_func|
|
753
|
+
@api.remove_function( db_func.name, db_func)
|
754
|
+
@functions.delete( db_func.signature )
|
747
755
|
end
|
748
756
|
end
|
749
757
|
|
@@ -802,9 +810,9 @@ module Amalgalite
|
|
802
810
|
to_remove = possibles
|
803
811
|
end
|
804
812
|
|
805
|
-
to_remove.each do |
|
806
|
-
i =
|
807
|
-
@api.remove_aggregate( i.name, i.arity,
|
813
|
+
to_remove.each do |db_agg|
|
814
|
+
i = db_agg.new
|
815
|
+
@api.remove_aggregate( i.name, i.arity, db_agg)
|
808
816
|
@aggregates.delete( i.signature )
|
809
817
|
end
|
810
818
|
end
|
data/lib/amalgalite/packer.rb
CHANGED
@@ -105,7 +105,7 @@ module Amalgalite
|
|
105
105
|
# The SQL to create the table for storing ruby code
|
106
106
|
#
|
107
107
|
def create_table_sql
|
108
|
-
|
108
|
+
<<-create
|
109
109
|
CREATE TABLE #{options[:table_name]} (
|
110
110
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
111
111
|
#{options[:filename_column]} TEXT UNIQUE,
|
@@ -211,7 +211,10 @@ module Amalgalite
|
|
211
211
|
STDERR.puts "Unable to add #{f} to the manifest, cannot find the file on disk"
|
212
212
|
next
|
213
213
|
end
|
214
|
-
|
214
|
+
# Make sure that we can handle files without the .rb extension
|
215
|
+
# if we have to. This means bin/foo works as a require path
|
216
|
+
# without requiring bin/foo to actually be bin/foo.rb
|
217
|
+
m.require_path = m.require_path.to_s.sub(/\.rb\Z/,'')
|
215
218
|
manifest << m
|
216
219
|
end
|
217
220
|
return manifest
|
data/lib/amalgalite/requires.rb
CHANGED
@@ -18,17 +18,24 @@ module Amalgalite
|
|
18
18
|
end
|
19
19
|
|
20
20
|
#
|
21
|
-
# Allocate a database connection to the given filename
|
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.
|
22
25
|
#
|
23
26
|
def db_connection_to( dbfile_name )
|
24
|
-
|
25
|
-
|
26
|
-
|
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
|
27
35
|
end
|
28
|
-
return connection
|
29
36
|
end
|
30
37
|
|
31
|
-
#
|
38
|
+
#
|
32
39
|
# Setting a class level variable as a flag to know what we are currently
|
33
40
|
# in the middle of requiring
|
34
41
|
#
|
@@ -55,7 +62,7 @@ module Amalgalite
|
|
55
62
|
raise ::LoadError, "amalgalite has no such file to load -- #{filename}"
|
56
63
|
end
|
57
64
|
end
|
58
|
-
|
65
|
+
end
|
59
66
|
|
60
67
|
attr_reader :dbfile_name
|
61
68
|
attr_reader :table_name
|
@@ -96,16 +103,12 @@ module Amalgalite
|
|
96
103
|
else
|
97
104
|
begin
|
98
105
|
filename = filename.gsub(/\.rb\Z/,'')
|
99
|
-
rows = db_connection.execute(sql, filename)
|
100
|
-
if rows.size > 0 then
|
101
|
-
row = rows.first
|
102
|
-
contents = row[contents_column].to_s
|
103
|
-
if row[compressed_column] then
|
104
|
-
contents = ::Amalgalite::Packer.gunzip( contents )
|
105
|
-
end
|
106
106
|
|
107
|
-
|
108
|
-
|
107
|
+
contents = file_contents(filename)
|
108
|
+
|
109
|
+
if contents
|
110
|
+
eval( contents, TOPLEVEL_BINDING, filename )
|
111
|
+
$LOADED_FEATURES << filename
|
109
112
|
return true
|
110
113
|
else
|
111
114
|
return false
|
@@ -115,6 +118,34 @@ module Amalgalite
|
|
115
118
|
end
|
116
119
|
end
|
117
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
|
+
|
118
149
|
end
|
119
150
|
end
|
120
151
|
require 'amalgalite/core_ext/kernel/require'
|
data/lib/amalgalite/schema.rb
CHANGED
@@ -15,31 +15,52 @@ module Amalgalite
|
|
15
15
|
#
|
16
16
|
class Schema
|
17
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.
|
18
21
|
attr_reader :catalog
|
19
|
-
|
22
|
+
|
23
|
+
# The schema_version at the time this schema was taken.
|
20
24
|
attr_reader :schema_version
|
21
|
-
|
25
|
+
|
26
|
+
# The Amalagalite::Database this schema is associated with.
|
22
27
|
attr_reader :db
|
23
28
|
|
24
29
|
#
|
25
30
|
# Create a new instance of Schema
|
26
31
|
#
|
27
|
-
def initialize( db, catalog = 'main',
|
28
|
-
@db
|
29
|
-
@catalog
|
30
|
-
@schema = schema
|
32
|
+
def initialize( db, catalog = 'main', master_table = 'sqlite_master' )
|
33
|
+
@db = db
|
34
|
+
@catalog = catalog
|
31
35
|
@schema_version = nil
|
32
|
-
@tables
|
33
|
-
@views
|
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
|
34
45
|
load_schema!
|
35
46
|
end
|
36
47
|
|
37
|
-
def
|
38
|
-
|
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?
|
39
60
|
end
|
40
61
|
|
41
62
|
def current_version
|
42
|
-
@db.first_value_from("PRAGMA schema_version")
|
63
|
+
@db.first_value_from("PRAGMA #{catalog}.schema_version")
|
43
64
|
end
|
44
65
|
|
45
66
|
#
|
@@ -47,15 +68,24 @@ module Amalgalite
|
|
47
68
|
def load_schema!
|
48
69
|
load_tables
|
49
70
|
load_views
|
71
|
+
if @temp_schema then
|
72
|
+
@temp_schema.load_schema!
|
73
|
+
end
|
50
74
|
@schema_version = self.current_version
|
51
75
|
nil
|
52
76
|
end
|
53
77
|
|
54
78
|
##
|
55
|
-
# return the tables, reloading if dirty
|
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.
|
56
82
|
def tables
|
57
83
|
load_schema! if dirty?
|
58
|
-
|
84
|
+
t = @tables
|
85
|
+
if @temp_schema then
|
86
|
+
t = @tables.merge( @temp_schema.tables )
|
87
|
+
end
|
88
|
+
return t
|
59
89
|
end
|
60
90
|
|
61
91
|
##
|
@@ -63,7 +93,7 @@ module Amalgalite
|
|
63
93
|
#
|
64
94
|
def load_tables
|
65
95
|
@tables = {}
|
66
|
-
@db.execute("SELECT tbl_name FROM
|
96
|
+
@db.execute("SELECT tbl_name FROM #{catalog_master_table} WHERE type = 'table' AND name != 'sqlite_sequence'") do |table_info|
|
67
97
|
table = load_table( table_info['tbl_name'] )
|
68
98
|
table.indexes = load_indexes( table )
|
69
99
|
@tables[table.name] = table
|
@@ -74,36 +104,26 @@ module Amalgalite
|
|
74
104
|
##
|
75
105
|
# Load a single table
|
76
106
|
def load_table( table_name )
|
77
|
-
rows = @db.execute("SELECT tbl_name, sql FROM
|
107
|
+
rows = @db.execute("SELECT tbl_name, sql FROM #{catalog_master_table} WHERE type = 'table' AND tbl_name = ?", table_name)
|
78
108
|
table_info = rows.first
|
79
109
|
table = nil
|
80
|
-
if table_info then
|
110
|
+
if table_info then
|
81
111
|
table = Amalgalite::Table.new( table_info['tbl_name'], table_info['sql'] )
|
82
|
-
table.columns = load_columns( table )
|
83
112
|
table.schema = self
|
113
|
+
table.columns = load_columns( table )
|
84
114
|
table.indexes = load_indexes( table )
|
85
|
-
@tables[table.name] = table
|
86
|
-
else
|
87
|
-
# might be a temporary table
|
88
|
-
table = Amalgalite::Table.new( table_name, nil )
|
89
|
-
cols = load_columns( table )
|
90
|
-
if cols.size > 0 then
|
91
|
-
table.columns = cols
|
92
|
-
table.schema = self
|
93
|
-
table.indexes = load_indexes( table )
|
94
|
-
@tables[table.name] = table
|
95
|
-
end
|
115
|
+
@tables[table.name] = table
|
96
116
|
end
|
97
117
|
return table
|
98
118
|
end
|
99
119
|
|
100
|
-
##
|
120
|
+
##
|
101
121
|
# load all the indexes for a particular table
|
102
122
|
#
|
103
123
|
def load_indexes( table )
|
104
124
|
indexes = {}
|
105
125
|
|
106
|
-
@db.prepare("SELECT name, sql FROM
|
126
|
+
@db.prepare("SELECT name, sql FROM #{catalog_master_table} WHERE type ='index' and tbl_name = $name") do |idx_stmt|
|
107
127
|
idx_stmt.execute( "$name" => table.name) do |idx_info|
|
108
128
|
indexes[idx_info['name']] = Amalgalite::Index.new( idx_info['name'], idx_info['sql'], table )
|
109
129
|
end
|
@@ -134,8 +154,8 @@ module Amalgalite
|
|
134
154
|
def load_columns( table )
|
135
155
|
cols = {}
|
136
156
|
idx = 0
|
137
|
-
@db.execute("PRAGMA table_info(#{@db.quote(table.name)})") do |row|
|
138
|
-
col = Amalgalite::Column.new(
|
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'])
|
139
159
|
|
140
160
|
col.default_value = row['dflt_value']
|
141
161
|
|
@@ -154,7 +174,7 @@ module Amalgalite
|
|
154
174
|
|
155
175
|
unless table.temporary? then
|
156
176
|
# get more exact information
|
157
|
-
@db.api.table_column_metadata(
|
177
|
+
@db.api.table_column_metadata( catalog, table.name, col.name ).each_pair do |key, value|
|
158
178
|
col.send("#{key}=", value)
|
159
179
|
end
|
160
180
|
end
|
@@ -168,16 +188,23 @@ module Amalgalite
|
|
168
188
|
##
|
169
189
|
# return the views, reloading if dirty
|
170
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
|
+
#
|
171
194
|
def views
|
172
195
|
reload_schema! if dirty?
|
173
|
-
|
196
|
+
v = @views
|
197
|
+
if @temp_schema then
|
198
|
+
v = @views.merge( @temp_schema.views )
|
199
|
+
end
|
200
|
+
return v
|
174
201
|
end
|
175
202
|
|
176
203
|
##
|
177
204
|
# load a single view
|
178
205
|
#
|
179
206
|
def load_view( name )
|
180
|
-
rows = @db.execute("SELECT name, sql FROM
|
207
|
+
rows = @db.execute("SELECT name, sql FROM #{catalog_master_table} WHERE type = 'view' AND name = ?", name )
|
181
208
|
view_info = rows.first
|
182
209
|
view = Amalgalite::View.new( view_info['name'], view_info['sql'] )
|
183
210
|
view.schema = self
|
@@ -188,7 +215,7 @@ module Amalgalite
|
|
188
215
|
# load all the views for the database
|
189
216
|
#
|
190
217
|
def load_views
|
191
|
-
@db.execute("SELECT name, sql FROM
|
218
|
+
@db.execute("SELECT name, sql FROM #{catalog_master_table} WHERE type = 'view'") do |view_info|
|
192
219
|
view = load_view( view_info['name'] )
|
193
220
|
@views[view.name] = view
|
194
221
|
end
|