amalgalite 1.1.2-x86-mswin32 → 1.3.0-x86-mswin32
Sign up to get free protection for your applications and to get access to all the features.
- 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
|