amalgalite 0.4.2-x86-mswin32-60

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 (83) hide show
  1. data/HISTORY +81 -0
  2. data/LICENSE +29 -0
  3. data/README +40 -0
  4. data/bin/amalgalite-pack-into-db +155 -0
  5. data/examples/a.rb +9 -0
  6. data/examples/blob.rb +105 -0
  7. data/examples/bootstrap.rb +36 -0
  8. data/examples/gem-db.rb +94 -0
  9. data/examples/requires.rb +54 -0
  10. data/examples/schema-info.rb +34 -0
  11. data/ext/amalgalite3.c +201 -0
  12. data/ext/amalgalite3.h +121 -0
  13. data/ext/amalgalite3_blob.c +241 -0
  14. data/ext/amalgalite3_constants.c +221 -0
  15. data/ext/amalgalite3_database.c +550 -0
  16. data/ext/amalgalite3_requires_bootstrap.c +210 -0
  17. data/ext/amalgalite3_statement.c +628 -0
  18. data/ext/extconf.rb +19 -0
  19. data/ext/gen_constants.rb +130 -0
  20. data/ext/rbconfig-mingw.rb +178 -0
  21. data/ext/sqlite3.c +97092 -0
  22. data/ext/sqlite3.h +6364 -0
  23. data/ext/sqlite3_options.h +4 -0
  24. data/ext/sqlite3ext.h +372 -0
  25. data/gemspec.rb +55 -0
  26. data/lib/amalgalite.rb +33 -0
  27. data/lib/amalgalite/blob.rb +186 -0
  28. data/lib/amalgalite/boolean.rb +42 -0
  29. data/lib/amalgalite/column.rb +86 -0
  30. data/lib/amalgalite/core_ext/kernel/require.rb +14 -0
  31. data/lib/amalgalite/database.rb +514 -0
  32. data/lib/amalgalite/index.rb +43 -0
  33. data/lib/amalgalite/paths.rb +70 -0
  34. data/lib/amalgalite/profile_tap.rb +130 -0
  35. data/lib/amalgalite/requires.rb +112 -0
  36. data/lib/amalgalite/schema.rb +115 -0
  37. data/lib/amalgalite/sqlite3.rb +6 -0
  38. data/lib/amalgalite/sqlite3/constants.rb +82 -0
  39. data/lib/amalgalite/sqlite3/database/status.rb +69 -0
  40. data/lib/amalgalite/sqlite3/status.rb +61 -0
  41. data/lib/amalgalite/sqlite3/version.rb +38 -0
  42. data/lib/amalgalite/statement.rb +394 -0
  43. data/lib/amalgalite/table.rb +36 -0
  44. data/lib/amalgalite/taps.rb +2 -0
  45. data/lib/amalgalite/taps/console.rb +27 -0
  46. data/lib/amalgalite/taps/io.rb +71 -0
  47. data/lib/amalgalite/trace_tap.rb +35 -0
  48. data/lib/amalgalite/type_map.rb +63 -0
  49. data/lib/amalgalite/type_maps/default_map.rb +167 -0
  50. data/lib/amalgalite/type_maps/storage_map.rb +41 -0
  51. data/lib/amalgalite/type_maps/text_map.rb +23 -0
  52. data/lib/amalgalite/version.rb +37 -0
  53. data/lib/amalgalite/view.rb +26 -0
  54. data/lib/amalgalite3.so +0 -0
  55. data/spec/amalgalite_spec.rb +4 -0
  56. data/spec/blob_spec.rb +81 -0
  57. data/spec/boolean_spec.rb +23 -0
  58. data/spec/database_spec.rb +238 -0
  59. data/spec/default_map_spec.rb +87 -0
  60. data/spec/integeration_spec.rb +111 -0
  61. data/spec/paths_spec.rb +28 -0
  62. data/spec/schema_spec.rb +60 -0
  63. data/spec/spec_helper.rb +25 -0
  64. data/spec/sqlite3/constants_spec.rb +65 -0
  65. data/spec/sqlite3/database_status_spec.rb +36 -0
  66. data/spec/sqlite3/status_spec.rb +18 -0
  67. data/spec/sqlite3/version_spec.rb +14 -0
  68. data/spec/sqlite3_spec.rb +23 -0
  69. data/spec/statement_spec.rb +134 -0
  70. data/spec/storage_map_spec.rb +41 -0
  71. data/spec/tap_spec.rb +59 -0
  72. data/spec/text_map_spec.rb +23 -0
  73. data/spec/type_map_spec.rb +17 -0
  74. data/spec/version_spec.rb +9 -0
  75. data/tasks/announce.rake +39 -0
  76. data/tasks/config.rb +110 -0
  77. data/tasks/distribution.rake +53 -0
  78. data/tasks/documentation.rake +33 -0
  79. data/tasks/extension.rake +100 -0
  80. data/tasks/rspec.rake +32 -0
  81. data/tasks/rubyforge.rake +59 -0
  82. data/tasks/utils.rb +80 -0
  83. metadata +192 -0
@@ -0,0 +1,43 @@
1
+ #--
2
+ # Copyright (c) 2008 Jeremy Hinegardner
3
+ # All rights reserved. See LICENSE and/or COPYING for details.
4
+ #++
5
+
6
+ module Amalgalite
7
+ #
8
+ # a class representing the meta information about an SQLite index
9
+ #
10
+ class Index
11
+ # the name of the index
12
+ attr_reader :name
13
+
14
+ # the sql statement that created the index
15
+ attr_reader :sql
16
+
17
+ # the table the index is for
18
+ attr_accessor :table
19
+
20
+ # the columns that make up this index, in index order
21
+ attr_accessor :columns
22
+
23
+ # sqlite sequence number of the index
24
+ attr_accessor :sequence_number
25
+
26
+ # is the index unique
27
+ attr_writer :unique
28
+
29
+ def initialize( name, sql, table )
30
+ @name = name
31
+ @sql = sql
32
+ @table = table
33
+ @columns = []
34
+ @sequence_number = nil
35
+ @unique = nil
36
+ end
37
+
38
+ def unique?
39
+ return @unique
40
+ end
41
+ end
42
+ end
43
+
@@ -0,0 +1,70 @@
1
+ #--
2
+ # Copyright (c) 2008 Jeremy Hinegardner
3
+ # All rights reserved. See LICENSE and/or COPYING for details.
4
+ #++
5
+ module Amalgalite
6
+ #
7
+ # Paths contains helpful methods to determine paths of files inside the
8
+ # Amalgalite library
9
+ #
10
+ module Paths
11
+ #
12
+ # The root directory of the project is considered to be the parent directory
13
+ # of the 'lib' directory.
14
+ #
15
+ # returns:: [String] The full expanded path of the parent directory of 'lib'
16
+ # going up the path from the current file. Trailing
17
+ # File::SEPARATOR is guaranteed.
18
+ #
19
+ def self.root_dir
20
+ unless @root_dir
21
+ path_parts = ::File.expand_path(__FILE__).split(::File::SEPARATOR)
22
+ lib_index = path_parts.rindex("lib")
23
+ @root_dir = path_parts[0...lib_index].join(::File::SEPARATOR) + ::File::SEPARATOR
24
+ end
25
+ return @root_dir
26
+ end
27
+
28
+ # returns:: [String] The full expanded path of the +config+ directory
29
+ # below _root_dir_. All parameters passed in are joined onto the
30
+ # result. Trailing File::SEPARATOR is guaranteed if _args_ are
31
+ # *not* present.
32
+ #
33
+ def self.config_path(*args)
34
+ self.sub_path("config", *args)
35
+ end
36
+
37
+ # returns:: [String] The full expanded path of the +data+ directory below
38
+ # _root_dir_. All parameters passed in are joined onto the
39
+ # result. Trailing File::SEPARATOR is guaranteed if
40
+ # _*args_ are *not* present.
41
+ #
42
+ def self.data_path(*args)
43
+ self.sub_path("data", *args)
44
+ end
45
+
46
+ # returns:: [String] The full expanded path of the +lib+ directory below
47
+ # _root_dir_. All parameters passed in are joined onto the
48
+ # result. Trailing File::SEPARATOR is guaranteed if
49
+ # _*args_ are *not* present.
50
+ #
51
+ def self.lib_path(*args)
52
+ self.sub_path("lib", *args)
53
+ end
54
+
55
+ # returns:: [String] The full expanded path of the +ext+ directory below
56
+ # _root_dir_. All parameters passed in are joined onto the
57
+ # result. Trailing File::SEPARATOR is guaranteed if
58
+ # _*args_ are *not* present.
59
+ #
60
+ def self.ext_path(*args)
61
+ self.sub_path("ext", *args)
62
+ end
63
+
64
+ def self.sub_path(sub,*args)
65
+ sp = ::File.join(root_dir, sub) + File::SEPARATOR
66
+ sp = ::File.join(sp, *args) if args
67
+ end
68
+ end
69
+ end
70
+
@@ -0,0 +1,130 @@
1
+ #--
2
+ # Copyright (c) 2008 Jeremy Hinegardner
3
+ # All rights reserved. See LICENSE and/or COPYING for details.
4
+ #++
5
+
6
+ module Amalgalite
7
+ #
8
+ # A ProfileSampler is a sampler of profile times. It aggregates up profile
9
+ # events that happen for the same source. It is based upon the RFuzz::Sampler
10
+ # class from the rfuzz gem
11
+ #
12
+ class ProfileSampler
13
+ #
14
+ # create a new sampler with the given name
15
+ #
16
+ def initialize( name )
17
+ @name = name
18
+ reset!
19
+ end
20
+
21
+ ##
22
+ # reset the internal state so it may be used again
23
+ #
24
+ def reset!
25
+ @sum = 0.0
26
+ @sumsq = 0.0
27
+ @n = 0
28
+ @min = 0.0
29
+ @max = 0.0
30
+ end
31
+
32
+ ##
33
+ # add a sample to the calculations
34
+ #
35
+ def sample( value )
36
+ @sum += value
37
+ @sumsq += (value * value)
38
+ if @n == 0 then
39
+ @min = @max = value
40
+ else
41
+ @min = value if value < @min
42
+ @max = value if value > @max
43
+ end
44
+ @n += 1
45
+ end
46
+
47
+ ##
48
+ # return the mean of the data
49
+ #
50
+ def mean
51
+ @sum / @n
52
+ end
53
+
54
+ ##
55
+ # returns the standard deviation of the data
56
+ #
57
+ def stddev
58
+ begin
59
+ Math.sqrt( (@sumsq - ( @sum * @sum / @n)) / (@n-1) )
60
+ rescue Errno::EDOM
61
+ return 0.0
62
+ end
63
+ end
64
+
65
+ ##
66
+ # return all the values as an array
67
+ #
68
+ def to_a
69
+ [ @name, @sum, @sumsq, @n, mean, stddev, @min, @max ]
70
+ end
71
+
72
+ ##
73
+ # return all the values as a hash
74
+ #
75
+ def to_h
76
+ { 'name' => @name, 'n' => @n,
77
+ 'sum' => @sum, 'sumsq' => @sumsq, 'mean' => mean,
78
+ 'stddev' => stddev, 'min' => @min, 'max' => @max }
79
+ end
80
+
81
+ ##
82
+ # return a string containing the sampler summary
83
+ #
84
+ def to_s
85
+ "[%s] => sum: %d, sumsq: %d, n: %d, mean: %0.6f, stddev: %0.6f, min: %d, max: %d" % to_a
86
+ end
87
+
88
+ end
89
+
90
+ #
91
+ # A Profile Tap recives +profile+ events from SQLite which involve the number of
92
+ # nanoseconds in wall-clock time it took for a particular thing to happen. In
93
+ # general this +thing+ is an SQL statement.
94
+ #
95
+ # It has a well known +profile+ method which when invoked will write the event
96
+ # to a delegate object.
97
+ #
98
+ #
99
+ class ProfileTap
100
+
101
+ attr_reader :samplers
102
+
103
+ #
104
+ # Create a new ProfileTap object that wraps the given object and calls the
105
+ # method named in +send_to+ ever time a profile event happens.
106
+ #
107
+ def initialize( wrapped_obj, send_to = 'profile' )
108
+ unless wrapped_obj.respond_to?( send_to )
109
+ raise Amalgalite::Error, "#{wrapped_obj.class.name} does not respond to #{send_to.to_s} "
110
+ end
111
+
112
+ @delegate_obj = wrapped_obj
113
+ @delegate_method = send_to
114
+ @samplers = {}
115
+ end
116
+
117
+ #
118
+ # Record the profile information and send the delegate object the msg and
119
+ # time information.
120
+ #
121
+ def profile( msg, time )
122
+ unless sampler = @samplers[msg]
123
+ msg = msg.gsub(/\s+/,' ')
124
+ sampler = @samplers[msg] = ProfileSampler.new( msg )
125
+ end
126
+ sampler.sample( time )
127
+ @delegate_obj.send( @delegate_method, msg, time )
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,112 @@
1
+ require 'amalgalite'
2
+
3
+ module Amalgalite
4
+ #
5
+ # Requires encapsulates requiring itesm from the database
6
+ class Requires
7
+ class << self
8
+ def load_path_db_connections
9
+ @load_path_db_connections ||= {}
10
+ end
11
+ def load_path
12
+ @load_path ||= []
13
+ end
14
+
15
+ def db_connection_to( dbfile_name )
16
+ unless connection = load_path_db_connections[ dbfile_name ]
17
+ puts "loading file #{dbfile_name}"
18
+ connection = ::Amalgalite::Database.new( dbfile_name )
19
+ load_path_db_connections[dbfile_name] = connection
20
+ end
21
+ return connection
22
+ end
23
+
24
+ def require( filename )
25
+ load_path.each { |lp| lp.require( filename ) }
26
+ end
27
+
28
+ #
29
+ # return the files in their dependency order for use for packing into a
30
+ # database
31
+ #
32
+ def require_order
33
+ @require_roder ||= %w[
34
+ amalgalite.rb
35
+ amalgalite/blob.rb
36
+ amalgalite/boolean.rb
37
+ amalgalite/column.rb
38
+ amalgalite/statement.rb
39
+ amalgalite/trace_tap.rb
40
+ amalgalite/profile_tap.rb
41
+ amalgalite/type_map.rb
42
+ amalgalite/type_maps/storage_map.rb
43
+ amalgalite/type_maps/text_map.rb
44
+ amalgalite/type_maps/default_map.rb
45
+ amalgalite/database.rb
46
+ amalgalite/index.rb
47
+ amalgalite/paths.rb
48
+ amalgalite/table.rb
49
+ amalgalite/view.rb
50
+ amalgalite/schema.rb
51
+ amalgalite/version.rb
52
+ amalgalite/sqlite3/version.rb
53
+ amalgalite/sqlite3/constants.rb
54
+ amalgalite/sqlite3.rb
55
+ amalgalite/taps/io.rb
56
+ amalgalite/taps/console.rb
57
+ amalgalite/taps.rb
58
+ amalgalite/core_ext/kernel/require.rb
59
+ amalgalite/requires.rb
60
+ ]
61
+ end
62
+ end
63
+
64
+ attr_reader :dbfile_name
65
+ attr_reader :table_name
66
+ attr_reader :filename_column
67
+ attr_reader :contents_column
68
+ attr_reader :db_connection
69
+
70
+ def initialize( opts = {} )
71
+ @dbfile_name = opts[:dbfile_name] || "lib.db"
72
+ @table_name = opts[:table_name] || "rubylibs"
73
+ @filename_column = opts[:filename_column] || "filename"
74
+ @contents_column = opts[:contents_column] || "contents"
75
+ @db_connection = Requires.db_connection_to( dbfile_name )
76
+ Requires.load_path << self
77
+ end
78
+
79
+ #
80
+ # return the sql to find the file contents for a file in this requires
81
+ #
82
+ def sql
83
+ @sql ||= "SELECT #{filename_column}, #{contents_column} FROM #{table_name} WHERE #{filename_column} = ?"
84
+ end
85
+
86
+ #
87
+ # require a file in this database table. This will check and see if the
88
+ # file is already required. If it isn't it will select the contents
89
+ # associated with the row identified by the filename and eval those contents
90
+ # within the context of TOPLEVEL_BINDING. The filename is then appended to
91
+ # $".
92
+ #
93
+ # if the file was required then true is returned, otherwise false
94
+ #
95
+ def require( filename )
96
+ if $".include?( filename ) then
97
+ return false
98
+ else
99
+ begin
100
+ rows = db_connection.execute(sql, filename)
101
+ row = rows.first
102
+ eval( row[contents_column].to_s, TOPLEVEL_BINDING)
103
+ $" << row[filename_column]
104
+ rescue => e
105
+ raise LoadError, "Failure loading #{filename} from #{dbfile_name} : #{e}"
106
+ end
107
+ end
108
+ return true
109
+ end
110
+ end
111
+ end
112
+ require 'amalgalite/core_ext/kernel/require'
@@ -0,0 +1,115 @@
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_reader :tables
21
+ attr_reader :views
22
+ attr_reader :db
23
+
24
+ #
25
+ # Create a new instance of Schema
26
+ #
27
+ def initialize( db, catalog = 'main', schema = 'sqlite')
28
+ @db = db
29
+ @catalog = catalog
30
+ @schema = schema
31
+
32
+ load_schema!
33
+ end
34
+
35
+ #
36
+ # load the schema from the database
37
+ def load_schema!
38
+ load_tables
39
+ load_views
40
+ end
41
+
42
+ ##
43
+ # load all the tables
44
+ #
45
+ def load_tables
46
+ @tables = {}
47
+ @db.execute("SELECT tbl_name, sql FROM sqlite_master WHERE type = 'table'") do |table_info|
48
+ table = Amalgalite::Table.new( table_info['tbl_name'], table_info['sql'] )
49
+ table.columns = load_columns( table )
50
+ table.schema = self
51
+ table.indexes = load_indexes( table )
52
+
53
+ @tables[table.name] = table
54
+ end
55
+
56
+ @tables
57
+ end
58
+
59
+ ##
60
+ # load all the indexes for a particular table
61
+ #
62
+ def load_indexes( table )
63
+ indexes = {}
64
+
65
+ @db.prepare("SELECT name, sql FROM sqlite_master WHERE type ='index' and tbl_name = $name") do |idx_stmt|
66
+ idx_stmt.execute( "$name" => table.name) do |idx_info|
67
+ indexes[idx_info['name']] = Amalgalite::Index.new( idx_info['name'], idx_info['sql'], table )
68
+ end
69
+ end
70
+
71
+ @db.execute("PRAGMA index_list( #{table.name} );") do |idx_list|
72
+ idx = indexes[idx_list['name']]
73
+
74
+ idx.sequence_number = idx_list['seq']
75
+ idx.unique = Boolean.to_bool( idx_list['unique'] )
76
+
77
+ @db.execute("PRAGMA index_info( #{idx.name} );") do |col_info|
78
+ idx.columns << table.columns[col_info['name']]
79
+ end
80
+ end
81
+ return indexes
82
+ end
83
+
84
+ ##
85
+ # load all the columns for a particular table
86
+ #
87
+ def load_columns( table )
88
+ cols = {}
89
+ @db.execute("PRAGMA table_info(#{table.name})") do |row|
90
+ col = Amalgalite::Column.new( "main", table.name, row['name'] )
91
+
92
+ col.default_value = row['dflt_value']
93
+ @db.api.table_column_metadata( "main", table.name, col.name ).each_pair do |key, value|
94
+ col.send("#{key}=", value)
95
+ end
96
+ col.schema = self
97
+ cols[col.name] = col
98
+ end
99
+ cols
100
+ end
101
+
102
+ ##
103
+ # load all the views for the database
104
+ #
105
+ def load_views
106
+ @views = {}
107
+ @db.execute("SELECT name, sql FROM sqlite_master WHERE type = 'view'") do |view_info|
108
+ view = Amalgalite::View.new( view_info['name'], view_info['sql'] )
109
+ view.schema = self
110
+ @views[view.name] = view
111
+ end
112
+ @views
113
+ end
114
+ end
115
+ end