amalgalite 0.10.1-x86-mingw32

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 (100) hide show
  1. data/HISTORY +201 -0
  2. data/LICENSE +29 -0
  3. data/README +51 -0
  4. data/bin/amalgalite-pack +126 -0
  5. data/examples/a.rb +9 -0
  6. data/examples/blob.rb +88 -0
  7. data/examples/bootstrap.rb +36 -0
  8. data/examples/define_aggregate.rb +75 -0
  9. data/examples/define_function.rb +104 -0
  10. data/examples/gem-db.rb +94 -0
  11. data/examples/gems.db +0 -0
  12. data/examples/require_me.rb +11 -0
  13. data/examples/requires.rb +42 -0
  14. data/examples/schema-info.rb +34 -0
  15. data/ext/amalgalite/amalgalite3.c +290 -0
  16. data/ext/amalgalite/amalgalite3.h +151 -0
  17. data/ext/amalgalite/amalgalite3_blob.c +240 -0
  18. data/ext/amalgalite/amalgalite3_constants.c +221 -0
  19. data/ext/amalgalite/amalgalite3_database.c +1148 -0
  20. data/ext/amalgalite/amalgalite3_requires_bootstrap.c +210 -0
  21. data/ext/amalgalite/amalgalite3_statement.c +639 -0
  22. data/ext/amalgalite/extconf.rb +36 -0
  23. data/ext/amalgalite/gen_constants.rb +130 -0
  24. data/ext/amalgalite/sqlite3.c +106729 -0
  25. data/ext/amalgalite/sqlite3.h +5626 -0
  26. data/ext/amalgalite/sqlite3_options.h +4 -0
  27. data/ext/amalgalite/sqlite3ext.h +380 -0
  28. data/gemspec.rb +60 -0
  29. data/lib/amalgalite.rb +43 -0
  30. data/lib/amalgalite/1.8/amalgalite3.so +0 -0
  31. data/lib/amalgalite/1.9/amalgalite3.so +0 -0
  32. data/lib/amalgalite/aggregate.rb +67 -0
  33. data/lib/amalgalite/blob.rb +186 -0
  34. data/lib/amalgalite/boolean.rb +42 -0
  35. data/lib/amalgalite/busy_timeout.rb +47 -0
  36. data/lib/amalgalite/column.rb +97 -0
  37. data/lib/amalgalite/core_ext/kernel/require.rb +21 -0
  38. data/lib/amalgalite/database.rb +947 -0
  39. data/lib/amalgalite/function.rb +61 -0
  40. data/lib/amalgalite/index.rb +43 -0
  41. data/lib/amalgalite/packer.rb +226 -0
  42. data/lib/amalgalite/paths.rb +70 -0
  43. data/lib/amalgalite/profile_tap.rb +131 -0
  44. data/lib/amalgalite/progress_handler.rb +21 -0
  45. data/lib/amalgalite/requires.rb +120 -0
  46. data/lib/amalgalite/schema.rb +191 -0
  47. data/lib/amalgalite/sqlite3.rb +6 -0
  48. data/lib/amalgalite/sqlite3/constants.rb +80 -0
  49. data/lib/amalgalite/sqlite3/database/function.rb +48 -0
  50. data/lib/amalgalite/sqlite3/database/status.rb +68 -0
  51. data/lib/amalgalite/sqlite3/status.rb +60 -0
  52. data/lib/amalgalite/sqlite3/version.rb +37 -0
  53. data/lib/amalgalite/statement.rb +414 -0
  54. data/lib/amalgalite/table.rb +90 -0
  55. data/lib/amalgalite/taps.rb +2 -0
  56. data/lib/amalgalite/taps/console.rb +27 -0
  57. data/lib/amalgalite/taps/io.rb +71 -0
  58. data/lib/amalgalite/trace_tap.rb +35 -0
  59. data/lib/amalgalite/type_map.rb +63 -0
  60. data/lib/amalgalite/type_maps/default_map.rb +167 -0
  61. data/lib/amalgalite/type_maps/storage_map.rb +40 -0
  62. data/lib/amalgalite/type_maps/text_map.rb +22 -0
  63. data/lib/amalgalite/version.rb +37 -0
  64. data/lib/amalgalite/view.rb +26 -0
  65. data/spec/aggregate_spec.rb +169 -0
  66. data/spec/amalgalite_spec.rb +4 -0
  67. data/spec/blob_spec.rb +81 -0
  68. data/spec/boolean_spec.rb +23 -0
  69. data/spec/busy_handler.rb +165 -0
  70. data/spec/database_spec.rb +494 -0
  71. data/spec/default_map_spec.rb +87 -0
  72. data/spec/function_spec.rb +94 -0
  73. data/spec/integeration_spec.rb +111 -0
  74. data/spec/packer_spec.rb +60 -0
  75. data/spec/paths_spec.rb +28 -0
  76. data/spec/progress_handler_spec.rb +105 -0
  77. data/spec/requires_spec.rb +23 -0
  78. data/spec/rtree_spec.rb +71 -0
  79. data/spec/schema_spec.rb +120 -0
  80. data/spec/spec_helper.rb +27 -0
  81. data/spec/sqlite3/constants_spec.rb +65 -0
  82. data/spec/sqlite3/database_status_spec.rb +36 -0
  83. data/spec/sqlite3/status_spec.rb +18 -0
  84. data/spec/sqlite3/version_spec.rb +14 -0
  85. data/spec/sqlite3_spec.rb +53 -0
  86. data/spec/statement_spec.rb +161 -0
  87. data/spec/storage_map_spec.rb +41 -0
  88. data/spec/tap_spec.rb +59 -0
  89. data/spec/text_map_spec.rb +23 -0
  90. data/spec/type_map_spec.rb +17 -0
  91. data/spec/version_spec.rb +15 -0
  92. data/tasks/announce.rake +43 -0
  93. data/tasks/config.rb +107 -0
  94. data/tasks/distribution.rake +77 -0
  95. data/tasks/documentation.rake +32 -0
  96. data/tasks/extension.rake +141 -0
  97. data/tasks/rspec.rake +33 -0
  98. data/tasks/rubyforge.rake +59 -0
  99. data/tasks/utils.rb +80 -0
  100. metadata +237 -0
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # An example of requiring all the files in a table via the Bootstrap::lift
4
+ # method.
5
+ #
6
+ # First use the blob.rb example in this same directory to load the a.rb file
7
+ # into an example database:
8
+ #
9
+ # ruby blob.rb store a.rb
10
+ #
11
+ # Then run this example.
12
+ #
13
+
14
+ # Require "ONLY" then binary extension, do not +require+ the ruby based code
15
+ $: << "../ext"
16
+ require 'amalgalite/amalgalite3'
17
+
18
+ # See what the load path is, notice that it is very small
19
+ puts "Before $\" : #{$LOADED_FEATURES.inspect}"
20
+
21
+ # tell the binary extension to "require" every file in the filestore.db in the
22
+ # table 'files' orderd by column 'id'. The 'path' column is added to $LOADED_FEATURES and the
23
+ # code in 'data' is evaled.
24
+ Amalgalite::Requires::Bootstrap.lift( "dbfile" => "filestore.db",
25
+ "table_name" => "rubylibs",
26
+ "rowid_column" => "id",
27
+ "filename_column" => "filename",
28
+ "contents_column" => "contents" )
29
+
30
+ # Notice that a.rb is in the list of files that has been required
31
+ puts "After $\" : #{$LOADED_FEATURES.inspect}"
32
+
33
+ # and look we prove that the code was eval'd appropriately
34
+ a = A.new
35
+ a.a
36
+
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ $: << "../lib"
5
+ $: << "../ext"
6
+ require 'amalgalite'
7
+
8
+ #--
9
+ # Create a database and a table to put some results from the functions in
10
+ #--
11
+ db = Amalgalite::Database.new( ":memory:" )
12
+ db.execute( "CREATE TABLE atest( words )" )
13
+
14
+ #------------------------------------------------------------------------------
15
+ # Create unique word count aggregate
16
+ #------------------------------------------------------------------------------
17
+ class UniqueWordCount < ::Amalgalite::Aggregate
18
+ attr_accessor :words
19
+
20
+ def initialize
21
+ @name = 'unique_word_count'
22
+ @arity = 1
23
+ @words = Hash.new { |h,k| h[k] = 0 }
24
+ end
25
+
26
+ def step( str )
27
+ str.split(/\W+/).each do |word|
28
+ words[ word.downcase ] += 1
29
+ end
30
+ return nil
31
+ end
32
+
33
+ def finalize
34
+ return words.size
35
+ end
36
+ end
37
+
38
+ db.define_aggregate( 'unique_word_count', UniqueWordCount )
39
+
40
+ #------------------------------------------------------------------------------
41
+ # Now we have a new aggregate function, lets insert some rows into the database
42
+ # and see what we can find.
43
+ #------------------------------------------------------------------------------
44
+ sql = "INSERT INTO atest( words ) VALUES( ? )"
45
+ verify = {}
46
+ db.prepare( sql ) do |stmt|
47
+ DATA.each do |words|
48
+ words.strip!
49
+ puts "Inserting #{words}"
50
+ stmt.execute( words )
51
+ words.split(/\W+/).each { |w| verify[w] = true }
52
+ end
53
+ end
54
+
55
+ #------------------------------------------------------------------------------
56
+ # And show the results
57
+ #------------------------------------------------------------------------------
58
+ puts
59
+ puts "Getting results..."
60
+ puts
61
+ all_rows = db.execute("SELECT unique_word_count( words ) AS uwc FROM atest")
62
+ puts "#{all_rows.first['uwc']} unique words found"
63
+ puts "#{verify.size} unique words to verify"
64
+
65
+ __END__
66
+ some random
67
+ words with
68
+ which
69
+ to play
70
+ and there should
71
+ be a couple of different
72
+ words that appear
73
+ more than once and
74
+ some that appear only
75
+ once
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ $: << "../lib"
5
+ $: << "../ext"
6
+ require 'amalgalite'
7
+
8
+ #--
9
+ # Create a database and a table to put some results from the functions in
10
+ #--
11
+ db = Amalgalite::Database.new( ":memory:" )
12
+ db.execute( "CREATE TABLE ftest( data, md5, sha1, sha2_bits, sha2)" )
13
+
14
+ #------------------------------------------------------------------------------
15
+ # Create an MD5 method using the block format of defining an sql fuction
16
+ #------------------------------------------------------------------------------
17
+ require 'digest/md5'
18
+ db.define_function( 'md5' ) do |x|
19
+ Digest::MD5.hexdigest( x.to_s )
20
+ end
21
+
22
+ #------------------------------------------------------------------------------
23
+ # Create a SHA1 method using the lambda format of defining an sql function
24
+ #------------------------------------------------------------------------------
25
+ require 'digest/sha1'
26
+ sha1 = lambda do |y|
27
+ Digest::SHA1.hexdigest( y.to_s )
28
+ end
29
+ db.define_function( "sha1", sha1 )
30
+
31
+ #------------------------------------------------------------------------------
32
+ # Create a SHA2 method using the class format for defining an sql function
33
+ # In this one we will allow any number of parameters, but we will only use the
34
+ # first two.
35
+ #------------------------------------------------------------------------------
36
+ require 'digest/sha2'
37
+ class SQLSha2
38
+ # track the number of invocations
39
+ attr_reader :call_count
40
+
41
+ def initialize
42
+ @call_count = 0
43
+ end
44
+
45
+ # the protocol that is used for sql function definition
46
+ def to_proc() self ; end
47
+
48
+ # say we take any number of parameters
49
+ def arity
50
+ -1
51
+ end
52
+
53
+ # The method that is called by SQLite, must be named 'call'
54
+ def call( *args )
55
+ text = args.shift.to_s
56
+ bitlength = (args.shift || 256).to_i
57
+ Digest::SHA2.new( bitlength ).hexdigest( text )
58
+ end
59
+ end
60
+ db.define_function('sha2', SQLSha2.new)
61
+
62
+
63
+ #------------------------------------------------------------------------------
64
+ # Now we have 3 new sql functions, each defined in one of the available methods
65
+ # to define sql functions in amalgalite. Lets insert some rows and look at the
66
+ # results
67
+ #------------------------------------------------------------------------------
68
+ possible_bits = [ 256, 384, 512 ]
69
+ sql = "INSERT INTO ftest( data, md5, sha1, sha2_bits, sha2 ) VALUES( @word , md5( @word ), sha1( @word ), @bits, sha2(@word,@bits) )"
70
+ db.prepare( sql ) do |stmt|
71
+ DATA.each do |word|
72
+ word.strip!
73
+ bits = possible_bits[ rand(3) ]
74
+ puts "Inserting #{word}, #{bits}"
75
+ stmt.execute( { '@word' => word, '@bits' => bits } )
76
+ end
77
+ end
78
+
79
+ #------------------------------------------------------------------------------
80
+ # And show the results
81
+ #------------------------------------------------------------------------------
82
+ puts
83
+ puts "Getting results..."
84
+ puts
85
+ columns = db.schema.tables['ftest'].columns.keys.sort
86
+ i = 0
87
+ db.execute("SELECT #{columns.join(',')} FROM ftest") do |row|
88
+ i += 1
89
+ puts "-----[ row #{i} ]-" + "-" * 42
90
+ columns.each do |col|
91
+ puts "#{col.ljust(10)} : #{row[col]}"
92
+ end
93
+ puts
94
+ end
95
+
96
+
97
+ __END__
98
+ some
99
+ random
100
+ words
101
+ with
102
+ which
103
+ to
104
+ play
@@ -0,0 +1,94 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #
4
+ # Basic amalgalite example creating a table, inserting rows and doing various
5
+ # selects and prepared statements
6
+ #
7
+ require 'rubygems'
8
+ require 'amalgalite'
9
+
10
+ #
11
+ # Create a database, this will create the DB if it doesn't exist
12
+ #
13
+ puts "Opening database (version #{Amalgalite::Version})"
14
+ db = Amalgalite::Database.new("gems.db")
15
+
16
+ #
17
+ # Setup taps into profile and trace information of sqlite, the profile tap will
18
+ # goto the profile_tap.log file and the trace information will go to the
19
+ # trace_tap.log file
20
+ #
21
+ puts "Establishing taps"
22
+ db.trace_tap = Amalgalite::Taps::IO.new( trace_tap_file = File.open("trace_tap.log", "w+") )
23
+ db.profile_tap = Amalgalite::Taps::IO.new( profile_tap_file = File.open("profile_tap.log", "w+") )
24
+
25
+ #
26
+ # Create the schema unless it already exists in the table. The meta information
27
+ # about the database schema is available as the result of the db.schema method
28
+ #
29
+ schema = db.schema
30
+ unless schema.tables['gems']
31
+ puts "Create schema"
32
+ db.execute <<-SQL
33
+ CREATE TABLE gems (
34
+ id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
35
+ name VARCHAR(128),
36
+ version VARCHAR(32),
37
+ author VARCHAR(128)
38
+ );
39
+ SQL
40
+ db.reload_schema!
41
+ end
42
+
43
+ #
44
+ # Get some data from the system to insert into the database. Since everyone
45
+ # probably has gems installed, that's a ready known piece of information. We'll
46
+ # just pull in the latest version of each installed gem and dump some meta
47
+ # information into a db for testing.
48
+ #
49
+ latest_specs = Gem.source_index.latest_specs
50
+
51
+ puts "Inserting #{latest_specs.size} rows of gem information..."
52
+ before = Time.now
53
+
54
+ # Inserting bulk rows as a transaction is good practice with SQLite, it is
55
+ # MUCH faster.
56
+ db.transaction do |db_in_transaction|
57
+ db_in_transaction.prepare("INSERT INTO gems(name, version, author) VALUES( :name, :version, :author );") do |stmt|
58
+ latest_specs.each do |spec|
59
+ insert_data = {}
60
+ insert_data[':name'] = spec.name.to_s
61
+ insert_data[':version'] = spec.version.to_s
62
+ insert_data[':author'] = spec.authors.join(' ')
63
+ #puts "Inserting #{insert_data.inspect}"
64
+ stmt.execute( insert_data )
65
+ end
66
+ end
67
+ end
68
+ puts "Took #{Time.now - before} seconds"
69
+ puts "Done Inserting"
70
+
71
+ authors_by_number = db.execute("SELECT author, count( name ) as num_gems FROM gems GROUP BY author ORDER BY num_gems DESC")
72
+ favorite_author = authors_by_number.first
73
+ puts "Your favorite gem author is <#{favorite_author['author']}>, with #{favorite_author['num_gems']} gems installed."
74
+
75
+ #
76
+ # Now we'll look at the profile sampler and see what information it traced about
77
+ # our behavoir.
78
+ #
79
+ db.profile_tap.samplers.each do |stat_name, stat_values|
80
+ puts "-" * 20
81
+ puts stat_values.to_s
82
+ end
83
+
84
+ #
85
+ # Clear out the taps (not really necessary, just cleaning up)
86
+ #
87
+ db.trace_tap = profile_tap = nil
88
+
89
+ #
90
+ # close things down
91
+ #
92
+ db.close
93
+ trace_tap_file.close
94
+ profile_tap_file.close
data/examples/gems.db ADDED
Binary file
@@ -0,0 +1,11 @@
1
+ CONSTANT = "bad"
2
+ class RequireMe
3
+ def initialize( msg )
4
+ @msg = msg
5
+ puts "RequireMe initialized"
6
+ end
7
+
8
+ def foo
9
+ puts @msg
10
+ end
11
+ end
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #
4
+ # An Amalgalite example showing how to 'require' data in an amalgalite database
5
+ #
6
+ # We'll make a database with one table, that we store file contents in.
7
+ #
8
+
9
+ $: << "../lib"
10
+ $: << "../ext"
11
+ require 'rubygems'
12
+ require 'amalgalite'
13
+
14
+ style = ARGV.shift || "normal"
15
+
16
+ #
17
+ # create the database
18
+ #
19
+ dbfile = Amalgalite::Requires::Bootstrap::DEFAULT_DB
20
+ File.unlink( dbfile ) if File.exist?( dbfile )
21
+ require 'amalgalite/packer'
22
+ options = { :verbose => true }
23
+ if style == "compressed" then
24
+ options[:compressed] = true
25
+ end
26
+ p = Amalgalite::Packer.new( options )
27
+ p.pack( [ "require_me.rb" ] )
28
+
29
+ require 'amalgalite/requires'
30
+ begin
31
+ Amalgalite::Requires.new( :dbfile_name => p.dbfile )
32
+ FileUtils.mv 'require_me.rb', 'rm.rb', :verbose => true
33
+ require 'require_me'
34
+ e = RequireMe.new( "#{style} require style works!" )
35
+ e.foo
36
+ require 'require_me'
37
+ puts
38
+
39
+ ensure
40
+ FileUtils.mv 'rm.rb', 'require_me.rb', :verbose => true
41
+ File.unlink( dbfile ) if File.exist?( dbfile )
42
+ end
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'amalgalite'
5
+
6
+ db_name = ARGV.shift
7
+ unless db_name
8
+ puts "Usage: #{File.basename($0)} dbname"
9
+ exit 1
10
+ end
11
+ db = Amalgalite::Database.new( db_name )
12
+ col_info = %w[ default_value declared_data_type collation_sequence_name not_null_constraint primary_key auto_increment ]
13
+ max_width = col_info.collect { |c| c.length }.sort.last
14
+
15
+ db.schema.tables.keys.sort.each do |table_name|
16
+ puts "Table: #{table_name}"
17
+ puts "=" * 42
18
+ db.schema.tables[table_name].columns.each_pair do |col_name, col|
19
+ puts " Column : #{col.name}"
20
+ col_info.each do |ci|
21
+ puts " |#{ci.rjust( max_width, "." )} : #{col.send( ci )}"
22
+ end
23
+ puts
24
+ end
25
+
26
+ db.schema.tables[table_name].indexes.each_pair do |idx_name, index|
27
+ puts " Index : #{index.name}"
28
+ puts " |#{"sequence_number".rjust( max_width, "." )} : #{index.sequence_number}"
29
+ puts " |#{"is unique?".rjust( max_width, ".")} : #{index.unique?}"
30
+ puts " |#{"columns".rjust( max_width, ".")} : #{index.columns.collect { |c| c.name }.join(',') }"
31
+ puts
32
+ end
33
+ end
34
+
@@ -0,0 +1,290 @@
1
+ /**
2
+ * Copyright (c) 2008 Jeremy Hinegardner
3
+ * All rights reserved. See LICENSE and/or COPYING for details.
4
+ *
5
+ * vim: shiftwidth=4
6
+ */
7
+
8
+ #include "amalgalite3.h"
9
+
10
+ /* Module and Classes */
11
+ VALUE mA; /* module Amalgalite */
12
+ VALUE mAS; /* module Amalgalite::SQLite3 */
13
+ VALUE mASV; /* module Amalgalite::SQLite3::Version */
14
+ VALUE eAS_Error; /* class Amalgalite::SQLite3::Error */
15
+ VALUE cAS_Stat; /* class Amalgalite::SQLite3::Stat */
16
+
17
+ /*----------------------------------------------------------------------
18
+ * module methods for Amalgalite::SQLite3
19
+ *---------------------------------------------------------------------*/
20
+
21
+ /*
22
+ * call-seq:
23
+ * Amalgalite::SQLite3.threadsafe? -> true or false
24
+ *
25
+ * Has the SQLite3 extension been compiled "threadsafe". If threadsafe? is
26
+ * true then the internal SQLite mutexes are enabled and SQLite is threadsafe.
27
+ * That is threadsafe within the context of 'C' threads.
28
+ *
29
+ */
30
+ VALUE am_sqlite3_threadsafe(VALUE self)
31
+ {
32
+ if (sqlite3_threadsafe()) {
33
+ return Qtrue;
34
+ } else {
35
+ return Qfalse;
36
+ }
37
+ }
38
+
39
+ /*
40
+ * call-seq:
41
+ * Amalgalite::SQLite.temp_directory -> String or nil
42
+ *
43
+ * Return the directory name that all that all the temporary files created by
44
+ * SQLite creates will be placed. If _nil_ is returned, then SQLite will search
45
+ * for an appropriate directory.
46
+ */
47
+ VALUE am_sqlite3_get_temp_directory( VALUE self )
48
+ {
49
+ if (NULL == sqlite3_temp_directory) {
50
+ return Qnil;
51
+ } else {
52
+ return rb_str_new2( sqlite3_temp_directory );
53
+ }
54
+ }
55
+
56
+ /*
57
+ * call-seq:
58
+ * Amalgalite::SQLite.temp_directory = "/tmp/location"
59
+ *
60
+ * Set the temporary directory used by sqlite to store temporary directories.
61
+ * It is not safe to set this value after a Database has been opened.
62
+ *
63
+ */
64
+ VALUE am_sqlite3_set_temp_directory( VALUE self, VALUE new_dir )
65
+ {
66
+ char *p = NULL ;
67
+
68
+ if ( NULL != sqlite3_temp_directory ) {
69
+ free( sqlite3_temp_directory );
70
+ }
71
+
72
+ if ( Qnil != new_dir ) {
73
+ VALUE str = StringValue( new_dir );
74
+
75
+ p = calloc( RSTRING_LEN(str) + 1, sizeof(char) );
76
+ strncpy( p, RSTRING_PTR(str), RSTRING_LEN(str) );
77
+ }
78
+
79
+ sqlite3_temp_directory = p;
80
+
81
+ return Qnil;
82
+ }
83
+
84
+ VALUE amalgalite_format_string( char* pattern, VALUE string )
85
+ {
86
+ VALUE to_s= rb_funcall( string, rb_intern("to_s"), 0 );
87
+ VALUE str = StringValue( to_s );
88
+ char *p = sqlite3_mprintf(pattern, RSTRING_PTR(str));
89
+ VALUE rv = Qnil;
90
+ if ( NULL != p ) {
91
+ rv = rb_str_new2( p );
92
+ sqlite3_free( p );
93
+ } else {
94
+ rb_raise( rb_eNoMemError, "Unable to quote string" );
95
+ }
96
+
97
+ return rv;
98
+ }
99
+ /*
100
+ * call-seq:
101
+ * Amalgalite::SQLite.escape( string ) => escaped_string
102
+ *
103
+ * Takes the input string and escapes each ' (single quote) character by
104
+ * doubling it.
105
+ */
106
+ VALUE am_sqlite3_escape( VALUE self, VALUE string )
107
+ {
108
+ return ( Qnil == string ) ? Qnil : amalgalite_format_string( "%q", string );
109
+ }
110
+
111
+ /*
112
+ * call-seq:
113
+ * Amalgalite::SQLite.quote( string ) => quoted-escaped string
114
+ *
115
+ * Takes the input string and surrounds it with single quotes, it also escapes
116
+ * each embedded single quote with double quotes.
117
+ */
118
+ VALUE am_sqlite3_quote( VALUE self, VALUE string )
119
+ {
120
+ return ( Qnil == string ) ? Qnil : amalgalite_format_string( "%Q", string );
121
+ }
122
+
123
+ /*
124
+ * call-seq:
125
+ * Amalgalite::SQLite3.complete?( ... , opts = { :utf16 => false }) -> True, False
126
+ *
127
+ * Is the text passed in as a parameter a complete SQL statement? Or is
128
+ * additional input required before sending the SQL to the extension. If the
129
+ * extra 'opts' parameter is used, you can send in a UTF-16 encoded string as
130
+ * the SQL.
131
+ *
132
+ * A complete statement must end with a semicolon.
133
+ *
134
+ */
135
+ VALUE am_sqlite3_complete(VALUE self, VALUE args)
136
+ {
137
+ VALUE sql = rb_ary_shift( args );
138
+ VALUE opts = rb_ary_shift( args );
139
+ VALUE utf16 = Qnil;
140
+ int result = 0;
141
+
142
+ if ( ( Qnil != opts ) && ( T_HASH == TYPE(opts) ) ){
143
+ utf16 = rb_hash_aref( opts, rb_intern("utf16") );
144
+ }
145
+
146
+ if ( (Qfalse == utf16) || (Qnil == utf16) ) {
147
+ result = sqlite3_complete( StringValuePtr( sql ) );
148
+ } else {
149
+ result = sqlite3_complete16( (void*) StringValuePtr( sql ) );
150
+ }
151
+
152
+ return ( result > 0 ) ? Qtrue : Qfalse;
153
+ }
154
+
155
+ /*
156
+ * call-seq:
157
+ * Amalgalite::SQLite3::Stat.update!( reset = false ) -> nil
158
+ *
159
+ * Populates the _@current_ and _@higwater_ instance variables of self
160
+ * object with the values from the sqlite3_status call. If reset it true then
161
+ * the highwater mark for the stat is reset
162
+ *
163
+ */
164
+ VALUE am_sqlite3_stat_update_bang( int argc, VALUE *argv, VALUE self )
165
+ {
166
+ int status_op = -1;
167
+ int current = -1;
168
+ int highwater = -1;
169
+ VALUE reset = Qfalse;
170
+ int reset_flag = 0;
171
+ int rc;
172
+
173
+ status_op = FIX2INT( rb_iv_get( self, "@code" ) );
174
+ if ( argc > 0 ) {
175
+ reset = argv[0];
176
+ reset_flag = ( Qtrue == reset ) ? 1 : 0 ;
177
+ }
178
+
179
+ rc = sqlite3_status( status_op, &current, &highwater, reset_flag );
180
+
181
+ if ( SQLITE_OK != rc ) {
182
+ VALUE n = rb_iv_get( self, "@name" ) ;
183
+ char* name = StringValuePtr( n );
184
+ rb_raise(eAS_Error, "Failure to retrieve status for %s : [SQLITE_ERROR %d] \n", name, rc);
185
+ }
186
+
187
+ rb_iv_set( self, "@current", INT2NUM( current ) );
188
+ rb_iv_set( self, "@highwater", INT2NUM( highwater) );
189
+
190
+ return Qnil;
191
+ }
192
+
193
+ /*
194
+ * call-seq:
195
+ * Amalgalite::SQLite3.randomness( N ) -> String of length N
196
+ *
197
+ * Generate N bytes of random data.
198
+ *
199
+ */
200
+ VALUE am_sqlite3_randomness(VALUE self, VALUE num_bytes)
201
+ {
202
+ int n = NUM2INT(num_bytes);
203
+ char *buf = ALLOCA_N(char, n);
204
+
205
+ sqlite3_randomness( n, buf );
206
+ return rb_str_new( buf, n );
207
+ }
208
+
209
+ /*----------------------------------------------------------------------
210
+ * module methods for Amalgalite::SQLite3::Version
211
+ *---------------------------------------------------------------------*/
212
+
213
+ /*
214
+ * call-seq:
215
+ * Amalgalite::SQLite3::Version.to_s -> String
216
+ *
217
+ * Return the SQLite C library version number as a string
218
+ *
219
+ */
220
+ VALUE am_sqlite3_libversion(VALUE self)
221
+ {
222
+ return rb_str_new2(sqlite3_libversion());
223
+ }
224
+
225
+ /*
226
+ * call-seq:
227
+ * Amalgalite::SQLite3.Version.to_i -> Fixnum
228
+ *
229
+ * Return the SQLite C library version number as an integer
230
+ *
231
+ */
232
+ VALUE am_sqlite3_libversion_number(VALUE self)
233
+ {
234
+ return INT2FIX(sqlite3_libversion_number());
235
+ }
236
+
237
+ /**
238
+ * Document-class: Amalgalite::SQLite3
239
+ *
240
+ * The SQLite ruby extension inside Amalgalite.
241
+ *
242
+ */
243
+
244
+ void Init_amalgalite3()
245
+ {
246
+ /*
247
+ * top level module encapsulating the entire Amalgalite library
248
+ */
249
+ mA = rb_define_module("Amalgalite");
250
+
251
+ mAS = rb_define_module_under(mA, "SQLite3");
252
+ rb_define_module_function(mAS, "threadsafe?", am_sqlite3_threadsafe, 0);
253
+ rb_define_module_function(mAS, "complete?", am_sqlite3_complete, -2);
254
+ rb_define_module_function(mAS, "randomness", am_sqlite3_randomness,1);
255
+ rb_define_module_function(mAS, "temp_directory", am_sqlite3_get_temp_directory, 0);
256
+ rb_define_module_function(mAS, "temp_directory=", am_sqlite3_set_temp_directory, 1);
257
+
258
+ rb_define_module_function(mAS, "escape", am_sqlite3_escape, 1);
259
+ rb_define_module_function(mAS, "quote", am_sqlite3_quote, 1);
260
+
261
+ /*
262
+ * class encapsulating a single Stat
263
+ */
264
+ cAS_Stat = rb_define_class_under(mAS, "Stat", rb_cObject);
265
+ rb_define_method(cAS_Stat, "update!", am_sqlite3_stat_update_bang, -1);
266
+
267
+ /*
268
+ * Base class of all SQLite3 errors
269
+ */
270
+ eAS_Error = rb_define_class_under(mAS, "Error", rb_eStandardError); /* in amalgalite.c */
271
+
272
+ /**
273
+ * Encapsulation of the SQLite C library version
274
+ */
275
+ mASV = rb_define_module_under(mAS, "Version");
276
+ rb_define_module_function(mASV, "to_s", am_sqlite3_libversion, 0); /* in amalgalite3.c */
277
+ rb_define_module_function(mASV, "to_i", am_sqlite3_libversion_number, 0); /* in amalgalite3.c */
278
+
279
+ /*
280
+ * Initialize the rest of the module
281
+ */
282
+ Init_amalgalite3_constants( );
283
+ Init_amalgalite3_database( );
284
+ Init_amalgalite3_statement( );
285
+ Init_amalgalite3_blob( );
286
+ Init_amalgalite3_requires_bootstrap( );
287
+
288
+ }
289
+
290
+