amalgalite 1.1.2 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +15 -0
  2. data/CONTRIBUTING.md +49 -0
  3. data/{HISTORY.rdoc → HISTORY.md} +96 -73
  4. data/LICENSE +2 -2
  5. data/Manifest.txt +104 -0
  6. data/README.md +73 -0
  7. data/Rakefile +25 -0
  8. data/TODO.md +50 -0
  9. data/ext/amalgalite/{amalgalite3.c → c/amalgalite.c} +12 -12
  10. data/ext/amalgalite/{amalgalite3.h → c/amalgalite.h} +5 -5
  11. data/ext/amalgalite/{amalgalite3_blob.c → c/amalgalite_blob.c} +2 -2
  12. data/ext/amalgalite/{amalgalite3_constants.c → c/amalgalite_constants.c} +2 -2
  13. data/ext/amalgalite/{amalgalite3_database.c → c/amalgalite_database.c} +49 -21
  14. data/ext/amalgalite/{amalgalite3_requires_bootstrap.c → c/amalgalite_requires_bootstrap.c} +131 -58
  15. data/ext/amalgalite/{amalgalite3_statement.c → c/amalgalite_statement.c} +2 -2
  16. data/ext/amalgalite/{extconf.rb → c/extconf.rb} +4 -4
  17. data/ext/amalgalite/{gen_constants.rb → c/gen_constants.rb} +3 -3
  18. data/ext/amalgalite/c/notes.txt +134 -0
  19. data/ext/amalgalite/{sqlite3.c → c/sqlite3.c} +94602 -80497
  20. data/ext/amalgalite/{sqlite3.h → c/sqlite3.h} +1047 -216
  21. data/ext/amalgalite/{sqlite3_options.h → c/sqlite3_options.h} +0 -0
  22. data/ext/amalgalite/{sqlite3ext.h → c/sqlite3ext.h} +40 -13
  23. data/lib/amalgalite.rb +13 -6
  24. data/lib/amalgalite/column.rb +7 -5
  25. data/lib/amalgalite/database.rb +18 -10
  26. data/lib/amalgalite/packer.rb +5 -2
  27. data/lib/amalgalite/requires.rb +47 -16
  28. data/lib/amalgalite/schema.rb +63 -36
  29. data/lib/amalgalite/sqlite3/version.rb +0 -1
  30. data/lib/amalgalite/statement.rb +7 -5
  31. data/lib/amalgalite/table.rb +9 -8
  32. data/lib/amalgalite/type_maps/default_map.rb +0 -1
  33. data/lib/amalgalite/type_maps/storage_map.rb +0 -2
  34. data/lib/amalgalite/type_maps/text_map.rb +0 -1
  35. data/lib/amalgalite/version.rb +3 -32
  36. data/spec/aggregate_spec.rb +1 -1
  37. data/spec/amalgalite_spec.rb +1 -1
  38. data/spec/blob_spec.rb +1 -1
  39. data/spec/boolean_spec.rb +2 -1
  40. data/spec/busy_handler.rb +1 -1
  41. data/spec/database_spec.rb +16 -11
  42. data/spec/default_map_spec.rb +1 -1
  43. data/spec/function_spec.rb +1 -1
  44. data/spec/integeration_spec.rb +2 -1
  45. data/spec/packer_spec.rb +4 -4
  46. data/spec/paths_spec.rb +1 -1
  47. data/spec/progress_handler_spec.rb +4 -5
  48. data/spec/requires_spec.rb +36 -2
  49. data/spec/rtree_spec.rb +6 -5
  50. data/spec/schema_spec.rb +28 -20
  51. data/spec/spec_helper.rb +2 -7
  52. data/spec/sqlite3/constants_spec.rb +1 -1
  53. data/spec/sqlite3/database_status_spec.rb +4 -4
  54. data/spec/sqlite3/status_spec.rb +5 -5
  55. data/spec/sqlite3/version_spec.rb +7 -7
  56. data/spec/sqlite3_spec.rb +3 -3
  57. data/spec/statement_spec.rb +3 -4
  58. data/spec/storage_map_spec.rb +1 -1
  59. data/spec/tap_spec.rb +4 -4
  60. data/spec/text_map_spec.rb +1 -1
  61. data/spec/type_map_spec.rb +1 -1
  62. data/spec/version_spec.rb +2 -9
  63. data/tasks/custom.rake +99 -0
  64. data/tasks/default.rake +277 -0
  65. data/tasks/extension.rake +28 -202
  66. data/tasks/this.rb +209 -0
  67. metadata +186 -244
  68. data/README.rdoc +0 -54
  69. data/gemspec.rb +0 -63
  70. data/tasks/announce.rake +0 -44
  71. data/tasks/config.rb +0 -107
  72. data/tasks/distribution.rake +0 -77
  73. data/tasks/documentation.rake +0 -36
  74. data/tasks/rspec.rake +0 -30
  75. data/tasks/utils.rb +0 -80
@@ -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*,int eTextRep,const char*));
53
- int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*,int eTextRep,const void*));
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*,int(*)(void*,int,const void*,int,const void*));
79
- int (*create_collation16)(sqlite3*,const void*,int,void*,int(*)(void*,int,const void*,int,const void*));
80
- int (*create_function)(sqlite3*,const char*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*));
81
- int (*create_function16)(sqlite3*,const void*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*));
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*,const char*,const char*),void*);
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*,char const**,char const**,int*,int*,int*);
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*,sqlite_int64),void*);
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*,void (*xDestroy)(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,int,sqlite3_blob**);
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*,int(*)(void*,int,const void*,int,const void*),void(*)(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*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*),void(*xDestroy)(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;
@@ -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( /sqlite3/ ).empty? then
9
- raise LoadError, "amalgalite conflicts with sqlite3-ruby, please choose one or the other."
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
- # use a version subdirectory for extensions, initially to support windows, but
20
- # why make a special case, it doesn't hurt anyone to have an extra subdir
21
- # someplace
22
- require "amalgalite/#{RUBY_VERSION.sub(/\.\d$/,'')}/amalgalite3"
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'
@@ -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
@@ -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 containing the table and column structure of the
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 |db_function|
745
- @api.remove_function( db_function.name, db_function)
746
- @functions.delete( db_function.signature )
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 |db_aggregate|
806
- i = db_aggregate.new
807
- @api.remove_aggregate( i.name, i.arity, db_aggregate )
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
@@ -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
- sql = <<-create
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
- m.require_path = m.require_path.to_s[ /\A(.*)\.rb\Z/, 1]
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
@@ -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
- unless connection = load_path_db_connections[ dbfile_name ]
25
- connection = ::Amalgalite::Database.new( dbfile_name )
26
- load_path_db_connections[dbfile_name] = connection
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
- end
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
- eval( contents, TOPLEVEL_BINDING, row[filename_column] )
108
- $LOADED_FEATURES << row[filename_column]
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'
@@ -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
- attr_reader :schema
22
+
23
+ # The schema_version at the time this schema was taken.
20
24
  attr_reader :schema_version
21
- attr_writer :dirty
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', schema = 'sqlite')
28
- @db = db
29
- @catalog = 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 dirty?()
38
- return (@schema_version != self.current_version)
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
- return @tables
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 sqlite_master WHERE type = 'table' AND name != 'sqlite_sequence'") do |table_info|
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 sqlite_master WHERE type = 'table' AND tbl_name = ?", table_name)
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 sqlite_master WHERE type ='index' and tbl_name = $name") do |idx_stmt|
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( "main", table.name, row['name'], row['cid'])
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( "main", table.name, col.name ).each_pair do |key, value|
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
- return @views
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 sqlite_master WHERE type = 'view' AND name = ?", name )
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 sqlite_master WHERE type = 'view'") do |view_info|
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