amalgalite 1.6.0-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. checksums.yaml +7 -0
  2. data/CONTRIBUTING.md +49 -0
  3. data/HISTORY.md +346 -0
  4. data/LICENSE +31 -0
  5. data/Manifest.txt +104 -0
  6. data/README.md +65 -0
  7. data/Rakefile +26 -0
  8. data/TODO.md +57 -0
  9. data/bin/amalgalite-pack +147 -0
  10. data/examples/a.rb +9 -0
  11. data/examples/blob.rb +88 -0
  12. data/examples/bootstrap.rb +36 -0
  13. data/examples/define_aggregate.rb +75 -0
  14. data/examples/define_function.rb +104 -0
  15. data/examples/fts5.rb +152 -0
  16. data/examples/gem-db.rb +94 -0
  17. data/examples/require_me.rb +11 -0
  18. data/examples/requires.rb +42 -0
  19. data/examples/schema-info.rb +34 -0
  20. data/ext/amalgalite/c/amalgalite.c +355 -0
  21. data/ext/amalgalite/c/amalgalite.h +151 -0
  22. data/ext/amalgalite/c/amalgalite_blob.c +240 -0
  23. data/ext/amalgalite/c/amalgalite_constants.c +1226 -0
  24. data/ext/amalgalite/c/amalgalite_database.c +1178 -0
  25. data/ext/amalgalite/c/amalgalite_requires_bootstrap.c +282 -0
  26. data/ext/amalgalite/c/amalgalite_statement.c +649 -0
  27. data/ext/amalgalite/c/extconf.rb +62 -0
  28. data/ext/amalgalite/c/gen_constants.rb +330 -0
  29. data/ext/amalgalite/c/notes.txt +134 -0
  30. data/ext/amalgalite/c/sqlite3.c +205352 -0
  31. data/ext/amalgalite/c/sqlite3.h +10727 -0
  32. data/ext/amalgalite/c/sqlite3_options.h +4 -0
  33. data/ext/amalgalite/c/sqlite3ext.h +578 -0
  34. data/lib/amalgalite.rb +51 -0
  35. data/lib/amalgalite/2.0/amalgalite.so +0 -0
  36. data/lib/amalgalite/2.1/amalgalite.so +0 -0
  37. data/lib/amalgalite/2.2/amalgalite.so +0 -0
  38. data/lib/amalgalite/2.3/amalgalite.so +0 -0
  39. data/lib/amalgalite/2.4/amalgalite.so +0 -0
  40. data/lib/amalgalite/aggregate.rb +67 -0
  41. data/lib/amalgalite/blob.rb +186 -0
  42. data/lib/amalgalite/boolean.rb +42 -0
  43. data/lib/amalgalite/busy_timeout.rb +47 -0
  44. data/lib/amalgalite/column.rb +99 -0
  45. data/lib/amalgalite/core_ext/kernel/require.rb +21 -0
  46. data/lib/amalgalite/csv_table_importer.rb +74 -0
  47. data/lib/amalgalite/database.rb +984 -0
  48. data/lib/amalgalite/function.rb +61 -0
  49. data/lib/amalgalite/index.rb +43 -0
  50. data/lib/amalgalite/memory_database.rb +15 -0
  51. data/lib/amalgalite/packer.rb +231 -0
  52. data/lib/amalgalite/paths.rb +80 -0
  53. data/lib/amalgalite/profile_tap.rb +131 -0
  54. data/lib/amalgalite/progress_handler.rb +21 -0
  55. data/lib/amalgalite/requires.rb +151 -0
  56. data/lib/amalgalite/schema.rb +225 -0
  57. data/lib/amalgalite/sqlite3.rb +6 -0
  58. data/lib/amalgalite/sqlite3/constants.rb +95 -0
  59. data/lib/amalgalite/sqlite3/database/function.rb +48 -0
  60. data/lib/amalgalite/sqlite3/database/status.rb +68 -0
  61. data/lib/amalgalite/sqlite3/status.rb +60 -0
  62. data/lib/amalgalite/sqlite3/version.rb +55 -0
  63. data/lib/amalgalite/statement.rb +418 -0
  64. data/lib/amalgalite/table.rb +91 -0
  65. data/lib/amalgalite/taps.rb +2 -0
  66. data/lib/amalgalite/taps/console.rb +27 -0
  67. data/lib/amalgalite/taps/io.rb +71 -0
  68. data/lib/amalgalite/trace_tap.rb +35 -0
  69. data/lib/amalgalite/type_map.rb +63 -0
  70. data/lib/amalgalite/type_maps/default_map.rb +166 -0
  71. data/lib/amalgalite/type_maps/storage_map.rb +38 -0
  72. data/lib/amalgalite/type_maps/text_map.rb +21 -0
  73. data/lib/amalgalite/version.rb +8 -0
  74. data/lib/amalgalite/view.rb +26 -0
  75. data/spec/aggregate_spec.rb +154 -0
  76. data/spec/amalgalite_spec.rb +4 -0
  77. data/spec/blob_spec.rb +78 -0
  78. data/spec/boolean_spec.rb +24 -0
  79. data/spec/busy_handler.rb +157 -0
  80. data/spec/data/iso-3166-country.txt +242 -0
  81. data/spec/data/iso-3166-schema.sql +22 -0
  82. data/spec/data/iso-3166-subcountry.txt +3995 -0
  83. data/spec/data/make-iso-db.sh +12 -0
  84. data/spec/database_spec.rb +508 -0
  85. data/spec/default_map_spec.rb +92 -0
  86. data/spec/function_spec.rb +78 -0
  87. data/spec/integeration_spec.rb +97 -0
  88. data/spec/iso_3166_database.rb +58 -0
  89. data/spec/packer_spec.rb +60 -0
  90. data/spec/paths_spec.rb +28 -0
  91. data/spec/progress_handler_spec.rb +91 -0
  92. data/spec/requires_spec.rb +54 -0
  93. data/spec/rtree_spec.rb +66 -0
  94. data/spec/schema_spec.rb +131 -0
  95. data/spec/spec_helper.rb +48 -0
  96. data/spec/sqlite3/constants_spec.rb +108 -0
  97. data/spec/sqlite3/database_status_spec.rb +36 -0
  98. data/spec/sqlite3/status_spec.rb +22 -0
  99. data/spec/sqlite3/version_spec.rb +28 -0
  100. data/spec/sqlite3_spec.rb +53 -0
  101. data/spec/statement_spec.rb +168 -0
  102. data/spec/storage_map_spec.rb +38 -0
  103. data/spec/tap_spec.rb +57 -0
  104. data/spec/text_map_spec.rb +20 -0
  105. data/spec/type_map_spec.rb +14 -0
  106. data/spec/version_spec.rb +8 -0
  107. data/tasks/custom.rake +102 -0
  108. data/tasks/default.rake +240 -0
  109. data/tasks/extension.rake +38 -0
  110. data/tasks/this.rb +208 -0
  111. metadata +318 -0
@@ -0,0 +1,21 @@
1
+ module Amalgalite
2
+ ##
3
+ # A base class for use in creating your own progress handler classes
4
+ #
5
+ class ProgressHandler
6
+ def to_proc
7
+ self
8
+ end
9
+
10
+ # the arity of the call method
11
+ def arity() 0 ; end
12
+
13
+ ##
14
+ # Override this method, returning +false+ if the SQLite should act as if
15
+ # +interrupt!+ had been invoked.
16
+ #
17
+ def call
18
+ raise NotImplementedError, "The progress handler call() method must be implemented"
19
+ end
20
+ end
21
+ end
@@ -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,6 @@
1
+ require 'amalgalite/version'
2
+ require 'amalgalite/sqlite3/version'
3
+ require 'amalgalite/sqlite3/constants'
4
+ require 'amalgalite/sqlite3/status'
5
+ require 'amalgalite/sqlite3/database/status'
6
+ require 'amalgalite/sqlite3/database/function'
@@ -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