amalgalite 0.10.1-x86-mswin32

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