amalgalite 0.10.1-x86-mingw32
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY +201 -0
- data/LICENSE +29 -0
- data/README +51 -0
- data/bin/amalgalite-pack +126 -0
- data/examples/a.rb +9 -0
- data/examples/blob.rb +88 -0
- data/examples/bootstrap.rb +36 -0
- data/examples/define_aggregate.rb +75 -0
- data/examples/define_function.rb +104 -0
- data/examples/gem-db.rb +94 -0
- data/examples/gems.db +0 -0
- data/examples/require_me.rb +11 -0
- data/examples/requires.rb +42 -0
- data/examples/schema-info.rb +34 -0
- data/ext/amalgalite/amalgalite3.c +290 -0
- data/ext/amalgalite/amalgalite3.h +151 -0
- data/ext/amalgalite/amalgalite3_blob.c +240 -0
- data/ext/amalgalite/amalgalite3_constants.c +221 -0
- data/ext/amalgalite/amalgalite3_database.c +1148 -0
- data/ext/amalgalite/amalgalite3_requires_bootstrap.c +210 -0
- data/ext/amalgalite/amalgalite3_statement.c +639 -0
- data/ext/amalgalite/extconf.rb +36 -0
- data/ext/amalgalite/gen_constants.rb +130 -0
- data/ext/amalgalite/sqlite3.c +106729 -0
- data/ext/amalgalite/sqlite3.h +5626 -0
- data/ext/amalgalite/sqlite3_options.h +4 -0
- data/ext/amalgalite/sqlite3ext.h +380 -0
- data/gemspec.rb +60 -0
- data/lib/amalgalite.rb +43 -0
- data/lib/amalgalite/1.8/amalgalite3.so +0 -0
- data/lib/amalgalite/1.9/amalgalite3.so +0 -0
- data/lib/amalgalite/aggregate.rb +67 -0
- data/lib/amalgalite/blob.rb +186 -0
- data/lib/amalgalite/boolean.rb +42 -0
- data/lib/amalgalite/busy_timeout.rb +47 -0
- data/lib/amalgalite/column.rb +97 -0
- data/lib/amalgalite/core_ext/kernel/require.rb +21 -0
- data/lib/amalgalite/database.rb +947 -0
- data/lib/amalgalite/function.rb +61 -0
- data/lib/amalgalite/index.rb +43 -0
- data/lib/amalgalite/packer.rb +226 -0
- data/lib/amalgalite/paths.rb +70 -0
- data/lib/amalgalite/profile_tap.rb +131 -0
- data/lib/amalgalite/progress_handler.rb +21 -0
- data/lib/amalgalite/requires.rb +120 -0
- data/lib/amalgalite/schema.rb +191 -0
- data/lib/amalgalite/sqlite3.rb +6 -0
- data/lib/amalgalite/sqlite3/constants.rb +80 -0
- data/lib/amalgalite/sqlite3/database/function.rb +48 -0
- data/lib/amalgalite/sqlite3/database/status.rb +68 -0
- data/lib/amalgalite/sqlite3/status.rb +60 -0
- data/lib/amalgalite/sqlite3/version.rb +37 -0
- data/lib/amalgalite/statement.rb +414 -0
- data/lib/amalgalite/table.rb +90 -0
- data/lib/amalgalite/taps.rb +2 -0
- data/lib/amalgalite/taps/console.rb +27 -0
- data/lib/amalgalite/taps/io.rb +71 -0
- data/lib/amalgalite/trace_tap.rb +35 -0
- data/lib/amalgalite/type_map.rb +63 -0
- data/lib/amalgalite/type_maps/default_map.rb +167 -0
- data/lib/amalgalite/type_maps/storage_map.rb +40 -0
- data/lib/amalgalite/type_maps/text_map.rb +22 -0
- data/lib/amalgalite/version.rb +37 -0
- data/lib/amalgalite/view.rb +26 -0
- data/spec/aggregate_spec.rb +169 -0
- data/spec/amalgalite_spec.rb +4 -0
- data/spec/blob_spec.rb +81 -0
- data/spec/boolean_spec.rb +23 -0
- data/spec/busy_handler.rb +165 -0
- data/spec/database_spec.rb +494 -0
- data/spec/default_map_spec.rb +87 -0
- data/spec/function_spec.rb +94 -0
- data/spec/integeration_spec.rb +111 -0
- data/spec/packer_spec.rb +60 -0
- data/spec/paths_spec.rb +28 -0
- data/spec/progress_handler_spec.rb +105 -0
- data/spec/requires_spec.rb +23 -0
- data/spec/rtree_spec.rb +71 -0
- data/spec/schema_spec.rb +120 -0
- data/spec/spec_helper.rb +27 -0
- data/spec/sqlite3/constants_spec.rb +65 -0
- data/spec/sqlite3/database_status_spec.rb +36 -0
- data/spec/sqlite3/status_spec.rb +18 -0
- data/spec/sqlite3/version_spec.rb +14 -0
- data/spec/sqlite3_spec.rb +53 -0
- data/spec/statement_spec.rb +161 -0
- data/spec/storage_map_spec.rb +41 -0
- data/spec/tap_spec.rb +59 -0
- data/spec/text_map_spec.rb +23 -0
- data/spec/type_map_spec.rb +17 -0
- data/spec/version_spec.rb +15 -0
- data/tasks/announce.rake +43 -0
- data/tasks/config.rb +107 -0
- data/tasks/distribution.rake +77 -0
- data/tasks/documentation.rake +32 -0
- data/tasks/extension.rake +141 -0
- data/tasks/rspec.rake +33 -0
- data/tasks/rubyforge.rake +59 -0
- data/tasks/utils.rb +80 -0
- metadata +237 -0
@@ -0,0 +1,90 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2008 Jeremy Hinegardner
|
3
|
+
# All rights reserved. See LICENSE and/or COPYING for details.
|
4
|
+
#++
|
5
|
+
require 'set'
|
6
|
+
module Amalgalite
|
7
|
+
#
|
8
|
+
# a class representing the meta information about an SQLite table
|
9
|
+
#
|
10
|
+
class Table
|
11
|
+
# the schema object the table is associated with
|
12
|
+
attr_accessor :schema
|
13
|
+
|
14
|
+
# the table name
|
15
|
+
attr_reader :name
|
16
|
+
|
17
|
+
# the original sql that was used to create this table
|
18
|
+
attr_reader :sql
|
19
|
+
|
20
|
+
# hash of Index objects holding the meta informationa about the indexes
|
21
|
+
# on this table. The keys of the indexes variable is the index name
|
22
|
+
attr_accessor :indexes
|
23
|
+
|
24
|
+
# a hash of Column objects holding the meta information about the columns
|
25
|
+
# in this table. keys are the column names
|
26
|
+
attr_accessor :columns
|
27
|
+
|
28
|
+
def initialize( name, sql = nil )
|
29
|
+
@name = name
|
30
|
+
@sql = sql
|
31
|
+
@indexes = {}
|
32
|
+
@columns = {}
|
33
|
+
end
|
34
|
+
|
35
|
+
# Is the table a temporary table or not
|
36
|
+
def temporary?
|
37
|
+
!sql
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
# the Columns in original definition order
|
42
|
+
def columns_in_order
|
43
|
+
@columns.values.sort_by { |c| c.order }
|
44
|
+
end
|
45
|
+
|
46
|
+
# the column names in original definition order
|
47
|
+
def column_names
|
48
|
+
columns_in_order.map { |c| c.name }
|
49
|
+
end
|
50
|
+
|
51
|
+
# the columns that make up the primary key
|
52
|
+
def primary_key_columns
|
53
|
+
@columns.values.find_all { |c| c.primary_key? }
|
54
|
+
end
|
55
|
+
|
56
|
+
# the array of colmuns that make up the primary key of the table
|
57
|
+
# since a primary key has an index, we loop over all the indexes for the
|
58
|
+
# table and pick the first one that is unique, and all the columns in the
|
59
|
+
# index have primary_key? as true.
|
60
|
+
#
|
61
|
+
# we do this instead of just looking for the columns where primary key is
|
62
|
+
# true because we want the columns in primary key order
|
63
|
+
def primary_key
|
64
|
+
unless @primary_key
|
65
|
+
pk_column_names = Set.new( primary_key_columns.collect { |c| c.name } )
|
66
|
+
unique_indexes = indexes.values.find_all { |i| i.unique? }
|
67
|
+
|
68
|
+
pk_result = []
|
69
|
+
|
70
|
+
unique_indexes.each do |idx|
|
71
|
+
idx_column_names = Set.new( idx.columns.collect { |c| c.name } )
|
72
|
+
r = idx_column_names ^ pk_column_names
|
73
|
+
if r.size == 0 then
|
74
|
+
pk_result = idx.columns
|
75
|
+
break
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# no joy, see about just using all the columns that say the are primary
|
80
|
+
# keys
|
81
|
+
if pk_result.empty? then
|
82
|
+
pk_result = self.primary_key_columns
|
83
|
+
end
|
84
|
+
@primary_key = pk_result
|
85
|
+
end
|
86
|
+
return @primary_key
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2008 Jeremy Hinegardner
|
3
|
+
# All rights reserved. See LICENSE and/or COPYING for details.
|
4
|
+
#++
|
5
|
+
|
6
|
+
require 'amalgalite/taps/io'
|
7
|
+
|
8
|
+
module Amalgalite::Taps
|
9
|
+
#
|
10
|
+
# Class provide an IO tap that can write to $stdout
|
11
|
+
#
|
12
|
+
class Stdout < ::Amalgalite::Taps::IO
|
13
|
+
def initialize
|
14
|
+
super( $stdout )
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
#
|
19
|
+
# This class provide an IO tap that can write to $stderr
|
20
|
+
#
|
21
|
+
class Stderr < ::Amalgalite::Taps::IO
|
22
|
+
def initialize
|
23
|
+
super( $stderr )
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2008 Jeremy Hinegardner
|
3
|
+
# All rights reserved. See LICENSE and/or COPYING for details.
|
4
|
+
#++
|
5
|
+
|
6
|
+
require 'amalgalite/profile_tap'
|
7
|
+
require 'stringio'
|
8
|
+
|
9
|
+
module Amalgalite
|
10
|
+
module Taps
|
11
|
+
#
|
12
|
+
# An IOTap is an easy way to send all top information to andy IO based
|
13
|
+
# object. Both profile and trace tap information can be captured
|
14
|
+
# This means you can send the events to STDOUT with:
|
15
|
+
#
|
16
|
+
# db.profile_tap = db.trace_tap = Amalgalite::Taps::Stdout.new
|
17
|
+
#
|
18
|
+
#
|
19
|
+
class IO
|
20
|
+
|
21
|
+
attr_reader :profile_tap
|
22
|
+
attr_reader :io
|
23
|
+
|
24
|
+
def initialize( io )
|
25
|
+
@io = io
|
26
|
+
@profile_tap = ProfileTap.new( self, 'output_profile_event' )
|
27
|
+
end
|
28
|
+
|
29
|
+
def trace( msg )
|
30
|
+
io.puts msg
|
31
|
+
end
|
32
|
+
|
33
|
+
# need a profile method, it routes through the profile tap which calls back
|
34
|
+
# to output_profile_event
|
35
|
+
def profile( msg, time )
|
36
|
+
@profile_tap.profile(msg, time)
|
37
|
+
end
|
38
|
+
|
39
|
+
def output_profile_event( msg, time )
|
40
|
+
io.puts "#{time} : #{msg}"
|
41
|
+
end
|
42
|
+
|
43
|
+
def dump_profile
|
44
|
+
samplers.each_pair do |k,v|
|
45
|
+
io.puts v.to_s
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def samplers
|
50
|
+
profile_tap.samplers
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
#
|
55
|
+
# This class provides an IO tap that writes to a StringIO. The result is
|
56
|
+
# available via .to_s or .string.
|
57
|
+
#
|
58
|
+
class StringIO < ::Amalgalite::Taps::IO
|
59
|
+
def initialize
|
60
|
+
@stringio = ::StringIO.new
|
61
|
+
super( @stringio )
|
62
|
+
end
|
63
|
+
|
64
|
+
def to_s
|
65
|
+
@stringio.string
|
66
|
+
end
|
67
|
+
alias :string :to_s
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
@@ -0,0 +1,35 @@
|
|
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 TraceTap receives tracing information from SQLite3. It receives the SQL
|
9
|
+
# statement being executed as a +msg+ just before the statement first begins
|
10
|
+
# executing.
|
11
|
+
#
|
12
|
+
# A TraceTap is a wrapper around another object and a method. The Tap object
|
13
|
+
# will receive the call to +trace+ and redirect that call to another object
|
14
|
+
# and method.
|
15
|
+
#
|
16
|
+
class TraceTap
|
17
|
+
|
18
|
+
attr_reader :delegate_obj
|
19
|
+
attr_reader :delegate_method
|
20
|
+
|
21
|
+
def initialize( wrapped_obj, send_to = 'trace' )
|
22
|
+
unless wrapped_obj.respond_to?( send_to )
|
23
|
+
raise Amalgalite::Error, "#{wrapped_obj.class.name} does not respond to #{send_to.to_s} "
|
24
|
+
end
|
25
|
+
|
26
|
+
@delegate_obj = wrapped_obj
|
27
|
+
@delegate_method = send_to
|
28
|
+
end
|
29
|
+
|
30
|
+
def trace( msg )
|
31
|
+
delegate_obj.send( delegate_method, msg )
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
@@ -0,0 +1,63 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2008 Jeremy Hinegardner
|
3
|
+
# All rights reserved. See LICENSE and/or COPYING for details.
|
4
|
+
#++
|
5
|
+
module Amalgalite
|
6
|
+
##
|
7
|
+
# TypeMap defines the protocol used between Ruby and SQLite for mapping
|
8
|
+
# binding types, used in prepared statements; and result types, used in
|
9
|
+
# returning objects from a query.
|
10
|
+
#
|
11
|
+
#
|
12
|
+
class TypeMap
|
13
|
+
##
|
14
|
+
# :call-seq:
|
15
|
+
# map.bind_type_of( obj ) -> DataType constant
|
16
|
+
#
|
17
|
+
# bind_type_of is called during the Statement#bind process to convert the
|
18
|
+
# bind parameter to the appropriate SQLite types. This method MUST return
|
19
|
+
# one of the valid constants in the namespace
|
20
|
+
# Amalgalite::SQLite::Constants::DataType
|
21
|
+
#
|
22
|
+
def bind_type_of( obj )
|
23
|
+
raise NotImplementedError, "bind_type_of has not been implemented"
|
24
|
+
end
|
25
|
+
|
26
|
+
##
|
27
|
+
# :call-seq:
|
28
|
+
# map.result_value_of( declared_type, value ) -> String
|
29
|
+
#
|
30
|
+
# result_value_of is called during the result processing of column values
|
31
|
+
# to convert an SQLite database value into the appropriate Ruby class.
|
32
|
+
#
|
33
|
+
# +declared_type+ is the string from the original CREATE TABLE statment
|
34
|
+
# from which the column value originates. It may also be nil if the origin
|
35
|
+
# column cannot be determined.
|
36
|
+
#
|
37
|
+
# +value+ is the SQLite value from the column as either a Ruby String,
|
38
|
+
# Integer, Float or Amalgalite::Blob.
|
39
|
+
#
|
40
|
+
# result_value should return the value that is to be put into the result set
|
41
|
+
# for the query. It may do nothing, or it may do massive amounts of
|
42
|
+
# conversion.
|
43
|
+
def result_value_of( delcared_type, value )
|
44
|
+
raise NotImplementedError, "result_value_of has not been implemented"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
##
|
49
|
+
# The TypeMaps module holds all typemaps that ship with Amagalite. They
|
50
|
+
# currently are:
|
51
|
+
#
|
52
|
+
# DefaultMap:: does a 'best-guess' mapping to convert as many types as
|
53
|
+
# possible to known ruby classes from known SQL types.
|
54
|
+
# StorageMap:: converts to a limited set of classes directly based
|
55
|
+
# upon the SQLite storage types
|
56
|
+
# TextMap:: Everything is Text ... everything everything everything
|
57
|
+
#
|
58
|
+
module TypeMaps
|
59
|
+
end
|
60
|
+
end
|
61
|
+
require 'amalgalite/type_maps/default_map'
|
62
|
+
require 'amalgalite/type_maps/storage_map'
|
63
|
+
require 'amalgalite/type_maps/text_map'
|
@@ -0,0 +1,167 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2008 Jeremy Hinegardner
|
3
|
+
# All rights reserved. See LICENSE and/or COPYING for details.
|
4
|
+
#++
|
5
|
+
|
6
|
+
require 'amalgalite/type_map'
|
7
|
+
require 'time'
|
8
|
+
require 'date'
|
9
|
+
|
10
|
+
module Amalgalite::TypeMaps
|
11
|
+
##
|
12
|
+
# An Amalgalite::TypeMap that does its best to convert between Ruby classes
|
13
|
+
# and known SQL data types.
|
14
|
+
#
|
15
|
+
# Upon instantiation, DefaultMap generates a conversion map to try to figure
|
16
|
+
# out the best way to convert between populate SQL 'types' and ruby classes
|
17
|
+
#
|
18
|
+
class DefaultMap
|
19
|
+
class << self
|
20
|
+
def methods_handling_sql_types # :nodoc:
|
21
|
+
@methods_handling_sql_types ||= {
|
22
|
+
'date' => %w[ date ],
|
23
|
+
'datetime' => %w[ datetime ],
|
24
|
+
'time' => %w[ timestamp time ],
|
25
|
+
'float' => %w[ double real numeric decimal ],
|
26
|
+
'integer' => %w[ integer tinyint smallint int int2 int4 int8 bigint serial bigserial ],
|
27
|
+
'string' => %w[ text char varchar character ],
|
28
|
+
'boolean' => %w[ bool boolean ],
|
29
|
+
'blob' => %w[ binary blob ],
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
# say what method to call to convert an sql type to a ruby type
|
34
|
+
#
|
35
|
+
def sql_to_method( sql_type ) # :nodoc:
|
36
|
+
unless defined? @sql_to_method
|
37
|
+
@sql_to_method = {}
|
38
|
+
methods_handling_sql_types.each_pair do |method, sql_types|
|
39
|
+
sql_types.each { |t| @sql_to_method[t] = method }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
return_method = @sql_to_method[sql_type]
|
43
|
+
|
44
|
+
# the straight lookup didn't work, try iterating through the types and
|
45
|
+
# see what is found
|
46
|
+
unless return_method
|
47
|
+
@sql_to_method.each_pair do |sql, method|
|
48
|
+
if sql_type.index(sql) then
|
49
|
+
return_method = method
|
50
|
+
break
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
return return_method
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def initialize
|
59
|
+
end
|
60
|
+
|
61
|
+
##
|
62
|
+
# A straight logical mapping (for me at least) of basic Ruby classes to SQLite types, if
|
63
|
+
# nothing can be found then default to TEXT.
|
64
|
+
#
|
65
|
+
def bind_type_of( obj )
|
66
|
+
case obj
|
67
|
+
when Float
|
68
|
+
::Amalgalite::SQLite3::Constants::DataType::FLOAT
|
69
|
+
when Fixnum
|
70
|
+
::Amalgalite::SQLite3::Constants::DataType::INTEGER
|
71
|
+
when NilClass
|
72
|
+
::Amalgalite::SQLite3::Constants::DataType::NULL
|
73
|
+
when ::Amalgalite::Blob
|
74
|
+
::Amalgalite::SQLite3::Constants::DataType::BLOB
|
75
|
+
else
|
76
|
+
::Amalgalite::SQLite3::Constants::DataType::TEXT
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
##
|
81
|
+
# Map the incoming value to an outgoing value. For some incoming values,
|
82
|
+
# there will be no change, but for some (i.e. Dates and Times) there is some
|
83
|
+
# conversion
|
84
|
+
#
|
85
|
+
def result_value_of( declared_type, value )
|
86
|
+
case value
|
87
|
+
when Numeric
|
88
|
+
return value
|
89
|
+
when NilClass
|
90
|
+
return value
|
91
|
+
when Amalgalite::Blob
|
92
|
+
return value
|
93
|
+
when String
|
94
|
+
if declared_type then
|
95
|
+
conversion_method = DefaultMap.sql_to_method( declared_type.downcase )
|
96
|
+
if conversion_method then
|
97
|
+
return send(conversion_method, value)
|
98
|
+
else
|
99
|
+
raise ::Amalgalite::Error, "Unable to convert SQL type of #{declared_type} to a Ruby class"
|
100
|
+
end
|
101
|
+
else
|
102
|
+
# unable to do any other conversion, just return what we have.
|
103
|
+
return value
|
104
|
+
end
|
105
|
+
else
|
106
|
+
raise ::Amalgalite::Error, "Unable to convert a class #{value.class.name} with value #{value.inspect}"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
##
|
111
|
+
# convert a string to a date
|
112
|
+
#
|
113
|
+
def date( str )
|
114
|
+
Date.parse( str )
|
115
|
+
end
|
116
|
+
|
117
|
+
##
|
118
|
+
# convert a string to a datetime, if no timzone is found in the parsed
|
119
|
+
# string, set it to the local offset.
|
120
|
+
#
|
121
|
+
def datetime( str )
|
122
|
+
DateTime.parse( str )
|
123
|
+
end
|
124
|
+
|
125
|
+
##
|
126
|
+
# convert a string to a Time
|
127
|
+
#
|
128
|
+
def time( str )
|
129
|
+
Time.parse( str )
|
130
|
+
end
|
131
|
+
|
132
|
+
##
|
133
|
+
# convert a string to a Float
|
134
|
+
#
|
135
|
+
def float( str )
|
136
|
+
Float( str )
|
137
|
+
end
|
138
|
+
|
139
|
+
##
|
140
|
+
# convert an string to an Integer
|
141
|
+
#
|
142
|
+
def integer( str )
|
143
|
+
Float( str ).to_i
|
144
|
+
end
|
145
|
+
|
146
|
+
##
|
147
|
+
# convert a string to a String, yes redundant I know.
|
148
|
+
#
|
149
|
+
def string( str )
|
150
|
+
str
|
151
|
+
end
|
152
|
+
|
153
|
+
##
|
154
|
+
# convert a string to true of false
|
155
|
+
#
|
156
|
+
def boolean( str )
|
157
|
+
::Amalgalite::Boolean.to_bool( str )
|
158
|
+
end
|
159
|
+
|
160
|
+
##
|
161
|
+
# convert a string to a blob
|
162
|
+
#
|
163
|
+
def blob( str )
|
164
|
+
::Amalgalite::Blob.new( :string => str )
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|