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
Binary file
|
Binary file
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'amalgalite/sqlite3/database/function'
|
2
|
+
module Amalgalite
|
3
|
+
#
|
4
|
+
# A Base class to inherit from for creating your own SQL aggregate functions
|
5
|
+
# in ruby.
|
6
|
+
#
|
7
|
+
# These are SQL functions similar to _max(X)_, _count(X)_, _avg(X)_. The built
|
8
|
+
# in SQLite aggregate functions are:
|
9
|
+
#
|
10
|
+
# * http://www.sqlite.org/lang_aggfunc.html
|
11
|
+
#
|
12
|
+
# If you choose to use Aggregate as a parent class of your SQL scalar function
|
13
|
+
# implementation you must:
|
14
|
+
#
|
15
|
+
# * implement _initalize_ with 0 arguments
|
16
|
+
# * set the @arity data member
|
17
|
+
# * set the @name data member
|
18
|
+
# * implement _step_ with arity of +@arity+
|
19
|
+
# * implement _finalize_ with arity of 0
|
20
|
+
#
|
21
|
+
# For instance to implement a <i>unique_word_count(X)</i> aggregate function you could
|
22
|
+
# implement it as:
|
23
|
+
#
|
24
|
+
# class UniqueWordCount < ::Amalgalite::Aggregate
|
25
|
+
# attr_accessor :words
|
26
|
+
#
|
27
|
+
# def initialize
|
28
|
+
# @name = 'unique_word_count'
|
29
|
+
# @arity = 1
|
30
|
+
# @words = Hash.new { |h,k| h[k] = 0 }
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# def step( str )
|
34
|
+
# str.split(/\W+/).each do |word|
|
35
|
+
# words[ word.downcase ] += 1
|
36
|
+
# end
|
37
|
+
# return nil
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# def finalize
|
41
|
+
# return words.size
|
42
|
+
# end
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
#
|
46
|
+
class Aggregate
|
47
|
+
# The name of the SQL function
|
48
|
+
attr_accessor :name
|
49
|
+
|
50
|
+
# The arity of the SQL function
|
51
|
+
attr_accessor :arity
|
52
|
+
|
53
|
+
# finalize should return the final value of the aggregate function
|
54
|
+
def finalize
|
55
|
+
raise NotImplementedError, "Aggregate#finalize must be implemented"
|
56
|
+
end
|
57
|
+
|
58
|
+
# <b>Do Not Override</b>
|
59
|
+
#
|
60
|
+
# The function signature for use by the Amaglaite datase in tracking
|
61
|
+
# function creation.
|
62
|
+
#
|
63
|
+
def signature
|
64
|
+
@signature ||= ::Amalgalite::SQLite3::Database::Function.signature( self.name, self.arity )
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2008 Jeremy Hinegardner
|
3
|
+
# All rights reserved. See LICENSE and/or COPYING for details.
|
4
|
+
#++
|
5
|
+
module Amalgalite
|
6
|
+
##
|
7
|
+
# This is the interface to allow Blob objects to be written to and read from
|
8
|
+
# the SQLite database. When using statements, use a Blob object as
|
9
|
+
# the wrapper around the source to be written to the row, and a Blob object is
|
10
|
+
# returned if the the type mapping warrents during select queries.
|
11
|
+
#
|
12
|
+
# For instance during an insert:
|
13
|
+
#
|
14
|
+
# blob_column = db.schema.tables['blobs'].columns['data']
|
15
|
+
# db.execute("INSERT INTO blobs(name, data) VALUES ( $name, $blob )",
|
16
|
+
# { "$name" => "/path/to/file",
|
17
|
+
# "$blob" => Amalgalite::Blob.new( :file => '/path/to/file',
|
18
|
+
# :column => blob_column) } )
|
19
|
+
#
|
20
|
+
# db.execute("INSERT INTO blobs(id, data) VALUES ($id, $blob )",
|
21
|
+
# { "$name" => 'blobname',
|
22
|
+
# "$blob" => Amalgalite::Blob.new( :io => "something with .read and .length methods",
|
23
|
+
# :column => blob_column) } )
|
24
|
+
#
|
25
|
+
# On select the blob data needs to be read into an IO object
|
26
|
+
#
|
27
|
+
# all_rows = db.execute("SELECT name, blob FROM blobs WHERE name = '/path/to/file' ")
|
28
|
+
# blob_row = all_rows.first
|
29
|
+
# blob_row['blob'].write_to_file( blob_row['name'] )
|
30
|
+
#
|
31
|
+
# Or write to an IO object
|
32
|
+
#
|
33
|
+
# blob_results = {}
|
34
|
+
# db.execute("SELECT name, blob FROM blobs") do |row|
|
35
|
+
# io = StringIO.new
|
36
|
+
# row['blob'].write_to_io( io )
|
37
|
+
# blob_results[row['name']] = io
|
38
|
+
# # or use a shortcut
|
39
|
+
# # blob_results[row['name']] = row['blob'].to_string_io
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# If using a Blob as a conditional, for instance in a WHERE clause then the
|
43
|
+
# Blob must resolvable to a String.
|
44
|
+
#
|
45
|
+
# db.execute("SELECT FROM blobs(name, data) WHERE data = $blob",
|
46
|
+
# { "$blob' => Amalgalite::Blob.new( :string => "A string of data" ) })
|
47
|
+
#
|
48
|
+
class Blob
|
49
|
+
class Error < ::Amalgalite::Error; end
|
50
|
+
class << self
|
51
|
+
def valid_source_params
|
52
|
+
@valid_source_params ||= [ :file, :io, :string, :db_blob ]
|
53
|
+
end
|
54
|
+
|
55
|
+
def default_block_size
|
56
|
+
@default_block_size ||= 8192
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# the object representing the source of the blob
|
61
|
+
attr_reader :source
|
62
|
+
|
63
|
+
# the size in bytes of the of the blob
|
64
|
+
attr_reader :length
|
65
|
+
|
66
|
+
# the size in bytes of the blocks of data to move from the source
|
67
|
+
attr_reader :block_size
|
68
|
+
|
69
|
+
# the column the blob is associated with
|
70
|
+
attr_reader :column
|
71
|
+
|
72
|
+
##
|
73
|
+
# Initialize a new blob, it takes a single parameter, a hash which describes
|
74
|
+
# the source of the blob. The keys of the hash are one of:
|
75
|
+
#
|
76
|
+
# :file : the value is the path to a file on the file system
|
77
|
+
# :io : the value is an object that responds to the the methods +read+
|
78
|
+
# and +length+. +read+ should have the behavior of IO#read
|
79
|
+
# :db_blob : not normally used by an end user, used to initialize a blob
|
80
|
+
# object that is returned from an SQL query.
|
81
|
+
# :string : used when a Blob is part of a WHERE clause or result
|
82
|
+
#
|
83
|
+
# And additional key of :block_size may be used to indicate the maximum size
|
84
|
+
# of a single block of data to move from the source to the destination, this
|
85
|
+
# defaults ot 8192.
|
86
|
+
#
|
87
|
+
def initialize( params )
|
88
|
+
if (Blob.valid_source_params & params.keys).size > 1 then
|
89
|
+
raise Blob::Error, "Only a one of #{Blob.valid_source_params.join(', ')} is allowed to initialize a Blob. #{params.keys.join(', ')} were sent"
|
90
|
+
end
|
91
|
+
|
92
|
+
@source = nil
|
93
|
+
@source_length = 0
|
94
|
+
@close_source_after_read = false
|
95
|
+
@incremental = true
|
96
|
+
@block_size = params[:block_size] || Blob.default_block_size
|
97
|
+
@column = params[:column]
|
98
|
+
|
99
|
+
raise Blob::Error, "A :column parameter is required for a Blob" unless @column or params.has_key?( :string )
|
100
|
+
|
101
|
+
if params.has_key?( :file ) then
|
102
|
+
@source = File.open( params[:file], "r" )
|
103
|
+
@length = File.size( params[:file] )
|
104
|
+
@close_source_after_read = true
|
105
|
+
elsif params.has_key?( :io ) then
|
106
|
+
@source = params[:io]
|
107
|
+
@length = @source.length
|
108
|
+
elsif params.has_key?( :db_blob ) then
|
109
|
+
@source = params[:db_blob]
|
110
|
+
@length = @source.length
|
111
|
+
@close_source_after_read = true
|
112
|
+
elsif params.has_key?( :string ) then
|
113
|
+
@source = params[:string]
|
114
|
+
@length = @source.length
|
115
|
+
@incremental = false
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
##
|
120
|
+
# close the source when done reading from it
|
121
|
+
#
|
122
|
+
def close_source_after_read?
|
123
|
+
@close_source_after_read
|
124
|
+
end
|
125
|
+
|
126
|
+
##
|
127
|
+
# is this an incremental Blob or not
|
128
|
+
#
|
129
|
+
def incremental?
|
130
|
+
@incremental
|
131
|
+
end
|
132
|
+
|
133
|
+
##
|
134
|
+
# Write the Blob to an IO object
|
135
|
+
#
|
136
|
+
def write_to_io( io )
|
137
|
+
if source.respond_to?( :read ) then
|
138
|
+
while buf = source.read( block_size ) do
|
139
|
+
io.write( buf )
|
140
|
+
end
|
141
|
+
else
|
142
|
+
io.write( source.to_s )
|
143
|
+
end
|
144
|
+
|
145
|
+
if close_source_after_read? then
|
146
|
+
source.close
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
##
|
151
|
+
# conver the blob to a string
|
152
|
+
#
|
153
|
+
def to_s
|
154
|
+
to_string_io.string
|
155
|
+
end
|
156
|
+
|
157
|
+
##
|
158
|
+
# write the Blob contents to a StringIO
|
159
|
+
#
|
160
|
+
def to_string_io
|
161
|
+
sio = StringIO.new
|
162
|
+
write_to_io( sio )
|
163
|
+
return sio
|
164
|
+
end
|
165
|
+
|
166
|
+
##
|
167
|
+
# Write the Blob contents to a File.
|
168
|
+
#
|
169
|
+
def write_to_file( filename, modestring="w" )
|
170
|
+
File.open(filename, modestring) do |f|
|
171
|
+
write_to_io( f )
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
##
|
176
|
+
# Write the Blob contents to the column. This assumes that the row_id to
|
177
|
+
# insert into is the last row that was inserted into the db
|
178
|
+
#
|
179
|
+
def write_to_column!
|
180
|
+
last_rowid = column.schema.db.last_insert_rowid
|
181
|
+
SQLite3::Blob.new( column.schema.db.api, column.db, column.table, column.name, last_rowid, "w" ) do |sqlite_blob|
|
182
|
+
write_to_io( sqlite_blob )
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2008 Jeremy Hinegardner
|
3
|
+
# All rights reserved. See LICENSE and/or COPYING for details.
|
4
|
+
#++
|
5
|
+
module Amalgalite
|
6
|
+
##
|
7
|
+
# Do type conversion on values that could be boolen values into
|
8
|
+
# real 'true' or 'false'
|
9
|
+
#
|
10
|
+
# This is pulled from the possible boolean values from PostgreSQL
|
11
|
+
#
|
12
|
+
class Boolean
|
13
|
+
class << self
|
14
|
+
#
|
15
|
+
# list of downcased strings are potential true values
|
16
|
+
#
|
17
|
+
def true_values
|
18
|
+
@true_values ||= %w[ true t yes y 1 ]
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
# list of downcased strings are potential false values
|
23
|
+
#
|
24
|
+
def false_values
|
25
|
+
@false_values ||= %w[ false f no n 0 ]
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
# Convert +val+ to a string and attempt to convert it to +true+ or +false+
|
30
|
+
#
|
31
|
+
def to_bool( val )
|
32
|
+
return false if val.nil?
|
33
|
+
unless defined? @to_bool
|
34
|
+
@to_bool = {}
|
35
|
+
true_values.each { |t| @to_bool[t] = true }
|
36
|
+
false_values.each { |f| @to_bool[f] = false }
|
37
|
+
end
|
38
|
+
return @to_bool[val.to_s.downcase]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Amalgalite
|
2
|
+
##
|
3
|
+
# A base class for use in creating your own busy handler classes
|
4
|
+
#
|
5
|
+
class BusyHandler
|
6
|
+
def to_proc
|
7
|
+
self
|
8
|
+
end
|
9
|
+
|
10
|
+
# the arity of the call method
|
11
|
+
def arity() 1 ; end
|
12
|
+
|
13
|
+
##
|
14
|
+
# Override this method, returning +false+ if the SQLite should return
|
15
|
+
# SQLITE_BUSY for all parties involved in the lock, and anything else if the
|
16
|
+
# lock attempt should be tried again.
|
17
|
+
def call( count )
|
18
|
+
raise NotImplementedError, "The busy handler call(N) method must be implemented"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# A busy time out class for use in Database#define_busy_handler
|
24
|
+
#
|
25
|
+
class BusyTimeout < BusyHandler
|
26
|
+
attr_reader :call_count
|
27
|
+
##
|
28
|
+
# intialize by setting _count_ and _duration_ ( in milliseconds ).
|
29
|
+
#
|
30
|
+
def initialize( count = 20 , duration = 50 )
|
31
|
+
@count = count
|
32
|
+
@duration = duration.to_f / 1_000
|
33
|
+
@call_count = 0
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# return +false+ if _callcount_ is > _count_ otherwise sleep for _duration_
|
38
|
+
# milliseconds and then return +true+
|
39
|
+
#
|
40
|
+
def call( call_count )
|
41
|
+
@call_count = call_count
|
42
|
+
return false if ( call_count > @count )
|
43
|
+
sleep @duration
|
44
|
+
return true
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2008 Jeremy Hinegardner
|
3
|
+
# All rights reserved. See LICENSE and/or COPYING for details.
|
4
|
+
#++
|
5
|
+
|
6
|
+
require 'amalgalite/boolean'
|
7
|
+
require 'amalgalite/blob'
|
8
|
+
|
9
|
+
module Amalgalite
|
10
|
+
##
|
11
|
+
# a class representing the meta information about an SQLite column, this class
|
12
|
+
# serves both for general Schema level information, and for result set
|
13
|
+
# information from a SELECT query.
|
14
|
+
#
|
15
|
+
class Column
|
16
|
+
# the schema object this column is associated with
|
17
|
+
attr_accessor :schema
|
18
|
+
|
19
|
+
# the database name this column belongs to
|
20
|
+
attr_accessor :db
|
21
|
+
|
22
|
+
# the column name
|
23
|
+
attr_accessor :name
|
24
|
+
|
25
|
+
# the table to which this column belongs
|
26
|
+
attr_accessor :table
|
27
|
+
|
28
|
+
# the default value of the column. This may not have a value and that
|
29
|
+
# either means that there is no default value, or one could not be
|
30
|
+
# determined.
|
31
|
+
#
|
32
|
+
attr_accessor :default_value
|
33
|
+
|
34
|
+
# the declared data type of the column in the original sql that created the
|
35
|
+
# column
|
36
|
+
attr_accessor :declared_data_type
|
37
|
+
|
38
|
+
# the collation sequence name of the column
|
39
|
+
attr_accessor :collation_sequence_name
|
40
|
+
|
41
|
+
# The index (starting with 0) of this column in the table definition
|
42
|
+
# or result set
|
43
|
+
attr_accessor :order
|
44
|
+
|
45
|
+
##
|
46
|
+
# Create a column with its name and associated table
|
47
|
+
#
|
48
|
+
def initialize( db, table, name, order)
|
49
|
+
@db = db
|
50
|
+
@name = name
|
51
|
+
@table = table
|
52
|
+
@order = Float(order).to_i
|
53
|
+
@declared_data_type = nil
|
54
|
+
@default_value = nil
|
55
|
+
end
|
56
|
+
|
57
|
+
# true if the column has a default value
|
58
|
+
def has_default_value?
|
59
|
+
not default_value.nil?
|
60
|
+
end
|
61
|
+
|
62
|
+
# true if the column may have a NULL value
|
63
|
+
def nullable?
|
64
|
+
@not_null_constraint == false
|
65
|
+
end
|
66
|
+
|
67
|
+
# set whether or not the column has a not null constraint
|
68
|
+
def not_null_constraint=( other )
|
69
|
+
@not_null_constraint = Boolean.to_bool( other )
|
70
|
+
end
|
71
|
+
|
72
|
+
# true if the column as a NOT NULL constraint
|
73
|
+
def not_null_constraint?
|
74
|
+
@not_null_constraint
|
75
|
+
end
|
76
|
+
|
77
|
+
# set whether or not the column is a primary key column
|
78
|
+
def primary_key=( other )
|
79
|
+
@primary_key = Boolean.to_bool( other )
|
80
|
+
end
|
81
|
+
|
82
|
+
# true if the column is a primary key column
|
83
|
+
def primary_key?
|
84
|
+
@primary_key
|
85
|
+
end
|
86
|
+
|
87
|
+
# set whether or not the column is auto increment
|
88
|
+
def auto_increment=( other )
|
89
|
+
@auto_increment = Boolean.to_bool( other )
|
90
|
+
end
|
91
|
+
|
92
|
+
# true if the column is auto increment
|
93
|
+
def auto_increment?
|
94
|
+
@auto_increment
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|