libsql 0.1.0-x64-mingw-ucrt
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.
- checksums.yaml +7 -0
- data/CONTRIBUTING.md +60 -0
- data/HISTORY.md +6 -0
- data/LICENSE +31 -0
- data/Manifest.txt +96 -0
- data/README.md +59 -0
- data/Rakefile +28 -0
- data/TODO.md +57 -0
- data/examples/a.rb +9 -0
- data/examples/blob.rb +106 -0
- data/examples/define_aggregate.rb +75 -0
- data/examples/define_function.rb +104 -0
- data/examples/fts5.rb +152 -0
- data/examples/gem-db.rb +94 -0
- data/examples/schema-info.rb +34 -0
- data/ext/libsql/c/extconf.rb +86 -0
- data/ext/libsql/c/gen_constants.rb +353 -0
- data/ext/libsql/c/libsql_blob.c +240 -0
- data/ext/libsql/c/libsql_constants.c +1518 -0
- data/ext/libsql/c/libsql_database.c +1188 -0
- data/ext/libsql/c/libsql_ext.c +383 -0
- data/ext/libsql/c/libsql_ext.h +149 -0
- data/ext/libsql/c/libsql_statement.c +649 -0
- data/ext/libsql/c/notes.txt +134 -0
- data/ext/libsql/c/sqlite3.c +247030 -0
- data/ext/libsql/c/sqlite3.h +13436 -0
- data/lib/libsql/3.1/libsql_ext.so +0 -0
- data/lib/libsql/3.2/libsql_ext.so +0 -0
- data/lib/libsql/aggregate.rb +73 -0
- data/lib/libsql/blob.rb +186 -0
- data/lib/libsql/boolean.rb +42 -0
- data/lib/libsql/busy_timeout.rb +47 -0
- data/lib/libsql/column.rb +99 -0
- data/lib/libsql/csv_table_importer.rb +75 -0
- data/lib/libsql/database.rb +933 -0
- data/lib/libsql/function.rb +61 -0
- data/lib/libsql/index.rb +43 -0
- data/lib/libsql/memory_database.rb +15 -0
- data/lib/libsql/paths.rb +80 -0
- data/lib/libsql/profile_tap.rb +131 -0
- data/lib/libsql/progress_handler.rb +21 -0
- data/lib/libsql/schema.rb +225 -0
- data/lib/libsql/sqlite3/constants.rb +95 -0
- data/lib/libsql/sqlite3/database/function.rb +48 -0
- data/lib/libsql/sqlite3/database/status.rb +68 -0
- data/lib/libsql/sqlite3/libsql_version.rb +32 -0
- data/lib/libsql/sqlite3/status.rb +60 -0
- data/lib/libsql/sqlite3/version.rb +55 -0
- data/lib/libsql/sqlite3.rb +7 -0
- data/lib/libsql/statement.rb +421 -0
- data/lib/libsql/table.rb +91 -0
- data/lib/libsql/taps/console.rb +27 -0
- data/lib/libsql/taps/io.rb +74 -0
- data/lib/libsql/taps.rb +2 -0
- data/lib/libsql/trace_tap.rb +35 -0
- data/lib/libsql/type_map.rb +63 -0
- data/lib/libsql/type_maps/default_map.rb +166 -0
- data/lib/libsql/type_maps/storage_map.rb +38 -0
- data/lib/libsql/type_maps/text_map.rb +21 -0
- data/lib/libsql/version.rb +8 -0
- data/lib/libsql/view.rb +26 -0
- data/lib/libsql-ruby.rb +1 -0
- data/lib/libsql.rb +51 -0
- data/spec/aggregate_spec.rb +158 -0
- data/spec/blob_spec.rb +78 -0
- data/spec/boolean_spec.rb +24 -0
- data/spec/busy_handler.rb +157 -0
- data/spec/data/iso-3166-country.txt +242 -0
- data/spec/data/iso-3166-schema.sql +22 -0
- data/spec/data/iso-3166-subcountry.txt +3995 -0
- data/spec/data/make-iso-db.sh +12 -0
- data/spec/database_spec.rb +505 -0
- data/spec/default_map_spec.rb +92 -0
- data/spec/function_spec.rb +78 -0
- data/spec/integeration_spec.rb +97 -0
- data/spec/iso_3166_database.rb +58 -0
- data/spec/json_spec.rb +24 -0
- data/spec/libsql_spec.rb +4 -0
- data/spec/paths_spec.rb +28 -0
- data/spec/progress_handler_spec.rb +91 -0
- data/spec/rtree_spec.rb +66 -0
- data/spec/schema_spec.rb +131 -0
- data/spec/spec_helper.rb +48 -0
- data/spec/sqlite3/constants_spec.rb +108 -0
- data/spec/sqlite3/database_status_spec.rb +36 -0
- data/spec/sqlite3/libsql_version_spec.rb +16 -0
- data/spec/sqlite3/status_spec.rb +22 -0
- data/spec/sqlite3/version_spec.rb +28 -0
- data/spec/sqlite3_spec.rb +53 -0
- data/spec/statement_spec.rb +168 -0
- data/spec/storage_map_spec.rb +38 -0
- data/spec/tap_spec.rb +57 -0
- data/spec/text_map_spec.rb +20 -0
- data/spec/type_map_spec.rb +14 -0
- data/spec/version_spec.rb +8 -0
- data/tasks/custom.rake +134 -0
- data/tasks/default.rake +257 -0
- data/tasks/extension.rake +29 -0
- data/tasks/this.rb +208 -0
- metadata +329 -0
data/examples/fts5.rb
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'rubygems'
|
3
|
+
require 'libsql'
|
4
|
+
require 'benchmark'
|
5
|
+
require 'pathname'
|
6
|
+
|
7
|
+
begin
|
8
|
+
require 'json'
|
9
|
+
rescue LoadError
|
10
|
+
abort "'gem install json' to run this example"
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
README = <<_
|
15
|
+
This example program assumes that you have available the 'fortune' BSD command dataset.
|
16
|
+
|
17
|
+
execute `fortune -f` to see if you have this command available.
|
18
|
+
_
|
19
|
+
|
20
|
+
fortune_dir = %x[ fortune -f 2>&1 ].split("\n").first.split.last
|
21
|
+
abort README unless fortune_dir and File.directory?( fortune_dir )
|
22
|
+
|
23
|
+
fortune_path = Pathname.new(fortune_dir)
|
24
|
+
|
25
|
+
#
|
26
|
+
# Lets create a database that utilizes FTS5 http://www.sqlite.org/fts5.html
|
27
|
+
#
|
28
|
+
#
|
29
|
+
|
30
|
+
#
|
31
|
+
# Create a database, this will create the DB if it doesn't exist
|
32
|
+
#
|
33
|
+
puts "Opening database (version #{::Libsql::VERSION})"
|
34
|
+
db = ::Libsql::Database.new("fts5.db")
|
35
|
+
|
36
|
+
#
|
37
|
+
# Create the schema unless it already exists in the table. The meta information
|
38
|
+
# about the database schema is available as the result of the db.schema method
|
39
|
+
#
|
40
|
+
schema = db.schema
|
41
|
+
unless schema.tables['search']
|
42
|
+
puts "Create schema"
|
43
|
+
db.execute_batch <<-SQL
|
44
|
+
CREATE VIRTUAL TABLE search USING fts5(
|
45
|
+
filename,
|
46
|
+
content
|
47
|
+
);
|
48
|
+
|
49
|
+
CREATE TABLE plain (
|
50
|
+
filename VARCHAR(128),
|
51
|
+
content TEXT
|
52
|
+
);
|
53
|
+
SQL
|
54
|
+
db.reload_schema!
|
55
|
+
end
|
56
|
+
|
57
|
+
def each_fortune(path,&block)
|
58
|
+
fortune = []
|
59
|
+
path.each_line do |line|
|
60
|
+
line.strip!
|
61
|
+
if line == "%" then
|
62
|
+
yield fortune.join("\n")
|
63
|
+
fortune.clear
|
64
|
+
else
|
65
|
+
fortune << line
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
#
|
71
|
+
# Only load the data if the db is empty
|
72
|
+
#
|
73
|
+
if db.first_value_from( "SELECT count(*) from search" ) == 0 then
|
74
|
+
before = Time.now
|
75
|
+
idx = 0
|
76
|
+
|
77
|
+
# Inserting bulk rows as a transaction is good practice with SQLite, it is
|
78
|
+
# MUCH faster.
|
79
|
+
db.transaction do |db_in_transaction|
|
80
|
+
# Iterate over the files in the fortunes dir and split on the fortunes, then
|
81
|
+
|
82
|
+
fortune_path.each_child do |fortune_file|
|
83
|
+
next if fortune_file.directory?
|
84
|
+
next if fortune_file.extname == ".dat"
|
85
|
+
$stdout.puts "Loading #{fortune_file}"
|
86
|
+
|
87
|
+
each_fortune(fortune_file) do |fortune|
|
88
|
+
insert_data = {
|
89
|
+
':fname' => fortune_file.to_s,
|
90
|
+
':content' => fortune
|
91
|
+
}
|
92
|
+
|
93
|
+
# insert into the FTS5 table
|
94
|
+
db_in_transaction.prepare("INSERT INTO search( filename, content ) VALUES( :fname, :content );") do |stmt|
|
95
|
+
stmt.execute( insert_data )
|
96
|
+
end
|
97
|
+
|
98
|
+
# insert into the normal table for comparison
|
99
|
+
db_in_transaction.prepare("INSERT INTO plain( filename, content ) VALUES( :fname, :content );") do |stmt|
|
100
|
+
stmt.execute( insert_data )
|
101
|
+
end
|
102
|
+
|
103
|
+
idx += 1
|
104
|
+
print "Processed #{idx}\r"
|
105
|
+
$stdout.flush
|
106
|
+
end
|
107
|
+
puts "\nFinalizing..."
|
108
|
+
end
|
109
|
+
end
|
110
|
+
puts "Took #{Time.now - before} seconds to insert #{idx} fortunes"
|
111
|
+
puts "Done Inserting"
|
112
|
+
end
|
113
|
+
|
114
|
+
doc_count = db.first_value_from( "SELECT count(*) from search" )
|
115
|
+
|
116
|
+
#
|
117
|
+
# Now lets do some searching for some various words
|
118
|
+
#
|
119
|
+
|
120
|
+
%w[ president salmon thanks ].each do |word|
|
121
|
+
|
122
|
+
count = 100
|
123
|
+
puts
|
124
|
+
puts "Searching for '#{word}' #{count} times across #{doc_count} fortunes"
|
125
|
+
puts "=" * 60
|
126
|
+
|
127
|
+
Benchmark.bm( 15 ) do |x|
|
128
|
+
|
129
|
+
#
|
130
|
+
# search using the fts search to get the cont of tweets with the given word
|
131
|
+
#
|
132
|
+
x.report('fts5: ') do
|
133
|
+
db.prepare( "SELECT count(filename) FROM search WHERE search MATCH 'content:#{word}'" ) do |stmt|
|
134
|
+
count.times do
|
135
|
+
stmt.execute
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
#
|
141
|
+
# search using basic string matching in sqlite.
|
142
|
+
#
|
143
|
+
x.report('plain: ') do
|
144
|
+
db.prepare( "SELECT count(filename) FROM plain WHERE content LIKE '% #{word} %'" ) do |stmt|
|
145
|
+
count.times do
|
146
|
+
stmt.execute
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
data/examples/gem-db.rb
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#
|
4
|
+
# Basic libsql example creating a table, inserting rows and doing various
|
5
|
+
# selects and prepared statements
|
6
|
+
#
|
7
|
+
require 'rubygems'
|
8
|
+
require 'libsql'
|
9
|
+
|
10
|
+
#
|
11
|
+
# Create a database, this will create the DB if it doesn't exist
|
12
|
+
#
|
13
|
+
puts "Opening database (version #{::Libsql::Version})"
|
14
|
+
db = ::Libsql::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 = ::Libsql::Taps::IO.new( trace_tap_file = File.open("trace_tap.log", "w+") )
|
23
|
+
db.profile_tap = ::Libsql::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
|
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'libsql'
|
5
|
+
|
6
|
+
db_name = ARGV.shift
|
7
|
+
unless db_name
|
8
|
+
puts "Usage: #{File.basename($0)} dbname"
|
9
|
+
exit 1
|
10
|
+
end
|
11
|
+
db = ::Libsql::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,86 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
require 'rbconfig'
|
3
|
+
|
4
|
+
# used by the ext:build_win-1.x.x tasks, really no one else but jeremy should be
|
5
|
+
# using this hack
|
6
|
+
$ruby = ARGV.shift if ARGV[0]
|
7
|
+
|
8
|
+
# make available table and column meta data api
|
9
|
+
$CFLAGS += " -DSQLITE_ENABLE_BYTECODE_VTAB=1"
|
10
|
+
$CFLAGS += " -DSQLITE_ENABLE_COLUMN_METADATA=1"
|
11
|
+
$CFLAGS += " -DSQLITE_ENABLE_DBSTAT_VTAB=1"
|
12
|
+
$CFLAGS += " -DSQLITE_ENABLE_DBPAGE_VTAB=1"
|
13
|
+
$CFLAGS += " -DSQLITE_ENABLE_EXPLAIN_COMMENTS=1"
|
14
|
+
$CFLAGS += " -DSQLITE_ENABLE_FTS3=1"
|
15
|
+
$CFLAGS += " -DSQLITE_ENABLE_FTS3_PARENTHESIS=1"
|
16
|
+
$CFLAGS += " -DSQLITE_ENABLE_FTS4=1"
|
17
|
+
$CFLAGS += " -DSQLITE_ENABLE_FTS5=1"
|
18
|
+
$CFLAGS += " -DSQLITE_ENABLE_GEOPOLY=1"
|
19
|
+
$CFLAGS += " -DSQLITE_ENABLE_MATH_FUNCTIONS=1"
|
20
|
+
$CFLAGS += " -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1"
|
21
|
+
$CFLAGS += " -DSQLITE_ENABLE_NORMALIZE=1"
|
22
|
+
$CFLAGS += " -DSQLITE_ENABLE_NULL_TRIM=1"
|
23
|
+
$CFLAGS += " -DSQLITE_ENABLE_PREUPDATE_HOOK=1"
|
24
|
+
$CFLAGS ++ " -DSQLITE_EANBLE_QPSG=1"
|
25
|
+
$CFLAGS += " -DSQLITE_ENABLE_RBU=1"
|
26
|
+
$CFLAGS += " -DSQLITE_ENABLE_RTREE=1"
|
27
|
+
$CFLAGS += " -DSQLITE_ENABLE_SESSION=1"
|
28
|
+
# https://github.com/libsql/libsql/issues/144
|
29
|
+
# $CFLAGS += " -DSQLITE_ENABLE_SNAPSHOT=1"
|
30
|
+
$CFLAGS += " -DSQLITE_ENABLE_STMTVTAB=1"
|
31
|
+
$CFLAGS += " -DSQLITE_ENABLE_STAT4=1"
|
32
|
+
$CFLAGS += " -DSQLITE_ENABLE_UNLOCK_NOTIFY=1"
|
33
|
+
$CFLAGS += " -DSQLITE_ENABLE_SOUNDEX=1"
|
34
|
+
|
35
|
+
$CFLAGS += " -DSQLITE_USE_ALLOCA=1"
|
36
|
+
$CFLAGS += " -DSQLITE_OMIT_DEPRECATED=1"
|
37
|
+
|
38
|
+
# we compile sqlite the same way that the installation of ruby is compiled.
|
39
|
+
if RbConfig::MAKEFILE_CONFIG['configure_args'].include?( "--enable-pthread" ) then
|
40
|
+
$CFLAGS += " -DSQLITE_THREADSAFE=1"
|
41
|
+
else
|
42
|
+
$CFLAGS += " -DSQLITE_THREADSAFE=0"
|
43
|
+
end
|
44
|
+
|
45
|
+
# remove the -g flags if it exists
|
46
|
+
%w[ -ggdb\\d* -g\\d* ].each do |debug|
|
47
|
+
$CFLAGS = $CFLAGS.gsub(/\s#{debug}\b/,'')
|
48
|
+
RbConfig::MAKEFILE_CONFIG['debugflags'] = RbConfig::MAKEFILE_CONFIG['debugflags'].gsub(/\s#{debug}\b/,'') if RbConfig::MAKEFILE_CONFIG['debugflags']
|
49
|
+
end
|
50
|
+
|
51
|
+
ignoreable_warnings = %w[ write-strings ]
|
52
|
+
ignore_by_compiler = {
|
53
|
+
"clang" => %w[
|
54
|
+
empty-body
|
55
|
+
declaration-after-statement
|
56
|
+
incompatible-pointer-types-discards-qualifiers
|
57
|
+
shorten-64-to-32
|
58
|
+
sign-compare
|
59
|
+
unused-const-variable
|
60
|
+
unused-variable
|
61
|
+
unused-but-set-variable
|
62
|
+
undef
|
63
|
+
],
|
64
|
+
"gcc" => %w[
|
65
|
+
declaration-after-statement
|
66
|
+
implicit-function-declaration
|
67
|
+
unused-variable
|
68
|
+
unused-but-set-variable
|
69
|
+
maybe-uninitialized
|
70
|
+
old-style-definition
|
71
|
+
undef
|
72
|
+
]
|
73
|
+
}
|
74
|
+
|
75
|
+
if extras = ignore_by_compiler[RbConfig::MAKEFILE_CONFIG["CC"]] then
|
76
|
+
ignoreable_warnings.concat(extras)
|
77
|
+
end
|
78
|
+
|
79
|
+
ignoreable_warnings.each do |warning|
|
80
|
+
$CFLAGS = $CFLAGS.gsub(/-W#{warning}/,'')
|
81
|
+
RbConfig::MAKEFILE_CONFIG['warnflags'] = RbConfig::MAKEFILE_CONFIG['warnflags'].gsub(/-W#{warning}/,'') if RbConfig::MAKEFILE_CONFIG['warnflags']
|
82
|
+
$CFLAGS += " -Wno-#{warning}"
|
83
|
+
end
|
84
|
+
|
85
|
+
subdir = RUBY_VERSION.sub(/\.\d$/,'')
|
86
|
+
create_makefile("libsql/#{subdir}/libsql_ext")
|