amalgalite 0.10.1-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
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