amalgalite 0.2.4 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY +30 -5
- data/bin/amalgalite-pack-into-db +155 -0
- data/examples/a.rb +9 -0
- data/examples/blob.rb +105 -0
- data/examples/bootstrap.rb +36 -0
- data/examples/filestore.db +0 -0
- data/examples/gem-db.rb +94 -0
- data/examples/requires.rb +54 -0
- data/examples/schema-info.rb +34 -0
- data/ext/amalgalite3.c +40 -31
- data/ext/amalgalite3_blob.c +7 -12
- data/ext/amalgalite3_constants.c +41 -4
- data/ext/amalgalite3_database.c +55 -5
- data/ext/amalgalite3_requires_bootstrap.c +204 -0
- data/ext/amalgalite3_statement.c +3 -4
- data/ext/extconf.rb +2 -0
- data/ext/gen_constants.rb +15 -4
- data/ext/sqlite3.c +68652 -59046
- data/ext/sqlite3.h +2613 -1939
- data/ext/sqlite3ext.h +13 -3
- data/gemspec.rb +0 -1
- data/lib/amalgalite.rb +22 -18
- data/lib/amalgalite/core_ext/kernel/require.rb +2 -2
- data/lib/amalgalite/database.rb +15 -6
- data/lib/amalgalite/index.rb +19 -3
- data/lib/amalgalite/requires.rb +37 -0
- data/lib/amalgalite/schema.rb +26 -5
- data/lib/amalgalite/sqlite3.rb +2 -0
- data/lib/amalgalite/sqlite3/constants.rb +51 -14
- data/lib/amalgalite/sqlite3/database/status.rb +69 -0
- data/lib/amalgalite/sqlite3/status.rb +61 -0
- data/lib/amalgalite/statement.rb +1 -1
- data/lib/amalgalite/table.rb +5 -5
- data/lib/amalgalite/type_map.rb +3 -0
- data/lib/amalgalite/version.rb +2 -2
- data/spec/blob_spec.rb +1 -1
- data/spec/boolean_spec.rb +0 -3
- data/spec/database_spec.rb +11 -3
- data/spec/schema_spec.rb +14 -0
- data/spec/sqlite3/constants_spec.rb +44 -4
- data/spec/sqlite3/database_status_spec.rb +36 -0
- data/spec/sqlite3/status_spec.rb +18 -0
- data/spec/sqlite3/version_spec.rb +3 -3
- data/spec/sqlite3_spec.rb +0 -12
- data/tasks/announce.rake +2 -1
- data/tasks/config.rb +2 -1
- data/tasks/distribution.rake +7 -0
- data/tasks/rubyforge.rake +14 -6
- metadata +53 -36
data/ext/sqlite3ext.h
CHANGED
@@ -15,7 +15,7 @@
|
|
15
15
|
** as extensions by SQLite should #include this file instead of
|
16
16
|
** sqlite3.h.
|
17
17
|
**
|
18
|
-
** @(#) $Id: sqlite3ext.h,v 1.
|
18
|
+
** @(#) $Id: sqlite3ext.h,v 1.24 2008/06/30 15:09:29 danielk1977 Exp $
|
19
19
|
*/
|
20
20
|
#ifndef _SQLITE3EXT_H_
|
21
21
|
#define _SQLITE3EXT_H_
|
@@ -78,7 +78,7 @@ struct sqlite3_api_routines {
|
|
78
78
|
int (*complete)(const char*sql);
|
79
79
|
int (*complete16)(const void*sql);
|
80
80
|
int (*create_collation)(sqlite3*,const char*,int,void*,int(*)(void*,int,const void*,int,const void*));
|
81
|
-
int (*create_collation16)(sqlite3*,const
|
81
|
+
int (*create_collation16)(sqlite3*,const void*,int,void*,int(*)(void*,int,const void*,int,const void*));
|
82
82
|
int (*create_function)(sqlite3*,const char*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*));
|
83
83
|
int (*create_function16)(sqlite3*,const void*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*));
|
84
84
|
int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*);
|
@@ -188,6 +188,11 @@ struct sqlite3_api_routines {
|
|
188
188
|
int (*test_control)(int, ...);
|
189
189
|
void (*randomness)(int,void*);
|
190
190
|
sqlite3 *(*context_db_handle)(sqlite3_context*);
|
191
|
+
int (*extended_result_codes)(sqlite3*,int);
|
192
|
+
int (*limit)(sqlite3*,int,int);
|
193
|
+
sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*);
|
194
|
+
const char *(*sql)(sqlite3_stmt*);
|
195
|
+
int (*status)(int,int*,int*,int);
|
191
196
|
};
|
192
197
|
|
193
198
|
/*
|
@@ -354,9 +359,14 @@ struct sqlite3_api_routines {
|
|
354
359
|
#define sqlite3_test_control sqlite3_api->test_control
|
355
360
|
#define sqlite3_randomness sqlite3_api->randomness
|
356
361
|
#define sqlite3_context_db_handle sqlite3_api->context_db_handle
|
362
|
+
#define sqlite3_extended_result_codes sqlite3_api->extended_result_codes
|
363
|
+
#define sqlite3_limit sqlite3_api->limit
|
364
|
+
#define sqlite3_next_stmt sqlite3_api->next_stmt
|
365
|
+
#define sqlite3_sql sqlite3_api->sql
|
366
|
+
#define sqlite3_status sqlite3_api->status
|
357
367
|
#endif /* SQLITE_CORE */
|
358
368
|
|
359
|
-
#define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api;
|
369
|
+
#define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api = 0;
|
360
370
|
#define SQLITE_EXTENSION_INIT2(v) sqlite3_api = v;
|
361
371
|
|
362
372
|
#endif /* _SQLITE3EXT_H_ */
|
data/gemspec.rb
CHANGED
@@ -28,7 +28,6 @@ Amalgalite::GEM_SPEC = Gem::Specification.new do |spec|
|
|
28
28
|
if ext_conf = Configuration.for_if_exist?("extension") then
|
29
29
|
spec.extensions << ext_conf.configs
|
30
30
|
spec.extensions.flatten!
|
31
|
-
spec.require_paths << "ext"
|
32
31
|
end
|
33
32
|
|
34
33
|
if rdoc = Configuration.for_if_exist?('rdoc') then
|
data/lib/amalgalite.rb
CHANGED
@@ -3,27 +3,31 @@
|
|
3
3
|
# All rights reserved. See LICENSE and/or COPYING for details.
|
4
4
|
#++
|
5
5
|
|
6
|
+
# check if sqlite3 has already been required. Amalgalite conflicts with system
|
7
|
+
# level sqlite3 libraries.
|
8
|
+
unless $LOADED_FEATURES.grep( /sqlite3/ ).empty? then
|
9
|
+
raise LoadError, "amalgalite conflicts with sqlite3-ruby, please choose one or the other."
|
10
|
+
end
|
11
|
+
|
6
12
|
module Amalgalite
|
7
13
|
#
|
8
14
|
# Base class of all errors in Amalgalite
|
9
15
|
#
|
10
16
|
class Error < ::StandardError; end
|
11
17
|
end
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
require "amalgalite/#{lib}"
|
29
|
-
end
|
18
|
+
require 'amalgalite/blob'
|
19
|
+
require 'amalgalite/boolean'
|
20
|
+
require 'amalgalite/column'
|
21
|
+
require 'amalgalite/database'
|
22
|
+
require 'amalgalite/index'
|
23
|
+
require 'amalgalite/paths'
|
24
|
+
require 'amalgalite/profile_tap'
|
25
|
+
require 'amalgalite/schema'
|
26
|
+
require 'amalgalite/sqlite3'
|
27
|
+
require 'amalgalite/statement'
|
28
|
+
require 'amalgalite/table'
|
29
|
+
require 'amalgalite/taps'
|
30
|
+
require 'amalgalite/trace_tap'
|
31
|
+
require 'amalgalite/type_map'
|
32
|
+
require 'amalgalite/version'
|
33
|
+
require 'amalgalite/view'
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Kernel
|
2
|
-
alias :
|
2
|
+
alias :amalgalite_original_require :require
|
3
3
|
#
|
4
4
|
# hook into the system 'require' to allow for required text or blobs from an
|
5
5
|
# amalgalite database.
|
@@ -7,7 +7,7 @@ module Kernel
|
|
7
7
|
def require( filename )
|
8
8
|
found = Amalgalite::Requires.require( filename )
|
9
9
|
unless found
|
10
|
-
found =
|
10
|
+
found = amalgalite_original_require( filename )
|
11
11
|
end
|
12
12
|
return found
|
13
13
|
end
|
data/lib/amalgalite/database.rb
CHANGED
@@ -467,14 +467,22 @@ module Amalgalite
|
|
467
467
|
# issued upon leaving the block.
|
468
468
|
#
|
469
469
|
# If no block is passed in then you are on your own.
|
470
|
+
#
|
471
|
+
# Nested transactions are not supported by SQLite, but they are faked here.
|
472
|
+
# If you call transaction within a transaction, no new transaction is
|
473
|
+
# started, the current one is just continued.
|
470
474
|
#
|
471
475
|
def transaction( mode = TransactionBehavior::DEFERRED )
|
472
476
|
raise Amalgalite::Error, "Invalid transaction behavior mode #{mode}" unless TransactionBehavior.valid?( mode )
|
473
|
-
|
474
|
-
|
477
|
+
|
478
|
+
# if already in a transaction, no need to start a new one.
|
479
|
+
if not in_transaction? then
|
480
|
+
execute( "BEGIN #{mode} TRANSACTION" )
|
481
|
+
end
|
482
|
+
|
475
483
|
if block_given? then
|
476
484
|
begin
|
477
|
-
yield self
|
485
|
+
return ( yield self )
|
478
486
|
ensure
|
479
487
|
if $! then
|
480
488
|
rollback
|
@@ -483,22 +491,23 @@ module Amalgalite
|
|
483
491
|
commit
|
484
492
|
end
|
485
493
|
end
|
494
|
+
else
|
495
|
+
return in_transaction?
|
486
496
|
end
|
487
|
-
return in_transaction?
|
488
497
|
end
|
489
498
|
|
490
499
|
##
|
491
500
|
# Commit a transaction
|
492
501
|
#
|
493
502
|
def commit
|
494
|
-
execute( "COMMIT" )
|
503
|
+
execute( "COMMIT" ) if in_transaction?
|
495
504
|
end
|
496
505
|
|
497
506
|
##
|
498
507
|
# Rollback a transaction
|
499
508
|
#
|
500
509
|
def rollback
|
501
|
-
execute( "ROLLBACK" )
|
510
|
+
execute( "ROLLBACK" ) if in_transaction?
|
502
511
|
end
|
503
512
|
end
|
504
513
|
end
|
data/lib/amalgalite/index.rb
CHANGED
@@ -17,10 +17,26 @@ module Amalgalite
|
|
17
17
|
# the table the index is for
|
18
18
|
attr_accessor :table
|
19
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
|
+
|
20
29
|
def initialize( name, sql, table )
|
21
|
-
@name
|
22
|
-
@sql
|
23
|
-
@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
|
24
40
|
end
|
25
41
|
end
|
26
42
|
end
|
data/lib/amalgalite/requires.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'amalgalite'
|
2
|
+
|
1
3
|
module Amalgalite
|
2
4
|
#
|
3
5
|
# Requires encapsulates requiring itesm from the database
|
@@ -22,6 +24,41 @@ module Amalgalite
|
|
22
24
|
def require( filename )
|
23
25
|
load_path.each { |lp| lp.require( filename ) }
|
24
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
|
25
62
|
end
|
26
63
|
|
27
64
|
attr_reader :dbfile_name
|
data/lib/amalgalite/schema.rb
CHANGED
@@ -48,18 +48,39 @@ module Amalgalite
|
|
48
48
|
table = Amalgalite::Table.new( table_info['tbl_name'], table_info['sql'] )
|
49
49
|
table.columns = load_columns( table )
|
50
50
|
table.schema = self
|
51
|
+
table.indexes = load_indexes( table )
|
51
52
|
|
52
|
-
@db.prepare("SELECT name, sql FROM sqlite_master WHERE type ='index' and tbl_name = @name") do |idx_stmt|
|
53
|
-
idx_stmt.execute( "@name" => table.name) do |idx_info|
|
54
|
-
table.indexes << Amalgalite::Index.new( idx_info['name'], idx_info['sql'], table )
|
55
|
-
end
|
56
|
-
end
|
57
53
|
@tables[table.name] = table
|
58
54
|
end
|
59
55
|
|
60
56
|
@tables
|
61
57
|
end
|
62
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
|
+
|
63
84
|
##
|
64
85
|
# load all the columns for a particular table
|
65
86
|
#
|
data/lib/amalgalite/sqlite3.rb
CHANGED
@@ -9,6 +9,39 @@ module Amalgalite::SQLite3
|
|
9
9
|
# module containing all constants used from the SQLite C extension
|
10
10
|
#
|
11
11
|
module Constants
|
12
|
+
module Helpers
|
13
|
+
#
|
14
|
+
# convert an integer value into the string representation of the associated
|
15
|
+
# constant. this is a helper method used by some of the other modules
|
16
|
+
#
|
17
|
+
def name_from_value( value )
|
18
|
+
unless @const_map_from_value
|
19
|
+
@const_map_from_value = {}
|
20
|
+
constants.each do |const_name|
|
21
|
+
c_int = const_get( const_name )
|
22
|
+
@const_map_from_value[c_int] = const_name
|
23
|
+
end
|
24
|
+
end
|
25
|
+
return @const_map_from_value[ value ]
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
# convert a string into the constant value. This is helper method used by
|
30
|
+
# some of the other modules
|
31
|
+
#
|
32
|
+
def value_from_name( name )
|
33
|
+
unless @const_map_from_name
|
34
|
+
@const_map_from_name = {}
|
35
|
+
constants.each do |const_name|
|
36
|
+
c_int = const_get( const_name )
|
37
|
+
@const_map_from_name[ const_name ] = c_int
|
38
|
+
end
|
39
|
+
end
|
40
|
+
return @const_map_from_name[ name.upcase ]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
|
12
45
|
##
|
13
46
|
# DataType defines the namespace for all possible SQLite data types.
|
14
47
|
#
|
@@ -24,25 +57,29 @@ module Amalgalite::SQLite3
|
|
24
57
|
end
|
25
58
|
Open.freeze
|
26
59
|
|
60
|
+
##
|
61
|
+
# Status defines the namespace for all the possible status flags for
|
62
|
+
# Amalgalite::SQLite3::Status objects
|
63
|
+
#
|
64
|
+
module Status
|
65
|
+
extend Helpers
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
##
|
70
|
+
# DBStatus defines the namespace for all the possible status codes for the
|
71
|
+
# Amalgalite::SQlite3::Database::Status objects.
|
72
|
+
#
|
73
|
+
module DBStatus
|
74
|
+
extend Helpers
|
75
|
+
end
|
76
|
+
|
27
77
|
##
|
28
78
|
# ResultCode defines the namespace for all possible result codes from an
|
29
79
|
# SQLite API call.
|
30
80
|
#
|
31
81
|
module ResultCode
|
32
|
-
|
33
|
-
# convert an integer value into the string representation of the associated
|
34
|
-
# ResultCode constant.
|
35
|
-
#
|
36
|
-
def self.from_int( value )
|
37
|
-
unless @const_map_from_int
|
38
|
-
@const_map_from_int = {}
|
39
|
-
constants.each do |const_name|
|
40
|
-
c_int = const_get( const_name )
|
41
|
-
@const_map_from_int[c_int] = const_name
|
42
|
-
end
|
43
|
-
end
|
44
|
-
return @const_map_from_int[ value ]
|
45
|
-
end
|
82
|
+
extend Helpers
|
46
83
|
end # end ResultCode
|
47
84
|
end
|
48
85
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'amalgalite3'
|
2
|
+
require 'amalgalite/sqlite3/constants'
|
3
|
+
module Amalgalite::SQLite3
|
4
|
+
class Database
|
5
|
+
#
|
6
|
+
# A Stat represents a single Database Status code and its current highwater mark.
|
7
|
+
#
|
8
|
+
# Some stats may not have a current or a highwater value, in those cases
|
9
|
+
# the associated _has_current?_ or _has_highwater?_ method returns false and the
|
10
|
+
# _current_ or _highwater_ method also returns +nil+.
|
11
|
+
#
|
12
|
+
class Stat
|
13
|
+
attr_reader :name
|
14
|
+
attr_reader :code
|
15
|
+
|
16
|
+
def initialize( api_db, name )
|
17
|
+
@name = name
|
18
|
+
@code = ::Amalgalite::SQLite3::Constants::DBStatus.value_from_name( name )
|
19
|
+
@current = nil
|
20
|
+
@highwater = nil
|
21
|
+
@api_db = api_db
|
22
|
+
end
|
23
|
+
|
24
|
+
def current
|
25
|
+
update!
|
26
|
+
return @current
|
27
|
+
end
|
28
|
+
|
29
|
+
def highwater
|
30
|
+
update!
|
31
|
+
return @highwater
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
# reset the given stat's highwater mark. This will also populate the
|
36
|
+
# _@current_ and _@highwater_ instance variables
|
37
|
+
#
|
38
|
+
def reset!
|
39
|
+
update!( true )
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
# Top level Status object holding all the Stat objects indicating the DBStatus
|
45
|
+
# of the SQLite3 C library.
|
46
|
+
#
|
47
|
+
class DBStatus
|
48
|
+
::Amalgalite::SQLite3::Constants::DBStatus.constants.each do |const_name|
|
49
|
+
method_name = const_name.downcase
|
50
|
+
module_eval( <<-code, __FILE__, __LINE__ )
|
51
|
+
def #{method_name}
|
52
|
+
@#{method_name} ||= Amalgalite::SQLite3::Database::Stat.new( self.api_db, '#{method_name}' )
|
53
|
+
end
|
54
|
+
code
|
55
|
+
end
|
56
|
+
|
57
|
+
attr_reader :api_db
|
58
|
+
|
59
|
+
def initialize( api_db )
|
60
|
+
@api_db = api_db
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# return the DBstatus object for the sqlite database
|
65
|
+
def status
|
66
|
+
@status ||= DBStatus.new( self )
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|