amalgalite 0.10.1-x86-mingw32

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.
Files changed (100) hide show
  1. data/HISTORY +201 -0
  2. data/LICENSE +29 -0
  3. data/README +51 -0
  4. data/bin/amalgalite-pack +126 -0
  5. data/examples/a.rb +9 -0
  6. data/examples/blob.rb +88 -0
  7. data/examples/bootstrap.rb +36 -0
  8. data/examples/define_aggregate.rb +75 -0
  9. data/examples/define_function.rb +104 -0
  10. data/examples/gem-db.rb +94 -0
  11. data/examples/gems.db +0 -0
  12. data/examples/require_me.rb +11 -0
  13. data/examples/requires.rb +42 -0
  14. data/examples/schema-info.rb +34 -0
  15. data/ext/amalgalite/amalgalite3.c +290 -0
  16. data/ext/amalgalite/amalgalite3.h +151 -0
  17. data/ext/amalgalite/amalgalite3_blob.c +240 -0
  18. data/ext/amalgalite/amalgalite3_constants.c +221 -0
  19. data/ext/amalgalite/amalgalite3_database.c +1148 -0
  20. data/ext/amalgalite/amalgalite3_requires_bootstrap.c +210 -0
  21. data/ext/amalgalite/amalgalite3_statement.c +639 -0
  22. data/ext/amalgalite/extconf.rb +36 -0
  23. data/ext/amalgalite/gen_constants.rb +130 -0
  24. data/ext/amalgalite/sqlite3.c +106729 -0
  25. data/ext/amalgalite/sqlite3.h +5626 -0
  26. data/ext/amalgalite/sqlite3_options.h +4 -0
  27. data/ext/amalgalite/sqlite3ext.h +380 -0
  28. data/gemspec.rb +60 -0
  29. data/lib/amalgalite.rb +43 -0
  30. data/lib/amalgalite/1.8/amalgalite3.so +0 -0
  31. data/lib/amalgalite/1.9/amalgalite3.so +0 -0
  32. data/lib/amalgalite/aggregate.rb +67 -0
  33. data/lib/amalgalite/blob.rb +186 -0
  34. data/lib/amalgalite/boolean.rb +42 -0
  35. data/lib/amalgalite/busy_timeout.rb +47 -0
  36. data/lib/amalgalite/column.rb +97 -0
  37. data/lib/amalgalite/core_ext/kernel/require.rb +21 -0
  38. data/lib/amalgalite/database.rb +947 -0
  39. data/lib/amalgalite/function.rb +61 -0
  40. data/lib/amalgalite/index.rb +43 -0
  41. data/lib/amalgalite/packer.rb +226 -0
  42. data/lib/amalgalite/paths.rb +70 -0
  43. data/lib/amalgalite/profile_tap.rb +131 -0
  44. data/lib/amalgalite/progress_handler.rb +21 -0
  45. data/lib/amalgalite/requires.rb +120 -0
  46. data/lib/amalgalite/schema.rb +191 -0
  47. data/lib/amalgalite/sqlite3.rb +6 -0
  48. data/lib/amalgalite/sqlite3/constants.rb +80 -0
  49. data/lib/amalgalite/sqlite3/database/function.rb +48 -0
  50. data/lib/amalgalite/sqlite3/database/status.rb +68 -0
  51. data/lib/amalgalite/sqlite3/status.rb +60 -0
  52. data/lib/amalgalite/sqlite3/version.rb +37 -0
  53. data/lib/amalgalite/statement.rb +414 -0
  54. data/lib/amalgalite/table.rb +90 -0
  55. data/lib/amalgalite/taps.rb +2 -0
  56. data/lib/amalgalite/taps/console.rb +27 -0
  57. data/lib/amalgalite/taps/io.rb +71 -0
  58. data/lib/amalgalite/trace_tap.rb +35 -0
  59. data/lib/amalgalite/type_map.rb +63 -0
  60. data/lib/amalgalite/type_maps/default_map.rb +167 -0
  61. data/lib/amalgalite/type_maps/storage_map.rb +40 -0
  62. data/lib/amalgalite/type_maps/text_map.rb +22 -0
  63. data/lib/amalgalite/version.rb +37 -0
  64. data/lib/amalgalite/view.rb +26 -0
  65. data/spec/aggregate_spec.rb +169 -0
  66. data/spec/amalgalite_spec.rb +4 -0
  67. data/spec/blob_spec.rb +81 -0
  68. data/spec/boolean_spec.rb +23 -0
  69. data/spec/busy_handler.rb +165 -0
  70. data/spec/database_spec.rb +494 -0
  71. data/spec/default_map_spec.rb +87 -0
  72. data/spec/function_spec.rb +94 -0
  73. data/spec/integeration_spec.rb +111 -0
  74. data/spec/packer_spec.rb +60 -0
  75. data/spec/paths_spec.rb +28 -0
  76. data/spec/progress_handler_spec.rb +105 -0
  77. data/spec/requires_spec.rb +23 -0
  78. data/spec/rtree_spec.rb +71 -0
  79. data/spec/schema_spec.rb +120 -0
  80. data/spec/spec_helper.rb +27 -0
  81. data/spec/sqlite3/constants_spec.rb +65 -0
  82. data/spec/sqlite3/database_status_spec.rb +36 -0
  83. data/spec/sqlite3/status_spec.rb +18 -0
  84. data/spec/sqlite3/version_spec.rb +14 -0
  85. data/spec/sqlite3_spec.rb +53 -0
  86. data/spec/statement_spec.rb +161 -0
  87. data/spec/storage_map_spec.rb +41 -0
  88. data/spec/tap_spec.rb +59 -0
  89. data/spec/text_map_spec.rb +23 -0
  90. data/spec/type_map_spec.rb +17 -0
  91. data/spec/version_spec.rb +15 -0
  92. data/tasks/announce.rake +43 -0
  93. data/tasks/config.rb +107 -0
  94. data/tasks/distribution.rake +77 -0
  95. data/tasks/documentation.rake +32 -0
  96. data/tasks/extension.rake +141 -0
  97. data/tasks/rspec.rake +33 -0
  98. data/tasks/rubyforge.rake +59 -0
  99. data/tasks/utils.rb +80 -0
  100. metadata +237 -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,120 @@
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
22
+ #
23
+ 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
+ end
28
+ return connection
29
+ end
30
+
31
+ #
32
+ # Setting a class level variable as a flag to know what we are currently
33
+ # in the middle of requiring
34
+ #
35
+ def requiring
36
+ @requiring ||= []
37
+ end
38
+
39
+ def require( filename )
40
+ if load_path.empty? then
41
+ raise ::LoadError, "Amalgalite load path is empty -- #{filename}"
42
+ elsif $LOADED_FEATURES.include?( filename ) then
43
+ return false
44
+ elsif Requires.requiring.include?( filename ) then
45
+ return false
46
+ else
47
+ Requires.requiring << filename
48
+ load_path.each do |lp|
49
+ if lp.require( filename ) then
50
+ Requires.requiring.delete( filename )
51
+ return true
52
+ end
53
+ end
54
+ Requires.requiring.delete( filename )
55
+ raise ::LoadError, "amalgalite has no such file to load -- #{filename}"
56
+ end
57
+ end
58
+ end
59
+
60
+ attr_reader :dbfile_name
61
+ attr_reader :table_name
62
+ attr_reader :filename_column
63
+ attr_reader :contents_column
64
+ attr_reader :compressed_column
65
+ attr_reader :db_connection
66
+
67
+ def initialize( opts = {} )
68
+ @dbfile_name = opts[:dbfile_name] || Bootstrap::DEFAULT_DB
69
+ @table_name = opts[:table_name] || Bootstrap::DEFAULT_TABLE
70
+ @filename_column = opts[:filename_column] || Bootstrap::DEFAULT_FILENAME_COLUMN
71
+ @contents_column = opts[:contents_column] || Bootstrap::DEFAULT_CONTENTS_COLUMN
72
+ @compressed_column = opts[:compressed_column] || Bootstrap::DEFAULT_COMPRESSED_COLUMN
73
+ @db_connection = Requires.db_connection_to( dbfile_name )
74
+ Requires.load_path << self
75
+ end
76
+
77
+ #
78
+ # return the sql to find the file contents for a file in this requires
79
+ #
80
+ def sql
81
+ @sql ||= "SELECT #{filename_column}, #{compressed_column}, #{contents_column} FROM #{table_name} WHERE #{filename_column} = ?"
82
+ end
83
+
84
+ #
85
+ # load a file in this database table. This will check and see if the
86
+ # file is already required. If it isn't it will select the contents
87
+ # associated with the row identified by the filename and eval those contents
88
+ # within the context of TOPLEVEL_BINDING. The filename is then appended to
89
+ # $LOADED_FEATURES.
90
+ #
91
+ # if the file was required then true is returned, otherwise false
92
+ #
93
+ def require( filename )
94
+ if $LOADED_FEATURES.include?( filename ) then
95
+ return false
96
+ else
97
+ begin
98
+ 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
+
107
+ eval( contents, TOPLEVEL_BINDING, row[filename_column] )
108
+ $LOADED_FEATURES << row[filename_column]
109
+ return true
110
+ else
111
+ return false
112
+ end
113
+ rescue => e
114
+ raise ::LoadError, "Failure loading #{filename} from #{dbfile_name} : #{e}"
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
120
+ require 'amalgalite/core_ext/kernel/require'
@@ -0,0 +1,191 @@
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
+ attr_reader :catalog
19
+ attr_reader :schema
20
+ attr_writer :dirty
21
+ attr_reader :db
22
+
23
+ #
24
+ # Create a new instance of Schema
25
+ #
26
+ def initialize( db, catalog = 'main', schema = 'sqlite')
27
+ @db = db
28
+ @catalog = catalog
29
+ @schema = schema
30
+ @tables = {}
31
+ @views = {}
32
+ @dirty = true
33
+ load_schema!
34
+ end
35
+
36
+ def dirty?() @dirty; end
37
+ def dirty!() @dirty = true; end
38
+
39
+ #
40
+ # load the schema from the database
41
+ def load_schema!
42
+ load_tables
43
+ load_views
44
+ @dirty = false
45
+ end
46
+
47
+ ##
48
+ # return the tables, reloading if dirty
49
+ def tables
50
+ load_schema! if dirty?
51
+ return @tables
52
+ end
53
+
54
+ ##
55
+ # load all the tables
56
+ #
57
+ def load_tables
58
+ @tables = {}
59
+ @db.execute("SELECT tbl_name FROM sqlite_master WHERE type = 'table' AND name != 'sqlite_sequence'") do |table_info|
60
+ table = load_table( table_info['tbl_name'] )
61
+ table.indexes = load_indexes( table )
62
+ @tables[table.name] = table
63
+ end
64
+ return @tables
65
+ end
66
+
67
+ ##
68
+ # Load a single table
69
+ def load_table( table_name )
70
+ rows = @db.execute("SELECT tbl_name, sql FROM sqlite_master WHERE type = 'table' AND tbl_name = ?", table_name)
71
+ table_info = rows.first
72
+ table = nil
73
+ if table_info then
74
+ table = Amalgalite::Table.new( table_info['tbl_name'], table_info['sql'] )
75
+ table.columns = load_columns( table )
76
+ table.schema = self
77
+ table.indexes = load_indexes( table )
78
+ @tables[table.name] = table
79
+ else
80
+ # might be a temporary table
81
+ table = Amalgalite::Table.new( table_name, nil )
82
+ cols = load_columns( table )
83
+ if cols.size > 0 then
84
+ table.columns = cols
85
+ table.schema = self
86
+ table.indexes = load_indexes( table )
87
+ @tables[table.name] = table
88
+ end
89
+ end
90
+ return table
91
+ end
92
+
93
+ ##
94
+ # load all the indexes for a particular table
95
+ #
96
+ def load_indexes( table )
97
+ indexes = {}
98
+
99
+ @db.prepare("SELECT name, sql FROM sqlite_master WHERE type ='index' and tbl_name = $name") do |idx_stmt|
100
+ idx_stmt.execute( "$name" => table.name) do |idx_info|
101
+ indexes[idx_info['name']] = Amalgalite::Index.new( idx_info['name'], idx_info['sql'], table )
102
+ end
103
+ end
104
+
105
+ @db.execute("PRAGMA index_list( #{@db.quote(table.name)} );") do |idx_list|
106
+ idx = indexes[idx_list['name']]
107
+
108
+ # temporary indexes do not show up in the previous list
109
+ if idx.nil? then
110
+ idx = Amalgalite::Index.new( idx_list['name'], nil, table )
111
+ indexes[idx_list['name']] = idx
112
+ end
113
+
114
+ idx.sequence_number = idx_list['seq']
115
+ idx.unique = Boolean.to_bool( idx_list['unique'] )
116
+
117
+ @db.execute("PRAGMA index_info( #{@db.quote(idx.name)} );") do |col_info|
118
+ idx.columns << table.columns[col_info['name']]
119
+ end
120
+ end
121
+ return indexes
122
+ end
123
+
124
+ ##
125
+ # load all the columns for a particular table
126
+ #
127
+ def load_columns( table )
128
+ cols = {}
129
+ idx = 0
130
+ @db.execute("PRAGMA table_info(#{@db.quote(table.name)})") do |row|
131
+ col = Amalgalite::Column.new( "main", table.name, row['name'], row['cid'])
132
+
133
+ col.default_value = row['dflt_value']
134
+
135
+ col.declared_data_type = row['type']
136
+ col.not_null_constraint = row['notnull']
137
+ col.primary_key = row['pk']
138
+
139
+ # need to remove leading and trailing ' or " from the default value
140
+ if col.default_value and col.default_value.kind_of?( String ) and ( col.default_value.length >= 2 ) then
141
+ fc = col.default_value[0].chr
142
+ lc = col.default_value[-1].chr
143
+ if fc == lc and ( fc == "'" || fc == '"' ) then
144
+ col.default_value = col.default_value[1..-2]
145
+ end
146
+ end
147
+
148
+ unless table.temporary? then
149
+ # get more exact information
150
+ @db.api.table_column_metadata( "main", table.name, col.name ).each_pair do |key, value|
151
+ col.send("#{key}=", value)
152
+ end
153
+ end
154
+ col.schema = self
155
+ cols[col.name] = col
156
+ idx += 1
157
+ end
158
+ return cols
159
+ end
160
+
161
+ ##
162
+ # return the views, reloading if dirty
163
+ #
164
+ def views
165
+ reload_schema! if dirty?
166
+ return @views
167
+ end
168
+
169
+ ##
170
+ # load a single view
171
+ #
172
+ def load_view( name )
173
+ rows = @db.execute("SELECT name, sql FROM sqlite_master WHERE type = 'view' AND name = ?", name )
174
+ view_info = rows.first
175
+ view = Amalgalite::View.new( view_info['name'], view_info['sql'] )
176
+ view.schema = self
177
+ return view
178
+ end
179
+
180
+ ##
181
+ # load all the views for the database
182
+ #
183
+ def load_views
184
+ @db.execute("SELECT name, sql FROM sqlite_master WHERE type = 'view'") do |view_info|
185
+ view = load_view( view_info['name'] )
186
+ @views[view.name] = view
187
+ end
188
+ return @views
189
+ end
190
+ end
191
+ 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,80 @@
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
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 ] = 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
+ end
45
+ DataType.freeze
46
+
47
+ ##
48
+ # Open defines the namespace for all possible flags to the Database.open
49
+ # method
50
+ #
51
+ module Open
52
+ end
53
+ Open.freeze
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
+ ##
65
+ # DBStatus defines the namespace for all the possible status codes for the
66
+ # Amalgalite::SQlite3::Database::Status objects.
67
+ #
68
+ module DBStatus
69
+ extend Helpers
70
+ end
71
+
72
+ ##
73
+ # ResultCode defines the namespace for all possible result codes from an
74
+ # SQLite API call.
75
+ #
76
+ module ResultCode
77
+ extend Helpers
78
+ end # end ResultCode
79
+ end
80
+ end
@@ -0,0 +1,48 @@
1
+ module Amalgalite::SQLite3
2
+ class Database
3
+ ##
4
+ # A wrapper around a proc for use as an SQLite Ddatabase fuction
5
+ #
6
+ # f = Function.new( 'md5', lambda { |x| Digest::MD5.hexdigest( x.to_s ) } )
7
+ #
8
+ class Function
9
+
10
+ # the name of the function, and how it will be called in SQL
11
+ attr_reader :name
12
+
13
+ # The unique signature of this function. This is used to determin if the
14
+ # function is already registered or not
15
+ #
16
+ def self.signature( name, arity )
17
+ "#{name}/#{arity}"
18
+ end
19
+
20
+ # Initialize with the name and the Proc
21
+ #
22
+ def initialize( name, _proc )
23
+ @name = name
24
+ @function = _proc
25
+ end
26
+
27
+ # The unique signature of this function
28
+ #
29
+ def signature
30
+ @signature ||= Function.signature( name, arity )
31
+ end
32
+ alias :to_s :signature
33
+
34
+ # The arity of SQL function, -1 means it is takes a variable number of
35
+ # arguments.
36
+ #
37
+ def arity
38
+ @function.arity
39
+ end
40
+
41
+ # Invoke the proc
42
+ #
43
+ def call( *args )
44
+ @function.call( *args )
45
+ end
46
+ end
47
+ end
48
+ end