amalgalite 0.4.2-x86-mswin32-60

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