sqlite3-1.7.3/ 0000755 0000041 0000041 00000000000 14620135377 013146 5 ustar www-data www-data sqlite3-1.7.3/ChangeLog.cvs 0000644 0000041 0000041 00000005742 14620135377 015522 0 ustar www-data www-data 2005-01-05 09:40 minam
* Rakefile, sqlite3-ruby-win32.gemspec, sqlite3-ruby.gemspec: Added
win32 gem.
2005-01-05 07:31 minam
* Rakefile, test/tc_integration.rb, test/tests.rb: Added
native-vs-dl benchmark to Rakefile. Added SQLITE3_DRIVERS
environment variable to integration test to specify which
driver(s) should be tested (defaults to "Native").
2005-01-04 14:26 minam
* ext/sqlite3_api/sqlite3_api.i, lib/sqlite3/database.rb,
lib/sqlite3/driver/native/driver.rb, test/tc_database.rb,
test/tc_integration.rb, test/tests.rb: Unit tests: done. Bugs:
fixed.
2005-01-03 23:13 minam
* ext/sqlite3_api/sqlite3_api.i, lib/sqlite3/database.rb,
lib/sqlite3/driver/dl/driver.rb,
lib/sqlite3/driver/native/driver.rb, test/tc_integration.rb:
Custom functions (aggregate and otherwise) are supported by the
native driver now. Test cases for the same.
2005-01-03 13:51 minam
* ext/sqlite3_api/MANIFEST, ext/sqlite3_api/extconf.rb,
ext/sqlite3_api/post-clean.rb, ext/sqlite3_api/post-distclean.rb,
ext/sqlite3_api/sqlite3_api.i, lib/sqlite3/database.rb,
lib/sqlite3/resultset.rb, lib/sqlite3/version.rb,
lib/sqlite3/driver/dl/driver.rb,
lib/sqlite3/driver/native/driver.rb, test/native-vs-dl.rb,
test/tc_integration.rb: Added preliminary implementation of
native driver (swig-based), and integration tests.
2004-12-29 19:37 minam
* lib/sqlite3/driver/dl/driver.rb: Some fixes to allow the DL
driver to work with Ruby 1.8.1.
2004-12-29 14:52 minam
* lib/sqlite3/: database.rb, version.rb: Made #quote a class method
(again). Bumped version to 0.6.
2004-12-25 22:59 minam
* lib/sqlite3/driver/dl/api.rb: Added check for darwin in supported
platforms (thanks to bitsweat).
2004-12-22 12:38 minam
* Rakefile: Rakefile wasn't packaging the README file.
2004-12-21 22:28 minam
* Rakefile, sqlite3-ruby.gemspec, test/bm.rb: Packaging now works.
Added benchmarks.
2004-12-21 21:45 minam
* LICENSE, README, Rakefile, setup.rb, sqlite3-ruby.gemspec,
doc/faq/faq.rb, doc/faq/faq.yml, lib/sqlite3.rb,
lib/sqlite3/statement.rb, lib/sqlite3/constants.rb,
lib/sqlite3/database.rb, lib/sqlite3/resultset.rb,
lib/sqlite3/translator.rb, lib/sqlite3/value.rb,
lib/sqlite3/version.rb, lib/sqlite3/errors.rb,
lib/sqlite3/pragmas.rb, lib/sqlite3/driver/dl/api.rb,
lib/sqlite3/driver/dl/driver.rb, test/mocks.rb,
test/tc_database.rb, test/tests.rb, test/driver/dl/tc_driver.rb:
Initial import
2004-12-21 21:45 minam
* LICENSE, README, Rakefile, setup.rb, sqlite3-ruby.gemspec,
doc/faq/faq.rb, doc/faq/faq.yml, lib/sqlite3.rb,
lib/sqlite3/statement.rb, lib/sqlite3/constants.rb,
lib/sqlite3/database.rb, lib/sqlite3/resultset.rb,
lib/sqlite3/translator.rb, lib/sqlite3/value.rb,
lib/sqlite3/version.rb, lib/sqlite3/errors.rb,
lib/sqlite3/pragmas.rb, lib/sqlite3/driver/dl/api.rb,
lib/sqlite3/driver/dl/driver.rb, test/mocks.rb,
test/tc_database.rb, test/tests.rb, test/driver/dl/tc_driver.rb:
Initial revision
sqlite3-1.7.3/API_CHANGES.md 0000644 0000041 0000041 00000004376 14620135377 015243 0 ustar www-data www-data # API Changes
* SQLite3::Database#execute only accepts an array for bind parameters.
* SQLite3::ResultSet used to query the database for the first row, regardless
of whether the user asked for it or not. I have removed that so that rows
will not be returned until the user asks for them. This is a subtle but
sometimes important change in behavior.
83882d2208ed189361617d5ab8532a325aaf729d
* SQLite3::Database#trace now takes either a block or an object that responds
to "call". The previous implementation passed around a VALUE that was cast
to a void *. This is dangerous because the value could get garbage collected
before the proc was called. If the user wants data passed around with the
block, they should use variables available to the closure or create an
object.
* SQLite3::Statement#step automatically converts to ruby types, where before
all values were automatically yielded as strings. This will only be a
problem for people who were accessing information about the database that
wasn't previously passed through the pure ruby conversion code.
* SQLite3::Database#errmsg no longer takes a parameter to return error
messages as UTF-16. Do people even use that? I opt for staying UTF-8 when
possible. See test_integration.rb test_errmsg_utf16
* SQLite3::Database#authorize same changes as trace
* test/test_tc_database.rb was removed because we no longer use the Driver
design pattern.
# Garbage Collection Strategy
All statements keep pointers back to their respective database connections.
The @connection instance variable on the Statement handle keeps the database
connection alive. Memory allocated for a statement handler will be freed in
two cases:
* close is called on the statement
* The SQLite3::Database object gets garbage collected
We can't free the memory for the statement in the garbage collection function
for the statement handler. The reason is because there exists a race
condition. We cannot guarantee the order in which objects will be garbage
collected. So, it is possible that a connection and a statement are up for
garbage collection. If the database connection were to be free'd before the
statement, then boom. Instead we'll be conservative and free unclosed
statements when the connection is terminated.
sqlite3-1.7.3/CONTRIBUTING.md 0000644 0000041 0000041 00000002362 14620135377 015402 0 ustar www-data www-data # Contributing to sqlite3-ruby
**This document is a work-in-progress.**
This doc is a short introduction on how to modify and maintain the sqlite3-ruby gem.
## Building gems
As a prerequisite please make sure you have `docker` correctly installed, so that you're able to cross-compile the native gems.
Run `bin/build-gems` which will package gems for all supported platforms, and run some basic sanity tests on those packages using `bin/test-gem-set` and `bin/test-gem-file-contents`.
## Updating the version of libsqlite3
Update `/dependencies.yml` to reflect:
- the version of libsqlite3
- the URL from which to download
- the checksum of the file, which will need to be verified manually (see comments in that file)
## Making a release
A quick checklist:
- [ ] make sure CI is green!
- [ ] update `CHANGELOG.md` and `lib/sqlite3/version.rb` including `VersionProxy::{MINOR,TINY}`
- [ ] run `bin/build-gems` and make sure it completes and all the tests pass
- [ ] create a git tag using a format that matches the pattern `v\d+\.\d+\.\d+`, e.g. `v1.3.13`
- [ ] `git push && git push --tags`
- [ ] `for g in gems/*.gem ; do gem push $g ; done`
- [ ] create a release at https://github.com/sparklemotion/sqlite3-ruby/releases and include sha2 checksums
sqlite3-1.7.3/lib/ 0000755 0000041 0000041 00000000000 14620135377 013714 5 ustar www-data www-data sqlite3-1.7.3/lib/sqlite3/ 0000755 0000041 0000041 00000000000 14620135377 015300 5 ustar www-data www-data sqlite3-1.7.3/lib/sqlite3/pragmas.rb 0000644 0000041 0000041 00000034525 14620135377 017270 0 ustar www-data www-data require 'sqlite3/errors'
module SQLite3
# This module is intended for inclusion solely by the Database class. It
# defines convenience methods for the various pragmas supported by SQLite3.
#
# For a detailed description of these pragmas, see the SQLite3 documentation
# at http://sqlite.org/pragma.html.
module Pragmas
# Returns +true+ or +false+ depending on the value of the named pragma.
def get_boolean_pragma( name )
get_first_value( "PRAGMA #{name}" ) != 0
end
# Sets the given pragma to the given boolean value. The value itself
# may be +true+ or +false+, or any other commonly used string or
# integer that represents truth.
def set_boolean_pragma( name, mode )
case mode
when String
case mode.downcase
when "on", "yes", "true", "y", "t"; mode = "'ON'"
when "off", "no", "false", "n", "f"; mode = "'OFF'"
else
raise Exception,
"unrecognized pragma parameter #{mode.inspect}"
end
when true, 1
mode = "ON"
when false, 0, nil
mode = "OFF"
else
raise Exception,
"unrecognized pragma parameter #{mode.inspect}"
end
execute( "PRAGMA #{name}=#{mode}" )
end
# Requests the given pragma (and parameters), and if the block is given,
# each row of the result set will be yielded to it. Otherwise, the results
# are returned as an array.
def get_query_pragma( name, *params, &block ) # :yields: row
if params.empty?
execute( "PRAGMA #{name}", &block )
else
args = "'" + params.join("','") + "'"
execute( "PRAGMA #{name}( #{args} )", &block )
end
end
# Return the value of the given pragma.
def get_enum_pragma( name )
get_first_value( "PRAGMA #{name}" )
end
# Set the value of the given pragma to +mode+. The +mode+ parameter must
# conform to one of the values in the given +enum+ array. Each entry in
# the array is another array comprised of elements in the enumeration that
# have duplicate values. See #synchronous, #default_synchronous,
# #temp_store, and #default_temp_store for usage examples.
def set_enum_pragma( name, mode, enums )
match = enums.find { |p| p.find { |i| i.to_s.downcase == mode.to_s.downcase } }
raise Exception,
"unrecognized #{name} #{mode.inspect}" unless match
execute( "PRAGMA #{name}='#{match.first.upcase}'" )
end
# Returns the value of the given pragma as an integer.
def get_int_pragma( name )
get_first_value( "PRAGMA #{name}" ).to_i
end
# Set the value of the given pragma to the integer value of the +value+
# parameter.
def set_int_pragma( name, value )
execute( "PRAGMA #{name}=#{value.to_i}" )
end
# The enumeration of valid synchronous modes.
SYNCHRONOUS_MODES = [ [ 'full', 2 ], [ 'normal', 1 ], [ 'off', 0 ] ]
# The enumeration of valid temp store modes.
TEMP_STORE_MODES = [ [ 'default', 0 ], [ 'file', 1 ], [ 'memory', 2 ] ]
# The enumeration of valid auto vacuum modes.
AUTO_VACUUM_MODES = [ [ 'none', 0 ], [ 'full', 1 ], [ 'incremental', 2 ] ]
# The list of valid journaling modes.
JOURNAL_MODES = [ [ 'delete' ], [ 'truncate' ], [ 'persist' ], [ 'memory' ],
[ 'wal' ], [ 'off' ] ]
# The list of valid locking modes.
LOCKING_MODES = [ [ 'normal' ], [ 'exclusive' ] ]
# The list of valid encodings.
ENCODINGS = [ [ 'utf-8' ], [ 'utf-16' ], [ 'utf-16le' ], [ 'utf-16be ' ] ]
# The list of valid WAL checkpoints.
WAL_CHECKPOINTS = [ [ 'passive' ], [ 'full' ], [ 'restart' ], [ 'truncate' ] ]
def application_id
get_int_pragma "application_id"
end
def application_id=( integer )
set_int_pragma "application_id", integer
end
def auto_vacuum
get_enum_pragma "auto_vacuum"
end
def auto_vacuum=( mode )
set_enum_pragma "auto_vacuum", mode, AUTO_VACUUM_MODES
end
def automatic_index
get_boolean_pragma "automatic_index"
end
def automatic_index=( mode )
set_boolean_pragma "automatic_index", mode
end
def busy_timeout
get_int_pragma "busy_timeout"
end
def busy_timeout=( milliseconds )
set_int_pragma "busy_timeout", milliseconds
end
def cache_size
get_int_pragma "cache_size"
end
def cache_size=( size )
set_int_pragma "cache_size", size
end
def cache_spill
get_boolean_pragma "cache_spill"
end
def cache_spill=( mode )
set_boolean_pragma "cache_spill", mode
end
def case_sensitive_like=( mode )
set_boolean_pragma "case_sensitive_like", mode
end
def cell_size_check
get_boolean_pragma "cell_size_check"
end
def cell_size_check=( mode )
set_boolean_pragma "cell_size_check", mode
end
def checkpoint_fullfsync
get_boolean_pragma "checkpoint_fullfsync"
end
def checkpoint_fullfsync=( mode )
set_boolean_pragma "checkpoint_fullfsync", mode
end
def collation_list( &block ) # :yields: row
get_query_pragma "collation_list", &block
end
def compile_options( &block ) # :yields: row
get_query_pragma "compile_options", &block
end
def count_changes
get_boolean_pragma "count_changes"
end
def count_changes=( mode )
set_boolean_pragma "count_changes", mode
end
def data_version
get_int_pragma "data_version"
end
def database_list( &block ) # :yields: row
get_query_pragma "database_list", &block
end
def default_cache_size
get_int_pragma "default_cache_size"
end
def default_cache_size=( size )
set_int_pragma "default_cache_size", size
end
def default_synchronous
get_enum_pragma "default_synchronous"
end
def default_synchronous=( mode )
set_enum_pragma "default_synchronous", mode, SYNCHRONOUS_MODES
end
def default_temp_store
get_enum_pragma "default_temp_store"
end
def default_temp_store=( mode )
set_enum_pragma "default_temp_store", mode, TEMP_STORE_MODES
end
def defer_foreign_keys
get_boolean_pragma "defer_foreign_keys"
end
def defer_foreign_keys=( mode )
set_boolean_pragma "defer_foreign_keys", mode
end
def encoding
get_enum_pragma "encoding"
end
def encoding=( mode )
set_enum_pragma "encoding", mode, ENCODINGS
end
def foreign_key_check( *table, &block ) # :yields: row
get_query_pragma "foreign_key_check", *table, &block
end
def foreign_key_list( table, &block ) # :yields: row
get_query_pragma "foreign_key_list", table, &block
end
def foreign_keys
get_boolean_pragma "foreign_keys"
end
def foreign_keys=( mode )
set_boolean_pragma "foreign_keys", mode
end
def freelist_count
get_int_pragma "freelist_count"
end
def full_column_names
get_boolean_pragma "full_column_names"
end
def full_column_names=( mode )
set_boolean_pragma "full_column_names", mode
end
def fullfsync
get_boolean_pragma "fullfsync"
end
def fullfsync=( mode )
set_boolean_pragma "fullfsync", mode
end
def ignore_check_constraints=( mode )
set_boolean_pragma "ignore_check_constraints", mode
end
def incremental_vacuum( pages, &block ) # :yields: row
get_query_pragma "incremental_vacuum", pages, &block
end
def index_info( index, &block ) # :yields: row
get_query_pragma "index_info", index, &block
end
def index_list( table, &block ) # :yields: row
get_query_pragma "index_list", table, &block
end
def index_xinfo( index, &block ) # :yields: row
get_query_pragma "index_xinfo", index, &block
end
def integrity_check( *num_errors, &block ) # :yields: row
get_query_pragma "integrity_check", *num_errors, &block
end
def journal_mode
get_enum_pragma "journal_mode"
end
def journal_mode=( mode )
set_enum_pragma "journal_mode", mode, JOURNAL_MODES
end
def journal_size_limit
get_int_pragma "journal_size_limit"
end
def journal_size_limit=( size )
set_int_pragma "journal_size_limit", size
end
def legacy_file_format
get_boolean_pragma "legacy_file_format"
end
def legacy_file_format=( mode )
set_boolean_pragma "legacy_file_format", mode
end
def locking_mode
get_enum_pragma "locking_mode"
end
def locking_mode=( mode )
set_enum_pragma "locking_mode", mode, LOCKING_MODES
end
def max_page_count
get_int_pragma "max_page_count"
end
def max_page_count=( size )
set_int_pragma "max_page_count", size
end
def mmap_size
get_int_pragma "mmap_size"
end
def mmap_size=( size )
set_int_pragma "mmap_size", size
end
def page_count
get_int_pragma "page_count"
end
def page_size
get_int_pragma "page_size"
end
def page_size=( size )
set_int_pragma "page_size", size
end
def parser_trace=( mode )
set_boolean_pragma "parser_trace", mode
end
def query_only
get_boolean_pragma "query_only"
end
def query_only=( mode )
set_boolean_pragma "query_only", mode
end
def quick_check( *num_errors, &block ) # :yields: row
get_query_pragma "quick_check", *num_errors, &block
end
def read_uncommitted
get_boolean_pragma "read_uncommitted"
end
def read_uncommitted=( mode )
set_boolean_pragma "read_uncommitted", mode
end
def recursive_triggers
get_boolean_pragma "recursive_triggers"
end
def recursive_triggers=( mode )
set_boolean_pragma "recursive_triggers", mode
end
def reverse_unordered_selects
get_boolean_pragma "reverse_unordered_selects"
end
def reverse_unordered_selects=( mode )
set_boolean_pragma "reverse_unordered_selects", mode
end
def schema_cookie
get_int_pragma "schema_cookie"
end
def schema_cookie=( cookie )
set_int_pragma "schema_cookie", cookie
end
def schema_version
get_int_pragma "schema_version"
end
def schema_version=( version )
set_int_pragma "schema_version", version
end
def secure_delete
get_boolean_pragma "secure_delete"
end
def secure_delete=( mode )
set_boolean_pragma "secure_delete", mode
end
def short_column_names
get_boolean_pragma "short_column_names"
end
def short_column_names=( mode )
set_boolean_pragma "short_column_names", mode
end
def shrink_memory
execute( "PRAGMA shrink_memory" )
end
def soft_heap_limit
get_int_pragma "soft_heap_limit"
end
def soft_heap_limit=( mode )
set_int_pragma "soft_heap_limit", mode
end
def stats( &block ) # :yields: row
get_query_pragma "stats", &block
end
def synchronous
get_enum_pragma "synchronous"
end
def synchronous=( mode )
set_enum_pragma "synchronous", mode, SYNCHRONOUS_MODES
end
def temp_store
get_enum_pragma "temp_store"
end
def temp_store=( mode )
set_enum_pragma "temp_store", mode, TEMP_STORE_MODES
end
def threads
get_int_pragma "threads"
end
def threads=( count )
set_int_pragma "threads", count
end
def user_cookie
get_int_pragma "user_cookie"
end
def user_cookie=( cookie )
set_int_pragma "user_cookie", cookie
end
def user_version
get_int_pragma "user_version"
end
def user_version=( version )
set_int_pragma "user_version", version
end
def vdbe_addoptrace=( mode )
set_boolean_pragma "vdbe_addoptrace", mode
end
def vdbe_debug=( mode )
set_boolean_pragma "vdbe_debug", mode
end
def vdbe_listing=( mode )
set_boolean_pragma "vdbe_listing", mode
end
def vdbe_trace
get_boolean_pragma "vdbe_trace"
end
def vdbe_trace=( mode )
set_boolean_pragma "vdbe_trace", mode
end
def wal_autocheckpoint
get_int_pragma "wal_autocheckpoint"
end
def wal_autocheckpoint=( mode )
set_int_pragma "wal_autocheckpoint", mode
end
def wal_checkpoint
get_enum_pragma "wal_checkpoint"
end
def wal_checkpoint=( mode )
set_enum_pragma "wal_checkpoint", mode, WAL_CHECKPOINTS
end
def writable_schema=( mode )
set_boolean_pragma "writable_schema", mode
end
###
# Returns information about +table+. Yields each row of table information
# if a block is provided.
def table_info table
stmt = prepare "PRAGMA table_info(#{table})"
columns = stmt.columns
needs_tweak_default =
version_compare(SQLite3.libversion.to_s, "3.3.7") > 0
result = [] unless block_given?
stmt.each do |row|
new_row = Hash[columns.zip(row)]
# FIXME: This should be removed but is required for older versions
# of rails
if(Object.const_defined?(:ActiveRecord))
new_row['notnull'] = new_row['notnull'].to_s
end
tweak_default(new_row) if needs_tweak_default
# Ensure the type value is downcased. On Mac and Windows
# platforms this value is now being returned as all upper
# case.
if new_row['type']
new_row['type'] = new_row['type'].downcase
end
if block_given?
yield new_row
else
result << new_row
end
end
stmt.close
result
end
private
# Compares two version strings
def version_compare(v1, v2)
v1 = v1.split(".").map { |i| i.to_i }
v2 = v2.split(".").map { |i| i.to_i }
parts = [v1.length, v2.length].max
v1.push 0 while v1.length < parts
v2.push 0 while v2.length < parts
v1.zip(v2).each do |a,b|
return -1 if a < b
return 1 if a > b
end
return 0
end
# Since SQLite 3.3.8, the table_info pragma has returned the default
# value of the row as a quoted SQL value. This method essentially
# unquotes those values.
def tweak_default(hash)
case hash["dflt_value"]
when /^null$/i
hash["dflt_value"] = nil
when /^'(.*)'$/m
hash["dflt_value"] = $1.gsub(/''/, "'")
when /^"(.*)"$/m
hash["dflt_value"] = $1.gsub(/""/, '"')
end
end
end
end
sqlite3-1.7.3/lib/sqlite3/statement.rb 0000644 0000041 0000041 00000010025 14620135377 017627 0 ustar www-data www-data require 'sqlite3/errors'
require 'sqlite3/resultset'
class String
def to_blob
SQLite3::Blob.new( self )
end
end
module SQLite3
# A statement represents a prepared-but-unexecuted SQL query. It will rarely
# (if ever) be instantiated directly by a client, and is most often obtained
# via the Database#prepare method.
class Statement
include Enumerable
# This is any text that followed the first valid SQL statement in the text
# with which the statement was initialized. If there was no trailing text,
# this will be the empty string.
attr_reader :remainder
# Binds the given variables to the corresponding placeholders in the SQL
# text.
#
# See Database#execute for a description of the valid placeholder
# syntaxes.
#
# Example:
#
# stmt = db.prepare( "select * from table where a=? and b=?" )
# stmt.bind_params( 15, "hello" )
#
# See also #execute, #bind_param, Statement#bind_param, and
# Statement#bind_params.
def bind_params( *bind_vars )
index = 1
bind_vars.flatten.each do |var|
if Hash === var
var.each { |key, val| bind_param key, val }
else
bind_param index, var
index += 1
end
end
end
# Execute the statement. This creates a new ResultSet object for the
# statement's virtual machine. If a block was given, the new ResultSet will
# be yielded to it; otherwise, the ResultSet will be returned.
#
# Any parameters will be bound to the statement using #bind_params.
#
# Example:
#
# stmt = db.prepare( "select * from table" )
# stmt.execute do |result|
# ...
# end
#
# See also #bind_params, #execute!.
def execute( *bind_vars )
reset! if active? || done?
bind_params(*bind_vars) unless bind_vars.empty?
@results = ResultSet.new(@connection, self)
step if 0 == column_count
yield @results if block_given?
@results
end
# Execute the statement. If no block was given, this returns an array of
# rows returned by executing the statement. Otherwise, each row will be
# yielded to the block.
#
# Any parameters will be bound to the statement using #bind_params.
#
# Example:
#
# stmt = db.prepare( "select * from table" )
# stmt.execute! do |row|
# ...
# end
#
# See also #bind_params, #execute.
def execute!( *bind_vars, &block )
execute(*bind_vars)
block_given? ? each(&block) : to_a
end
# Returns true if the statement is currently active, meaning it has an
# open result set.
def active?
!done?
end
# Return an array of the column names for this statement. Note that this
# may execute the statement in order to obtain the metadata; this makes it
# a (potentially) expensive operation.
def columns
get_metadata unless @columns
return @columns
end
def each
loop do
val = step
break self if done?
yield val
end
end
# Return an array of the data types for each column in this statement. Note
# that this may execute the statement in order to obtain the metadata; this
# makes it a (potentially) expensive operation.
def types
must_be_open!
get_metadata unless @types
@types
end
# Performs a sanity check to ensure that the statement is not
# closed. If it is, an exception is raised.
def must_be_open! # :nodoc:
if closed?
raise SQLite3::Exception, "cannot use a closed statement"
end
end
private
# A convenience method for obtaining the metadata about the query. Note
# that this will actually execute the SQL, which means it can be a
# (potentially) expensive operation.
def get_metadata
@columns = Array.new(column_count) do |column|
column_name column
end
@types = Array.new(column_count) do |column|
val = column_decltype(column)
val.nil? ? nil : val.downcase
end
end
end
end
sqlite3-1.7.3/lib/sqlite3/database.rb 0000644 0000041 0000041 00000063764 14620135377 017411 0 ustar www-data www-data require 'sqlite3/constants'
require 'sqlite3/errors'
require 'sqlite3/pragmas'
require 'sqlite3/statement'
require 'sqlite3/translator'
require 'sqlite3/value'
module SQLite3
# The Database class encapsulates a single connection to a SQLite3 database.
# Its usage is very straightforward:
#
# require 'sqlite3'
#
# SQLite3::Database.new( "data.db" ) do |db|
# db.execute( "select * from table" ) do |row|
# p row
# end
# end
#
# It wraps the lower-level methods provided by the selected driver, and
# includes the Pragmas module for access to various pragma convenience
# methods.
#
# The Database class provides type translation services as well, by which
# the SQLite3 data types (which are all represented as strings) may be
# converted into their corresponding types (as defined in the schemas
# for their tables). This translation only occurs when querying data from
# the database--insertions and updates are all still typeless.
#
# Furthermore, the Database class has been designed to work well with the
# ArrayFields module from Ara Howard. If you require the ArrayFields
# module before performing a query, and if you have not enabled results as
# hashes, then the results will all be indexible by field name.
class Database
attr_reader :collations
include Pragmas
class << self
# Without block works exactly as new.
# With block, like new closes the database at the end, but unlike new
# returns the result of the block instead of the database instance.
def open( *args )
database = new(*args)
if block_given?
begin
yield database
ensure
database.close
end
else
database
end
end
# Quotes the given string, making it safe to use in an SQL statement.
# It replaces all instances of the single-quote character with two
# single-quote characters. The modified string is returned.
def quote( string )
string.gsub( /'/, "''" )
end
end
# A boolean that indicates whether rows in result sets should be returned
# as hashes or not. By default, rows are returned as arrays.
attr_accessor :results_as_hash
# call-seq: SQLite3::Database.new(file, options = {})
#
# Create a new Database object that opens the given file.
#
# Supported permissions +options+:
# - the default mode is READWRITE | CREATE
# - +:readonly+: boolean (default false), true to set the mode to +READONLY+
# - +:readwrite+: boolean (default false), true to set the mode to +READWRITE+
# - +:flags+: set the mode to a combination of SQLite3::Constants::Open flags.
#
# Supported encoding +options+:
# - +:utf16+: boolean (default false), is the filename's encoding UTF-16 (only needed if the filename encoding is not UTF_16LE or BE)
#
# Other supported +options+:
# - +:strict+: boolean (default false), disallow the use of double-quoted string literals (see https://www.sqlite.org/quirks.html#double_quoted_string_literals_are_accepted)
# - +:results_as_hash+: boolean (default false), return rows as hashes instead of arrays
# - +:type_translation+: boolean (default false), enable type translation
# - +:default_transaction_mode+: one of +:deferred+ (default), +:immediate+, or +:exclusive+. If a mode is not specified in a call to #transaction, this will be the default transaction mode.
#
def initialize file, options = {}, zvfs = nil
mode = Constants::Open::READWRITE | Constants::Open::CREATE
file = file.to_path if file.respond_to? :to_path
if file.encoding == ::Encoding::UTF_16LE || file.encoding == ::Encoding::UTF_16BE || options[:utf16]
open16 file
else
# The three primary flag values for sqlite3_open_v2 are:
# SQLITE_OPEN_READONLY
# SQLITE_OPEN_READWRITE
# SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE -- always used for sqlite3_open and sqlite3_open16
mode = Constants::Open::READONLY if options[:readonly]
if options[:readwrite]
raise "conflicting options: readonly and readwrite" if options[:readonly]
mode = Constants::Open::READWRITE
end
if options[:flags]
if options[:readonly] || options[:readwrite]
raise "conflicting options: flags with readonly and/or readwrite"
end
mode = options[:flags]
end
open_v2 file.encode("utf-8"), mode, zvfs
if options[:strict]
disable_quirk_mode
end
end
@tracefunc = nil
@authorizer = nil
@encoding = nil
@busy_handler = nil
@collations = {}
@functions = {}
@results_as_hash = options[:results_as_hash]
@type_translation = options[:type_translation]
@type_translator = make_type_translator @type_translation
@readonly = mode & Constants::Open::READONLY != 0
@default_transaction_mode = options[:default_transaction_mode] || :deferred
if block_given?
begin
yield self
ensure
close
end
end
end
def type_translation= value # :nodoc:
warn(<<-eowarn) if $VERBOSE
#{caller[0]} is calling `SQLite3::Database#type_translation=` which is deprecated and will be removed in version 2.0.0.
eowarn
@type_translator = make_type_translator value
@type_translation = value
end
attr_reader :type_translation # :nodoc:
# Return the type translator employed by this database instance. Each
# database instance has its own type translator; this allows for different
# type handlers to be installed in each instance without affecting other
# instances. Furthermore, the translators are instantiated lazily, so that
# if a database does not use type translation, it will not be burdened by
# the overhead of a useless type translator. (See the Translator class.)
def translator
@translator ||= Translator.new
end
# Installs (or removes) a block that will be invoked for every access
# to the database. If the block returns 0 (or +nil+), the statement
# is allowed to proceed. Returning 1 causes an authorization error to
# occur, and returning 2 causes the access to be silently denied.
def authorizer( &block )
self.authorizer = block
end
# Returns a Statement object representing the given SQL. This does not
# execute the statement; it merely prepares the statement for execution.
#
# The Statement can then be executed using Statement#execute.
#
def prepare sql
stmt = SQLite3::Statement.new( self, sql )
return stmt unless block_given?
begin
yield stmt
ensure
stmt.close unless stmt.closed?
end
end
# Returns the filename for the database named +db_name+. +db_name+ defaults
# to "main". Main return `nil` or an empty string if the database is
# temporary or in-memory.
def filename db_name = 'main'
db_filename db_name
end
# Executes the given SQL statement. If additional parameters are given,
# they are treated as bind variables, and are bound to the placeholders in
# the query.
#
# Note that if any of the values passed to this are hashes, then the
# key/value pairs are each bound separately, with the key being used as
# the name of the placeholder to bind the value to.
#
# The block is optional. If given, it will be invoked for each row returned
# by the query. Otherwise, any results are accumulated into an array and
# returned wholesale.
#
# See also #execute2, #query, and #execute_batch for additional ways of
# executing statements.
def execute sql, bind_vars = [], *args, &block
if bind_vars.nil? || !args.empty?
if args.empty?
bind_vars = []
else
bind_vars = [bind_vars] + args
end
warn(<<-eowarn) if $VERBOSE
#{caller[0]} is calling `SQLite3::Database#execute` with nil or multiple bind params without using an array. Please switch to passing bind parameters as an array. Support for bind parameters as *args will be removed in 2.0.0.
eowarn
end
prepare( sql ) do |stmt|
stmt.bind_params(bind_vars)
stmt = ResultSet.new self, stmt
if block_given?
stmt.each do |row|
yield row
end
else
stmt.to_a
end
end
end
# Executes the given SQL statement, exactly as with #execute. However, the
# first row returned (either via the block, or in the returned array) is
# always the names of the columns. Subsequent rows correspond to the data
# from the result set.
#
# Thus, even if the query itself returns no rows, this method will always
# return at least one row--the names of the columns.
#
# See also #execute, #query, and #execute_batch for additional ways of
# executing statements.
def execute2( sql, *bind_vars )
prepare( sql ) do |stmt|
result = stmt.execute( *bind_vars )
if block_given?
yield stmt.columns
result.each { |row| yield row }
else
return result.inject( [ stmt.columns ] ) { |arr,row|
arr << row; arr }
end
end
end
# Executes all SQL statements in the given string. By contrast, the other
# means of executing queries will only execute the first statement in the
# string, ignoring all subsequent statements. This will execute each one
# in turn. The same bind parameters, if given, will be applied to each
# statement.
#
# This always returns +nil+, making it unsuitable for queries that return
# rows.
#
# See also #execute_batch2 for additional ways of
# executing statements.
def execute_batch( sql, bind_vars = [], *args )
# FIXME: remove this stuff later
unless [Array, Hash].include?(bind_vars.class)
bind_vars = [bind_vars]
warn(<<-eowarn) if $VERBOSE
#{caller[0]} is calling `SQLite3::Database#execute_batch` with bind parameters that are not a list of a hash. Please switch to passing bind parameters as an array or hash. Support for this behavior will be removed in version 2.0.0.
eowarn
end
# FIXME: remove this stuff later
if bind_vars.nil? || !args.empty?
if args.empty?
bind_vars = []
else
bind_vars = [nil] + args
end
warn(<<-eowarn) if $VERBOSE
#{caller[0]} is calling `SQLite3::Database#execute_batch` with nil or multiple bind params without using an array. Please switch to passing bind parameters as an array. Support for this behavior will be removed in version 2.0.0.
eowarn
end
sql = sql.strip
until sql.empty? do
prepare( sql ) do |stmt|
unless stmt.closed?
# FIXME: this should probably use sqlite3's api for batch execution
# This implementation requires stepping over the results.
if bind_vars.length == stmt.bind_parameter_count
stmt.bind_params(bind_vars)
end
stmt.step
end
sql = stmt.remainder.strip
end
end
# FIXME: we should not return `nil` as a success return value
nil
end
# Executes all SQL statements in the given string. By contrast, the other
# means of executing queries will only execute the first statement in the
# string, ignoring all subsequent statements. This will execute each one
# in turn. Bind parameters cannot be passed to #execute_batch2.
#
# If a query is made, all values will be returned as strings.
# If no query is made, an empty array will be returned.
#
# Because all values except for 'NULL' are returned as strings,
# a block can be passed to parse the values accordingly.
#
# See also #execute_batch for additional ways of
# executing statements.
def execute_batch2(sql, &block)
if block_given?
result = exec_batch(sql, @results_as_hash)
result.map do |val|
yield val
end
else
exec_batch(sql, @results_as_hash)
end
end
# This is a convenience method for creating a statement, binding
# parameters to it, and calling execute:
#
# result = db.query( "select * from foo where a=?", [5])
# # is the same as
# result = db.prepare( "select * from foo where a=?" ).execute( 5 )
#
# You must be sure to call +close+ on the ResultSet instance that is
# returned, or you could have problems with locks on the table. If called
# with a block, +close+ will be invoked implicitly when the block
# terminates.
def query( sql, bind_vars = [], *args )
if bind_vars.nil? || !args.empty?
if args.empty?
bind_vars = []
else
bind_vars = [bind_vars] + args
end
warn(<<-eowarn) if $VERBOSE
#{caller[0]} is calling `SQLite3::Database#query` with nil or multiple bind params without using an array. Please switch to passing bind parameters as an array. Support for this will be removed in version 2.0.0.
eowarn
end
result = prepare( sql ).execute( bind_vars )
if block_given?
begin
yield result
ensure
result.close
end
else
return result
end
end
# A convenience method for obtaining the first row of a result set, and
# discarding all others. It is otherwise identical to #execute.
#
# See also #get_first_value.
def get_first_row( sql, *bind_vars )
execute( sql, *bind_vars ).first
end
# A convenience method for obtaining the first value of the first row of a
# result set, and discarding all other values and rows. It is otherwise
# identical to #execute.
#
# See also #get_first_row.
def get_first_value( sql, *bind_vars )
query( sql, bind_vars ) do |rs|
if (row = rs.next)
return @results_as_hash ? row[rs.columns[0]] : row[0]
end
end
nil
end
alias :busy_timeout :busy_timeout=
# Creates a new function for use in SQL statements. It will be added as
# +name+, with the given +arity+. (For variable arity functions, use
# -1 for the arity.)
#
# The block should accept at least one parameter--the FunctionProxy
# instance that wraps this function invocation--and any other
# arguments it needs (up to its arity).
#
# The block does not return a value directly. Instead, it will invoke
# the FunctionProxy#result= method on the +func+ parameter and
# indicate the return value that way.
#
# Example:
#
# db.create_function( "maim", 1 ) do |func, value|
# if value.nil?
# func.result = nil
# else
# func.result = value.split(//).sort.join
# end
# end
#
# puts db.get_first_value( "select maim(name) from table" )
def create_function name, arity, text_rep=Constants::TextRep::UTF8, &block
define_function_with_flags(name, text_rep) do |*args|
fp = FunctionProxy.new
block.call(fp, *args)
fp.result
end
self
end
# Creates a new aggregate function for use in SQL statements. Aggregate
# functions are functions that apply over every row in the result set,
# instead of over just a single row. (A very common aggregate function
# is the "count" function, for determining the number of rows that match
# a query.)
#
# The new function will be added as +name+, with the given +arity+. (For
# variable arity functions, use -1 for the arity.)
#
# The +step+ parameter must be a proc object that accepts as its first
# parameter a FunctionProxy instance (representing the function
# invocation), with any subsequent parameters (up to the function's arity).
# The +step+ callback will be invoked once for each row of the result set.
#
# The +finalize+ parameter must be a +proc+ object that accepts only a
# single parameter, the FunctionProxy instance representing the current
# function invocation. It should invoke FunctionProxy#result= to
# store the result of the function.
#
# Example:
#
# db.create_aggregate( "lengths", 1 ) do
# step do |func, value|
# func[ :total ] ||= 0
# func[ :total ] += ( value ? value.length : 0 )
# end
#
# finalize do |func|
# func.result = func[ :total ] || 0
# end
# end
#
# puts db.get_first_value( "select lengths(name) from table" )
#
# See also #create_aggregate_handler for a more object-oriented approach to
# aggregate functions.
def create_aggregate( name, arity, step=nil, finalize=nil,
text_rep=Constants::TextRep::ANY, &block )
proxy = Class.new do
def self.step( &block )
define_method(:step_with_ctx, &block)
end
def self.finalize( &block )
define_method(:finalize_with_ctx, &block)
end
end
if block_given?
proxy.instance_eval(&block)
else
proxy.class_eval do
define_method(:step_with_ctx, step)
define_method(:finalize_with_ctx, finalize)
end
end
proxy.class_eval do
# class instance variables
@name = name
@arity = arity
def self.name
@name
end
def self.arity
@arity
end
def initialize
@ctx = FunctionProxy.new
end
def step( *args )
step_with_ctx(@ctx, *args)
end
def finalize
finalize_with_ctx(@ctx)
@ctx.result
end
end
define_aggregator2(proxy, name)
end
# This is another approach to creating an aggregate function (see
# #create_aggregate). Instead of explicitly specifying the name,
# callbacks, arity, and type, you specify a factory object
# (the "handler") that knows how to obtain all of that information. The
# handler should respond to the following messages:
#
# +arity+:: corresponds to the +arity+ parameter of #create_aggregate. This
# message is optional, and if the handler does not respond to it,
# the function will have an arity of -1.
# +name+:: this is the name of the function. The handler _must_ implement
# this message.
# +new+:: this must be implemented by the handler. It should return a new
# instance of the object that will handle a specific invocation of
# the function.
#
# The handler instance (the object returned by the +new+ message, described
# above), must respond to the following messages:
#
# +step+:: this is the method that will be called for each step of the
# aggregate function's evaluation. It should implement the same
# signature as the +step+ callback for #create_aggregate.
# +finalize+:: this is the method that will be called to finalize the
# aggregate function's evaluation. It should implement the
# same signature as the +finalize+ callback for
# #create_aggregate.
#
# Example:
#
# class LengthsAggregateHandler
# def self.arity; 1; end
# def self.name; 'lengths'; end
#
# def initialize
# @total = 0
# end
#
# def step( ctx, name )
# @total += ( name ? name.length : 0 )
# end
#
# def finalize( ctx )
# ctx.result = @total
# end
# end
#
# db.create_aggregate_handler( LengthsAggregateHandler )
# puts db.get_first_value( "select lengths(name) from A" )
def create_aggregate_handler( handler )
# This is a compatibility shim so the (basically pointless) FunctionProxy
# "ctx" object is passed as first argument to both step() and finalize().
# Now its up to the library user whether he prefers to store his
# temporaries as instance variables or fields in the FunctionProxy.
# The library user still must set the result value with
# FunctionProxy.result= as there is no backwards compatible way to
# change this.
proxy = Class.new(handler) do
def initialize
super
@fp = FunctionProxy.new
end
def step( *args )
super(@fp, *args)
end
def finalize
super(@fp)
@fp.result
end
end
define_aggregator2(proxy, proxy.name)
self
end
# Define an aggregate function named +name+ using a object template
# object +aggregator+. +aggregator+ must respond to +step+ and +finalize+.
# +step+ will be called with row information and +finalize+ must return the
# return value for the aggregator function.
#
# _API Change:_ +aggregator+ must also implement +clone+. The provided
# +aggregator+ object will serve as template that is cloned to provide the
# individual instances of the aggregate function. Regular ruby objects
# already provide a suitable +clone+.
# The functions arity is the arity of the +step+ method.
def define_aggregator( name, aggregator )
# Previously, this has been implemented in C. Now this is just yet
# another compatibility shim
proxy = Class.new do
@template = aggregator
@name = name
def self.template
@template
end
def self.name
@name
end
def self.arity
# this is what sqlite3_obj_method_arity did before
@template.method(:step).arity
end
def initialize
@klass = self.class.template.clone
end
def step(*args)
@klass.step(*args)
end
def finalize
@klass.finalize
end
end
define_aggregator2(proxy, name)
self
end
# Begins a new transaction. Note that nested transactions are not allowed
# by SQLite, so attempting to nest a transaction will result in a runtime
# exception.
#
# The +mode+ parameter may be either :deferred,
# :immediate, or :exclusive.
# If `nil` is specified, the default transaction mode, which was
# passed to #initialize, is used.
#
# If a block is given, the database instance is yielded to it, and the
# transaction is committed when the block terminates. If the block
# raises an exception, a rollback will be performed instead. Note that if
# a block is given, #commit and #rollback should never be called
# explicitly or you'll get an error when the block terminates.
#
# If a block is not given, it is the caller's responsibility to end the
# transaction explicitly, either by calling #commit, or by calling
# #rollback.
def transaction( mode = nil )
mode = @default_transaction_mode if mode.nil?
execute "begin #{mode.to_s} transaction"
if block_given?
abort = false
begin
yield self
rescue
abort = true
raise
ensure
abort and rollback or commit
end
end
true
end
# Commits the current transaction. If there is no current transaction,
# this will cause an error to be raised. This returns +true+, in order
# to allow it to be used in idioms like
# abort? and rollback or commit.
def commit
execute "commit transaction"
true
end
# Rolls the current transaction back. If there is no current transaction,
# this will cause an error to be raised. This returns +true+, in order
# to allow it to be used in idioms like
# abort? and rollback or commit.
def rollback
execute "rollback transaction"
true
end
# Returns +true+ if the database has been open in readonly mode
# A helper to check before performing any operation
def readonly?
@readonly
end
# A helper class for dealing with custom functions (see #create_function,
# #create_aggregate, and #create_aggregate_handler). It encapsulates the
# opaque function object that represents the current invocation. It also
# provides more convenient access to the API functions that operate on
# the function object.
#
# This class will almost _always_ be instantiated indirectly, by working
# with the create methods mentioned above.
class FunctionProxy
attr_accessor :result
# Create a new FunctionProxy that encapsulates the given +func+ object.
# If context is non-nil, the functions context will be set to that. If
# it is non-nil, it must quack like a Hash. If it is nil, then none of
# the context functions will be available.
def initialize
@result = nil
@context = {}
end
# Set the result of the function to the given error message.
# The function will then return that error.
def set_error( error )
@driver.result_error( @func, error.to_s, -1 )
end
# (Only available to aggregate functions.) Returns the number of rows
# that the aggregate has processed so far. This will include the current
# row, and so will always return at least 1.
def count
@driver.aggregate_count( @func )
end
# Returns the value with the given key from the context. This is only
# available to aggregate functions.
def []( key )
@context[ key ]
end
# Sets the value with the given key in the context. This is only
# available to aggregate functions.
def []=( key, value )
@context[ key ] = value
end
end
# Translates a +row+ of data from the database with the given +types+
def translate_from_db types, row
@type_translator.call types, row
end
private
NULL_TRANSLATOR = lambda { |_, row| row }
def make_type_translator should_translate
if should_translate
lambda { |types, row|
types.zip(row).map do |type, value|
translator.translate( type, value )
end
}
else
NULL_TRANSLATOR
end
end
end
end
sqlite3-1.7.3/lib/sqlite3/translator.rb 0000644 0000041 0000041 00000010047 14620135377 020020 0 ustar www-data www-data require 'time'
require 'date'
module SQLite3
# The Translator class encapsulates the logic and callbacks necessary for
# converting string data to a value of some specified type. Every Database
# instance may have a Translator instance, in order to assist in type
# translation (Database#type_translation).
#
# Further, applications may define their own custom type translation logic
# by registering translator blocks with the corresponding database's
# translator instance (Database#translator).
class Translator
# Create a new Translator instance. It will be preinitialized with default
# translators for most SQL data types.
def initialize
@translators = Hash.new( proc { |type,value| value } )
@type_name_cache = {}
register_default_translators
end
# Add a new translator block, which will be invoked to process type
# translations to the given type. The type should be an SQL datatype, and
# may include parentheses (i.e., "VARCHAR(30)"). However, any parenthetical
# information is stripped off and discarded, so type translation decisions
# are made solely on the "base" type name.
#
# The translator block itself should accept two parameters, "type" and
# "value". In this case, the "type" is the full type name (including
# parentheses), so the block itself may include logic for changing how a
# type is translated based on the additional data. The "value" parameter
# is the (string) data to convert.
#
# The block should return the translated value.
def add_translator( type, &block ) # :yields: type, value
warn(<<-eowarn) if $VERBOSE
#{caller[0]} is calling `SQLite3::Translator#add_translator`. Built-in translators are deprecated and will be removed in version 2.0.0.
eowarn
@translators[ type_name( type ) ] = block
end
# Translate the given string value to a value of the given type. In the
# absence of an installed translator block for the given type, the value
# itself is always returned. Further, +nil+ values are never translated,
# and are always passed straight through regardless of the type parameter.
def translate( type, value )
unless value.nil?
# FIXME: this is a hack to support Sequel
if type && %w{ datetime timestamp }.include?(type.downcase)
@translators[ type_name( type ) ].call( type, value.to_s )
else
@translators[ type_name( type ) ].call( type, value )
end
end
end
# A convenience method for working with type names. This returns the "base"
# type name, without any parenthetical data.
def type_name( type )
@type_name_cache[type] ||= begin
type = "" if type.nil?
type = $1 if type =~ /^(.*?)\(/
type.upcase
end
end
private :type_name
# Register the default translators for the current Translator instance.
# This includes translators for most major SQL data types.
def register_default_translators
[ "time",
"timestamp" ].each { |type| add_translator( type ) { |t, v| Time.parse( v ) } }
add_translator( "date" ) { |t,v| Date.parse(v) }
add_translator( "datetime" ) { |t,v| DateTime.parse(v) }
[ "decimal",
"float",
"numeric",
"double",
"real",
"dec",
"fixed" ].each { |type| add_translator( type ) { |t,v| v.to_f } }
[ "integer",
"smallint",
"mediumint",
"int",
"bigint" ].each { |type| add_translator( type ) { |t,v| v.to_i } }
[ "bit",
"bool",
"boolean" ].each do |type|
add_translator( type ) do |t,v|
!( v.strip.gsub(/00+/,"0") == "0" ||
v.downcase == "false" ||
v.downcase == "f" ||
v.downcase == "no" ||
v.downcase == "n" )
end
end
add_translator( "tinyint" ) do |type, value|
if type =~ /\(\s*1\s*\)/
value.to_i == 1
else
value.to_i
end
end
end
private :register_default_translators
end
end
sqlite3-1.7.3/lib/sqlite3/version.rb 0000644 0000041 0000041 00000000672 14620135377 017317 0 ustar www-data www-data module SQLite3
VERSION = "1.7.3"
module VersionProxy
MAJOR = 1
MINOR = 7
TINY = 3
BUILD = nil
STRING = [ MAJOR, MINOR, TINY, BUILD ].compact.join( "." )
VERSION = ::SQLite3::VERSION
end
def self.const_missing(name)
return super unless name == :Version
warn(<<-eowarn) if $VERBOSE
#{caller[0]}: `SQLite::Version` will be removed in sqlite3-ruby version 2.0.0
eowarn
VersionProxy
end
end
sqlite3-1.7.3/lib/sqlite3/resultset.rb 0000644 0000041 0000041 00000012716 14620135377 017666 0 ustar www-data www-data require 'sqlite3/constants'
require 'sqlite3/errors'
module SQLite3
# The ResultSet object encapsulates the enumerability of a query's output.
# It is a simple cursor over the data that the query returns. It will
# very rarely (if ever) be instantiated directly. Instead, clients should
# obtain a ResultSet instance via Statement#execute.
class ResultSet
include Enumerable
class ArrayWithTypes < Array # :nodoc:
attr_accessor :types
end
class ArrayWithTypesAndFields < Array # :nodoc:
attr_writer :types
attr_writer :fields
def types
warn(<<-eowarn) if $VERBOSE
#{caller[0]} is calling `#{self.class}#types` which is deprecated and will be removed in sqlite3 version 2.0.0. Please call the `types` method on the SQLite3::ResultSet object that created this object.
eowarn
@types
end
def fields
warn(<<-eowarn) if $VERBOSE
#{caller[0]} is calling `#{self.class}#fields` which is deprecated and will be removed in sqlite3 version 2.0.0. Please call the `columns` method on the SQLite3::ResultSet object that created this object.
eowarn
@fields
end
end
# The class of which we return an object in case we want a Hash as
# result.
class HashWithTypesAndFields < Hash # :nodoc:
attr_writer :types
attr_writer :fields
def types
warn(<<-eowarn) if $VERBOSE
#{caller[0]} is calling `#{self.class}#types` which is deprecated and will be removed in sqlite3 version 2.0.0. Please call the `types` method on the SQLite3::ResultSet object that created this object.
eowarn
@types
end
def fields
warn(<<-eowarn) if $VERBOSE
#{caller[0]} is calling `#{self.class}#fields` which is deprecated and will be removed in sqlite3 version 2.0.0. Please call the `columns` method on the SQLite3::ResultSet object that created this object.
eowarn
@fields
end
def [] key
key = fields[key] if key.is_a? Numeric
super key
end
end
# Create a new ResultSet attached to the given database, using the
# given sql text.
def initialize db, stmt
@db = db
@stmt = stmt
end
# Reset the cursor, so that a result set which has reached end-of-file
# can be rewound and reiterated.
def reset( *bind_params )
@stmt.reset!
@stmt.bind_params( *bind_params )
@eof = false
end
# Query whether the cursor has reached the end of the result set or not.
def eof?
@stmt.done?
end
# Obtain the next row from the cursor. If there are no more rows to be
# had, this will return +nil+. If type translation is active on the
# corresponding database, the values in the row will be translated
# according to their types.
#
# The returned value will be an array, unless Database#results_as_hash has
# been set to +true+, in which case the returned value will be a hash.
#
# For arrays, the column names are accessible via the +fields+ property,
# and the column types are accessible via the +types+ property.
#
# For hashes, the column names are the keys of the hash, and the column
# types are accessible via the +types+ property.
def next
if @db.results_as_hash
return next_hash
end
row = @stmt.step
return nil if @stmt.done?
row = @db.translate_from_db @stmt.types, row
if row.respond_to?(:fields)
# FIXME: this can only happen if the translator returns something
# that responds to `fields`. Since we're removing the translator
# in 2.0, we can remove this branch in 2.0.
row = ArrayWithTypes.new(row)
else
# FIXME: the `fields` and `types` methods are deprecated on this
# object for version 2.0, so we can safely remove this branch
# as well.
row = ArrayWithTypesAndFields.new(row)
end
row.fields = @stmt.columns
row.types = @stmt.types
row
end
# Required by the Enumerable mixin. Provides an internal iterator over the
# rows of the result set.
def each
while node = self.next
yield node
end
end
# Provides an internal iterator over the rows of the result set where
# each row is yielded as a hash.
def each_hash
while node = next_hash
yield node
end
end
# Closes the statement that spawned this result set.
# Use with caution! Closing a result set will automatically
# close any other result sets that were spawned from the same statement.
def close
@stmt.close
end
# Queries whether the underlying statement has been closed or not.
def closed?
@stmt.closed?
end
# Returns the types of the columns returned by this result set.
def types
@stmt.types
end
# Returns the names of the columns returned by this result set.
def columns
@stmt.columns
end
# Return the next row as a hash
def next_hash
row = @stmt.step
return nil if @stmt.done?
# FIXME: type translation is deprecated, so this can be removed
# in 2.0
row = @db.translate_from_db @stmt.types, row
# FIXME: this can be switched to a regular hash in 2.0
row = HashWithTypesAndFields[*@stmt.columns.zip(row).flatten]
# FIXME: these methods are deprecated for version 2.0, so we can remove
# this code in 2.0
row.fields = @stmt.columns
row.types = @stmt.types
row
end
end
end
sqlite3-1.7.3/lib/sqlite3/constants.rb 0000644 0000041 0000041 00000003354 14620135377 017646 0 ustar www-data www-data module SQLite3 ; module Constants
module TextRep
UTF8 = 1
UTF16LE = 2
UTF16BE = 3
UTF16 = 4
ANY = 5
DETERMINISTIC = 0x800
end
module ColumnType
INTEGER = 1
FLOAT = 2
TEXT = 3
BLOB = 4
NULL = 5
end
module ErrorCode
OK = 0 # Successful result
ERROR = 1 # SQL error or missing database
INTERNAL = 2 # An internal logic error in SQLite
PERM = 3 # Access permission denied
ABORT = 4 # Callback routine requested an abort
BUSY = 5 # The database file is locked
LOCKED = 6 # A table in the database is locked
NOMEM = 7 # A malloc() failed
READONLY = 8 # Attempt to write a readonly database
INTERRUPT = 9 # Operation terminated by sqlite_interrupt()
IOERR = 10 # Some kind of disk I/O error occurred
CORRUPT = 11 # The database disk image is malformed
NOTFOUND = 12 # (Internal Only) Table or record not found
FULL = 13 # Insertion failed because database is full
CANTOPEN = 14 # Unable to open the database file
PROTOCOL = 15 # Database lock protocol error
EMPTY = 16 # (Internal Only) Database table is empty
SCHEMA = 17 # The database schema changed
TOOBIG = 18 # Too much data for one row of a table
CONSTRAINT = 19 # Abort due to constraint violation
MISMATCH = 20 # Data type mismatch
MISUSE = 21 # Library used incorrectly
NOLFS = 22 # Uses OS features not supported on host
AUTH = 23 # Authorization denied
ROW = 100 # sqlite_step() has another row ready
DONE = 101 # sqlite_step() has finished executing
end
end ; end
sqlite3-1.7.3/lib/sqlite3/errors.rb 0000644 0000041 0000041 00000002403 14620135377 017140 0 ustar www-data www-data require 'sqlite3/constants'
module SQLite3
class Exception < ::StandardError
# A convenience for accessing the error code for this exception.
attr_reader :code
end
class SQLException < Exception; end
class InternalException < Exception; end
class PermissionException < Exception; end
class AbortException < Exception; end
class BusyException < Exception; end
class LockedException < Exception; end
class MemoryException < Exception; end
class ReadOnlyException < Exception; end
class InterruptException < Exception; end
class IOException < Exception; end
class CorruptException < Exception; end
class NotFoundException < Exception; end
class FullException < Exception; end
class CantOpenException < Exception; end
class ProtocolException < Exception; end
class EmptyException < Exception; end
class SchemaChangedException < Exception; end
class TooBigException < Exception; end
class ConstraintException < Exception; end
class MismatchException < Exception; end
class MisuseException < Exception; end
class UnsupportedException < Exception; end
class AuthorizationException < Exception; end
class FormatException < Exception; end
class RangeException < Exception; end
class NotADatabaseException < Exception; end
end
sqlite3-1.7.3/lib/sqlite3/value.rb 0000644 0000041 0000041 00000002041 14620135377 016736 0 ustar www-data www-data require 'sqlite3/constants'
module SQLite3
class Value
attr_reader :handle
def initialize( db, handle )
@driver = db.driver
@handle = handle
end
def null?
type == :null
end
def to_blob
@driver.value_blob( @handle )
end
def length( utf16=false )
if utf16
@driver.value_bytes16( @handle )
else
@driver.value_bytes( @handle )
end
end
def to_f
@driver.value_double( @handle )
end
def to_i
@driver.value_int( @handle )
end
def to_int64
@driver.value_int64( @handle )
end
def to_s( utf16=false )
@driver.value_text( @handle, utf16 )
end
def type
case @driver.value_type( @handle )
when Constants::ColumnType::INTEGER then :int
when Constants::ColumnType::FLOAT then :float
when Constants::ColumnType::TEXT then :text
when Constants::ColumnType::BLOB then :blob
when Constants::ColumnType::NULL then :null
end
end
end
end
sqlite3-1.7.3/lib/sqlite3.rb 0000644 0000041 0000041 00000000551 14620135377 015626 0 ustar www-data www-data # support multiple ruby version (fat binaries under windows)
begin
RUBY_VERSION =~ /(\d+\.\d+)/
require "sqlite3/#{$1}/sqlite3_native"
rescue LoadError
require 'sqlite3/sqlite3_native'
end
require 'sqlite3/database'
require 'sqlite3/version'
module SQLite3
# Was sqlite3 compiled with thread safety on?
def self.threadsafe?; threadsafe > 0; end
end
sqlite3-1.7.3/test/ 0000755 0000041 0000041 00000000000 14620135377 014125 5 ustar www-data www-data sqlite3-1.7.3/test/test_integration_open_close.rb 0000644 0000041 0000041 00000001313 14620135377 022240 0 ustar www-data www-data require 'helper'
class TC_OpenClose < SQLite3::TestCase
def test_create_close
begin
db = SQLite3::Database.new( "test-create.db" )
assert File.exist?( "test-create.db" )
assert_nothing_raised { db.close }
ensure
File.delete( "test-create.db" ) rescue nil
end
end
def test_open_close
begin
File.open( "test-open.db", "w" ) { |f| }
assert File.exist?( "test-open.db" )
db = SQLite3::Database.new( "test-open.db" )
assert_nothing_raised { db.close }
ensure
File.delete( "test-open.db" ) rescue nil
end
end
def test_bad_open
assert_raise( SQLite3::CantOpenException ) do
SQLite3::Database.new( "." )
end
end
end
sqlite3-1.7.3/test/test_integration_pending.rb 0000644 0000041 0000041 00000004357 14620135377 021551 0 ustar www-data www-data require 'helper'
require 'thread'
require 'benchmark'
class TC_Integration_Pending < SQLite3::TestCase
def setup
@db = SQLite3::Database.new("test.db")
@db.transaction do
@db.execute "create table foo ( a integer primary key, b text )"
@db.execute "insert into foo ( b ) values ( 'foo' )"
@db.execute "insert into foo ( b ) values ( 'bar' )"
@db.execute "insert into foo ( b ) values ( 'baz' )"
end
end
def teardown
@db.close
File.delete( "test.db" )
end
def test_busy_handler_outwait
skip("not working in 1.9") if RUBY_VERSION >= '1.9'
busy = Mutex.new
busy.lock
handler_call_count = 0
t = Thread.new(busy) do |locker|
begin
db2 = SQLite3::Database.open( "test.db" )
db2.transaction( :exclusive ) do
locker.lock
end
ensure
db2.close if db2
end
end
@db.busy_handler do |data,count|
handler_call_count += 1
busy.unlock
true
end
assert_nothing_raised do
@db.execute "insert into foo (b) values ( 'from 2' )"
end
t.join
assert_equal 1, handler_call_count
end
def test_busy_handler_impatient
busy = Mutex.new
busy.lock
handler_call_count = 0
t = Thread.new do
begin
db2 = SQLite3::Database.open( "test.db" )
db2.transaction( :exclusive ) do
busy.lock
end
ensure
db2.close if db2
end
end
sleep 1
@db.busy_handler do
handler_call_count += 1
false
end
assert_raise( SQLite3::BusyException ) do
@db.execute "insert into foo (b) values ( 'from 2' )"
end
busy.unlock
t.join
assert_equal 1, handler_call_count
end
def test_busy_timeout
@db.busy_timeout 1000
busy = Mutex.new
busy.lock
t = Thread.new do
begin
db2 = SQLite3::Database.open( "test.db" )
db2.transaction( :exclusive ) do
busy.lock
end
ensure
db2.close if db2
end
end
sleep 1
time = Benchmark.measure do
assert_raise( SQLite3::BusyException ) do
@db.execute "insert into foo (b) values ( 'from 2' )"
end
end
busy.unlock
t.join
assert time.real*1000 >= 1000
end
end
sqlite3-1.7.3/test/test_pragmas.rb 0000644 0000041 0000041 00000000733 14620135377 017146 0 ustar www-data www-data require 'helper'
module SQLite3
class TestPragmas < SQLite3::TestCase
def setup
super
@db = SQLite3::Database.new(":memory:")
end
def test_get_boolean_pragma
refute(@db.get_boolean_pragma("read_uncommitted"))
end
def test_set_boolean_pragma
@db.set_boolean_pragma("read_uncommitted", 1)
assert(@db.get_boolean_pragma("read_uncommitted"))
ensure
@db.set_boolean_pragma("read_uncommitted", 0)
end
end
end
sqlite3-1.7.3/test/test_statement_execute.rb 0000644 0000041 0000041 00000002113 14620135377 021234 0 ustar www-data www-data require 'helper'
module SQLite3
class TestStatementExecute < SQLite3::TestCase
def setup
@db = SQLite3::Database.new(':memory:')
@db.execute_batch(
"CREATE TABLE items (id integer PRIMARY KEY, number integer)")
end
def teardown
@db.close
end
def test_execute_insert
ps = @db.prepare("INSERT INTO items (number) VALUES (:n)")
ps.execute('n'=>10)
assert_equal 1, @db.get_first_value("SELECT count(*) FROM items")
ps.close
end
def test_execute_update
@db.execute("INSERT INTO items (number) VALUES (?)", [10])
ps = @db.prepare("UPDATE items SET number = :new WHERE number = :old")
ps.execute('old'=>10, 'new'=>20)
assert_equal 20, @db.get_first_value("SELECT number FROM items")
ps.close
end
def test_execute_delete
@db.execute("INSERT INTO items (number) VALUES (?)", [20])
ps = @db.prepare("DELETE FROM items WHERE number = :n")
ps.execute('n' => 20)
assert_equal 0, @db.get_first_value("SELECT count(*) FROM items")
ps.close
end
end
end
sqlite3-1.7.3/test/test_database_flags.rb 0000644 0000041 0000041 00000006657 14620135377 020447 0 ustar www-data www-data require 'helper'
module SQLite3
class TestDatabaseFlags < SQLite3::TestCase
def setup
File.unlink 'test-flags.db' if File.exist?('test-flags.db')
@db = SQLite3::Database.new('test-flags.db')
@db.execute("CREATE TABLE foos (id integer)")
@db.close
end
def teardown
@db.close unless @db.closed?
File.unlink 'test-flags.db' if File.exist?('test-flags.db')
end
def test_open_database_flags_constants
defined_to_date = [:READONLY, :READWRITE, :CREATE, :DELETEONCLOSE,
:EXCLUSIVE, :MAIN_DB, :TEMP_DB, :TRANSIENT_DB,
:MAIN_JOURNAL, :TEMP_JOURNAL, :SUBJOURNAL,
:MASTER_JOURNAL, :NOMUTEX, :FULLMUTEX]
if SQLite3::SQLITE_VERSION_NUMBER > 3007002
defined_to_date += [:AUTOPROXY, :SHAREDCACHE, :PRIVATECACHE, :WAL]
end
if SQLite3::SQLITE_VERSION_NUMBER > 3007007
defined_to_date += [:URI]
end
if SQLite3::SQLITE_VERSION_NUMBER > 3007013
defined_to_date += [:MEMORY]
end
assert defined_to_date.sort == SQLite3::Constants::Open.constants.sort
end
def test_open_database_flags_conflicts_with_readonly
assert_raise(RuntimeError) do
@db = SQLite3::Database.new('test-flags.db', :flags => 2, :readonly => true)
end
end
def test_open_database_flags_conflicts_with_readwrite
assert_raise(RuntimeError) do
@db = SQLite3::Database.new('test-flags.db', :flags => 2, :readwrite => true)
end
end
def test_open_database_readonly_flags
@db = SQLite3::Database.new('test-flags.db', :flags => SQLite3::Constants::Open::READONLY)
assert @db.readonly?
end
def test_open_database_readwrite_flags
@db = SQLite3::Database.new('test-flags.db', :flags => SQLite3::Constants::Open::READWRITE)
assert !@db.readonly?
end
def test_open_database_readonly_flags_cant_open
File.unlink 'test-flags.db'
assert_raise(SQLite3::CantOpenException) do
@db = SQLite3::Database.new('test-flags.db', :flags => SQLite3::Constants::Open::READONLY)
end
end
def test_open_database_readwrite_flags_cant_open
File.unlink 'test-flags.db'
assert_raise(SQLite3::CantOpenException) do
@db = SQLite3::Database.new('test-flags.db', :flags => SQLite3::Constants::Open::READWRITE)
end
end
def test_open_database_misuse_flags
assert_raise(SQLite3::MisuseException) do
flags = SQLite3::Constants::Open::READONLY | SQLite3::Constants::Open::READWRITE # <== incompatible flags
@db = SQLite3::Database.new('test-flags.db', :flags => flags)
end
end
def test_open_database_create_flags
File.unlink 'test-flags.db'
flags = SQLite3::Constants::Open::READWRITE | SQLite3::Constants::Open::CREATE
@db = SQLite3::Database.new('test-flags.db', :flags => flags) do |db|
db.execute("CREATE TABLE foos (id integer)")
db.execute("INSERT INTO foos (id) VALUES (12)")
end
assert File.exist?('test-flags.db')
end
def test_open_database_exotic_flags
flags = SQLite3::Constants::Open::READWRITE | SQLite3::Constants::Open::CREATE
exotic_flags = SQLite3::Constants::Open::NOMUTEX | SQLite3::Constants::Open::TEMP_DB
@db = SQLite3::Database.new('test-flags.db', :flags => flags | exotic_flags)
@db.execute("INSERT INTO foos (id) VALUES (12)")
assert @db.changes == 1
end
end
end
sqlite3-1.7.3/test/test_integration.rb 0000644 0000041 0000041 00000033551 14620135377 020043 0 ustar www-data www-data require 'helper'
class TC_Database_Integration < SQLite3::TestCase
def setup
@db = SQLite3::Database.new(":memory:")
@db.transaction do
@db.execute "create table foo ( a integer primary key, b text )"
@db.execute "insert into foo ( b ) values ( 'foo' )"
@db.execute "insert into foo ( b ) values ( 'bar' )"
@db.execute "insert into foo ( b ) values ( 'baz' )"
end
end
def teardown
@db.close
end
def test_table_info_with_type_translation_active
assert_nothing_raised { @db.table_info("foo") }
end
def test_table_info_with_defaults_for_version_3_3_8_and_higher
@db.transaction do
@db.execute "create table defaults_test ( a string default NULL, b string default 'Hello', c string default '--- []\n' )"
data = @db.table_info( "defaults_test" )
assert_equal({"name" => "a", "type" => "string", "dflt_value" => nil, "notnull" => 0, "cid" => 0, "pk" => 0},
data[0])
assert_equal({"name" => "b", "type" => "string", "dflt_value" => "Hello", "notnull" => 0, "cid" => 1, "pk" => 0},
data[1])
assert_equal({"name" => "c", "type" => "string", "dflt_value" => "--- []\n", "notnull" => 0, "cid" => 2, "pk" => 0},
data[2])
end
end
def test_table_info_without_defaults_for_version_3_3_8_and_higher
@db.transaction do
@db.execute "create table no_defaults_test ( a integer default 1, b integer )"
data = @db.table_info( "no_defaults_test" )
assert_equal({"name" => "a", "type" => "integer", "dflt_value" => "1", "notnull" => 0, "cid" => 0, "pk" => 0},
data[0])
assert_equal({"name" => "b", "type" => "integer", "dflt_value" => nil, "notnull" => 0, "cid" => 1, "pk" => 0},
data[1])
end
end
def test_complete_fail
assert !@db.complete?( "select * from foo" )
end
def test_complete_success
assert @db.complete?( "select * from foo;" )
end
# FIXME: do people really need UTF16 sql statements?
#def test_complete_fail_utf16
# assert !@db.complete?( "select * from foo".to_utf16(false), true )
#end
# FIXME: do people really need UTF16 sql statements?
#def test_complete_success_utf16
# assert @db.complete?( "select * from foo;".to_utf16(true), true )
#end
def test_errmsg
assert_equal "not an error", @db.errmsg
end
# FIXME: do people really need UTF16 error messages?
#def test_errmsg_utf16
# msg = Iconv.conv('UTF-16', 'UTF-8', 'not an error')
# assert_equal msg, @db.errmsg(true)
#end
def test_errcode
assert_equal 0, @db.errcode
end
def test_trace
result = nil
@db.trace { |sql| result = sql }
@db.execute "select * from foo"
assert_equal "select * from foo", result
end
def test_authorizer_okay
@db.authorizer { |type,a,b,c,d| 0 }
rows = @db.execute "select * from foo"
assert_equal 3, rows.length
end
def test_authorizer_error
@db.authorizer { |type,a,b,c,d| 1 }
assert_raise( SQLite3::AuthorizationException ) do
@db.execute "select * from foo"
end
end
def test_authorizer_silent
@db.authorizer { |type,a,b,c,d| 2 }
rows = @db.execute "select * from foo"
assert rows.empty?
end
def test_prepare_invalid_syntax
assert_raise( SQLite3::SQLException ) do
@db.prepare "select from foo"
end
end
def test_prepare_invalid_column
assert_raise( SQLite3::SQLException ) do
@db.prepare "select k from foo"
end
end
def test_prepare_invalid_table
assert_raise( SQLite3::SQLException ) do
@db.prepare "select * from barf"
end
end
def test_prepare_no_block
stmt = @db.prepare "select * from foo"
assert stmt.respond_to?(:execute)
stmt.close
end
def test_prepare_with_block
called = false
@db.prepare "select * from foo" do |stmt|
called = true
assert stmt.respond_to?(:execute)
end
assert called
end
def test_execute_no_block_no_bind_no_match
rows = @db.execute( "select * from foo where a > 100" )
assert rows.empty?
end
def test_execute_with_block_no_bind_no_match
called = false
@db.execute( "select * from foo where a > 100" ) do |row|
called = true
end
assert !called
end
def test_execute_no_block_with_bind_no_match
rows = @db.execute( "select * from foo where a > ?", 100 )
assert rows.empty?
end
def test_execute_with_block_with_bind_no_match
called = false
@db.execute( "select * from foo where a > ?", 100 ) do |row|
called = true
end
assert !called
end
def test_execute_no_block_no_bind_with_match
rows = @db.execute( "select * from foo where a = 1" )
assert_equal 1, rows.length
end
def test_execute_with_block_no_bind_with_match
called = 0
@db.execute( "select * from foo where a = 1" ) do |row|
called += 1
end
assert_equal 1, called
end
def test_execute_no_block_with_bind_with_match
rows = @db.execute( "select * from foo where a = ?", 1 )
assert_equal 1, rows.length
end
def test_execute_with_block_with_bind_with_match
called = 0
@db.execute( "select * from foo where a = ?", 1 ) do |row|
called += 1
end
assert_equal 1, called
end
def test_execute2_no_block_no_bind_no_match
columns, *rows = @db.execute2( "select * from foo where a > 100" )
assert rows.empty?
assert_equal [ "a", "b" ], columns
end
def test_execute2_with_block_no_bind_no_match
called = 0
@db.execute2( "select * from foo where a > 100" ) do |row|
assert [ "a", "b" ], row unless called == 0
called += 1
end
assert_equal 1, called
end
def test_execute2_no_block_with_bind_no_match
columns, *rows = @db.execute2( "select * from foo where a > ?", 100 )
assert rows.empty?
assert_equal [ "a", "b" ], columns
end
def test_execute2_with_block_with_bind_no_match
called = 0
@db.execute2( "select * from foo where a > ?", 100 ) do |row|
assert_equal [ "a", "b" ], row unless called == 0
called += 1
end
assert_equal 1, called
end
def test_execute2_no_block_no_bind_with_match
columns, *rows = @db.execute2( "select * from foo where a = 1" )
assert_equal 1, rows.length
assert_equal [ "a", "b" ], columns
end
def test_execute2_with_block_no_bind_with_match
called = 0
@db.execute2( "select * from foo where a = 1" ) do |row|
assert_equal [ 1, "foo" ], row unless called == 0
called += 1
end
assert_equal 2, called
end
def test_execute2_no_block_with_bind_with_match
columns, *rows = @db.execute2( "select * from foo where a = ?", 1 )
assert_equal 1, rows.length
assert_equal [ "a", "b" ], columns
end
def test_execute2_with_block_with_bind_with_match
called = 0
@db.execute2( "select * from foo where a = ?", 1 ) do
called += 1
end
assert_equal 2, called
end
def test_execute_batch_empty
assert_nothing_raised { @db.execute_batch "" }
end
def test_execute_batch_no_bind
@db.transaction do
@db.execute_batch <<-SQL
create table bar ( a, b, c );
insert into bar values ( 'one', 2, 'three' );
insert into bar values ( 'four', 5, 'six' );
insert into bar values ( 'seven', 8, 'nine' );
SQL
end
rows = @db.execute( "select * from bar" )
assert_equal 3, rows.length
end
def test_execute_batch_with_bind
@db.execute_batch( <<-SQL, [1] )
create table bar ( a, b, c );
insert into bar values ( 'one', 2, ? );
insert into bar values ( 'four', 5, ? );
insert into bar values ( 'seven', 8, ? );
SQL
rows = @db.execute( "select * from bar" ).map { |a,b,c| c }
assert_equal [1, 1, 1], rows
end
def test_query_no_block_no_bind_no_match
result = @db.query( "select * from foo where a > 100" )
assert_nil result.next
result.close
end
def test_query_with_block_no_bind_no_match
r = nil
@db.query( "select * from foo where a > 100" ) do |result|
assert_nil result.next
r = result
end
assert r.closed?
end
def test_query_no_block_with_bind_no_match
result = @db.query( "select * from foo where a > ?", 100 )
assert_nil result.next
result.close
end
def test_query_with_block_with_bind_no_match
r = nil
@db.query( "select * from foo where a > ?", 100 ) do |result|
assert_nil result.next
r = result
end
assert r.closed?
end
def test_query_no_block_no_bind_with_match
result = @db.query( "select * from foo where a = 1" )
assert_not_nil result.next
assert_nil result.next
result.close
end
def test_query_with_block_no_bind_with_match
r = nil
@db.query( "select * from foo where a = 1" ) do |result|
assert_not_nil result.next
assert_nil result.next
r = result
end
assert r.closed?
end
def test_query_no_block_with_bind_with_match
result = @db.query( "select * from foo where a = ?", 1 )
assert_not_nil result.next
assert_nil result.next
result.close
end
def test_query_with_block_with_bind_with_match
r = nil
@db.query( "select * from foo where a = ?", 1 ) do |result|
assert_not_nil result.next
assert_nil result.next
r = result
end
assert r.closed?
end
def test_get_first_row_no_bind_no_match
result = @db.get_first_row( "select * from foo where a=100" )
assert_nil result
end
def test_get_first_row_no_bind_with_match
result = @db.get_first_row( "select * from foo where a=1" )
assert_equal [ 1, "foo" ], result
end
def test_get_first_row_with_bind_no_match
result = @db.get_first_row( "select * from foo where a=?", 100 )
assert_nil result
end
def test_get_first_row_with_bind_with_match
result = @db.get_first_row( "select * from foo where a=?", 1 )
assert_equal [ 1, "foo" ], result
end
def test_get_first_value_no_bind_no_match
result = @db.get_first_value( "select b, a from foo where a=100" )
assert_nil result
@db.results_as_hash = true
result = @db.get_first_value( "select b, a from foo where a=100" )
assert_nil result
end
def test_get_first_value_no_bind_with_match
result = @db.get_first_value( "select b, a from foo where a=1" )
assert_equal "foo", result
@db.results_as_hash = true
result = @db.get_first_value( "select b, a from foo where a=1" )
assert_equal "foo", result
end
def test_get_first_value_with_bind_no_match
result = @db.get_first_value( "select b, a from foo where a=?", 100 )
assert_nil result
@db.results_as_hash = true
result = @db.get_first_value( "select b, a from foo where a=?", 100 )
assert_nil result
end
def test_get_first_value_with_bind_with_match
result = @db.get_first_value( "select b, a from foo where a=?", 1 )
assert_equal "foo", result
@db.results_as_hash = true
result = @db.get_first_value( "select b, a from foo where a=?", 1 )
assert_equal "foo", result
end
def test_last_insert_row_id
@db.execute "insert into foo ( b ) values ( 'test' )"
assert_equal 4, @db.last_insert_row_id
@db.execute "insert into foo ( b ) values ( 'again' )"
assert_equal 5, @db.last_insert_row_id
end
def test_changes
@db.execute "insert into foo ( b ) values ( 'test' )"
assert_equal 1, @db.changes
@db.execute "delete from foo where 1=1"
assert_equal 4, @db.changes
end
def test_total_changes
assert_equal 3, @db.total_changes
@db.execute "insert into foo ( b ) values ( 'test' )"
@db.execute "delete from foo where 1=1"
assert_equal 8, @db.total_changes
end
def test_transaction_nest
assert_raise( SQLite3::SQLException ) do
@db.transaction do
@db.transaction do
end
end
end
end
def test_transaction_rollback
@db.transaction
@db.execute_batch <<-SQL
insert into foo (b) values ( 'test1' );
insert into foo (b) values ( 'test2' );
insert into foo (b) values ( 'test3' );
insert into foo (b) values ( 'test4' );
SQL
assert_equal 7, @db.get_first_value("select count(*) from foo").to_i
@db.rollback
assert_equal 3, @db.get_first_value("select count(*) from foo").to_i
end
def test_transaction_commit
@db.transaction
@db.execute_batch <<-SQL
insert into foo (b) values ( 'test1' );
insert into foo (b) values ( 'test2' );
insert into foo (b) values ( 'test3' );
insert into foo (b) values ( 'test4' );
SQL
assert_equal 7, @db.get_first_value("select count(*) from foo").to_i
@db.commit
assert_equal 7, @db.get_first_value("select count(*) from foo").to_i
end
def test_transaction_rollback_in_block
assert_raise( SQLite3::SQLException ) do
@db.transaction do
@db.rollback
end
end
end
def test_transaction_commit_in_block
assert_raise( SQLite3::SQLException ) do
@db.transaction do
@db.commit
end
end
end
def test_transaction_active
assert !@db.transaction_active?
@db.transaction
assert @db.transaction_active?
@db.commit
assert !@db.transaction_active?
end
def test_transaction_implicit_rollback
assert !@db.transaction_active?
@db.transaction
@db.execute('create table bar (x CHECK(1 = 0))')
assert @db.transaction_active?
assert_raises( SQLite3::ConstraintException ) do
@db.execute("insert or rollback into bar (x) VALUES ('x')")
end
assert !@db.transaction_active?
end
def test_interrupt
@db.create_function( "abort", 1 ) do |func,x|
@db.interrupt
func.result = x
end
assert_raise( SQLite3::InterruptException ) do
@db.execute "select abort(a) from foo"
end
end
def test_create_function
@db.create_function( "munge", 1 ) do |func,x|
func.result = ">>>#{x}<<<"
end
value = @db.get_first_value( "select munge(b) from foo where a=1" )
assert_match( />>>.*<<, value )
end
def test_bind_array_parameter
result = @db.get_first_value( "select b from foo where a=? and b=?",
[ 1, "foo" ] )
assert_equal "foo", result
end
end
sqlite3-1.7.3/test/test_collation.rb 0000644 0000041 0000041 00000004106 14620135377 017476 0 ustar www-data www-data # -*- coding: utf-8 -*-
require 'helper'
module SQLite3
class TestCollation < SQLite3::TestCase
class Comparator
attr_reader :calls
def initialize
@calls = []
end
def compare left, right
@calls << [left, right]
left <=> right
end
end
def setup
@db = SQLite3::Database.new(':memory:')
@create = "create table ex(id int, data string)"
@db.execute(@create);
[ [1, 'hello'], [2, 'world'] ].each do |vals|
@db.execute('insert into ex (id, data) VALUES (?, ?)', vals)
end
end
def test_custom_collation
comparator = Comparator.new
@db.collation 'foo', comparator
assert_equal comparator, @db.collations['foo']
@db.execute('select data from ex order by 1 collate foo')
assert_equal 1, comparator.calls.length
end
def test_remove_collation
comparator = Comparator.new
@db.collation 'foo', comparator
@db.collation 'foo', nil
assert_nil @db.collations['foo']
assert_raises(SQLite3::SQLException) do
@db.execute('select data from ex order by 1 collate foo')
end
end
if RUBY_VERSION >= '1.9.1'
def test_encoding
comparator = Comparator.new
@db.collation 'foo', comparator
@db.execute('select data from ex order by 1 collate foo')
a, b = *comparator.calls.first
assert_equal Encoding.find('UTF-8'), a.encoding
assert_equal Encoding.find('UTF-8'), b.encoding
end
def test_encoding_default_internal
warn_before = $-w
$-w = false
before_enc = Encoding.default_internal
Encoding.default_internal = 'EUC-JP'
comparator = Comparator.new
@db.collation 'foo', comparator
@db.execute('select data from ex order by 1 collate foo')
a, b = *comparator.calls.first
assert_equal Encoding.find('EUC-JP'), a.encoding
assert_equal Encoding.find('EUC-JP'), b.encoding
ensure
Encoding.default_internal = before_enc
$-w = warn_before
end
end
end
end
sqlite3-1.7.3/test/test_backup.rb 0000644 0000041 0000041 00000002036 14620135377 016757 0 ustar www-data www-data require 'helper'
module SQLite3
class TestBackup < SQLite3::TestCase
def setup
@sdb = SQLite3::Database.new(':memory:')
@ddb = SQLite3::Database.new(':memory:')
@sdb.execute('CREATE TABLE foo (idx, val);');
@data = ('A'..'Z').map{|x|x * 40}
@data.each_with_index do |v, i|
@sdb.execute('INSERT INTO foo (idx, val) VALUES (?, ?);', [i, v])
end
end
def test_backup_step
b = SQLite3::Backup.new(@ddb, 'main', @sdb, 'main')
while b.step(1) == SQLite3::Constants::ErrorCode::OK
assert_not_equal(0, b.remaining)
end
assert_equal(0, b.remaining)
b.finish
assert_equal(@data.length, @ddb.execute('SELECT * FROM foo;').length)
end
def test_backup_all
b = SQLite3::Backup.new(@ddb, 'main', @sdb, 'main')
assert_equal(SQLite3::Constants::ErrorCode::DONE, b.step(-1))
assert_equal(0, b.remaining)
b.finish
assert_equal(@data.length, @ddb.execute('SELECT * FROM foo;').length)
end
end if defined?(SQLite3::Backup)
end
sqlite3-1.7.3/test/test_sqlite3.rb 0000644 0000041 0000041 00000001312 14620135377 017072 0 ustar www-data www-data require 'helper'
module SQLite3
class TestSQLite3 < SQLite3::TestCase
def test_libversion
assert_not_nil SQLite3.libversion
end
def test_threadsafe
assert_not_nil SQLite3.threadsafe
end
def test_threadsafe?
if SQLite3.threadsafe > 0
assert SQLite3.threadsafe?
else
refute SQLite3.threadsafe?
end
end
def test_version_strings
skip if SQLite3::VERSION.include?("test") # see set-version-to-timestamp rake task
assert_equal(SQLite3::VERSION, SQLite3::VersionProxy::STRING)
end
def test_compiled_version_and_loaded_version
assert_equal(SQLite3::SQLITE_VERSION, SQLite3::SQLITE_LOADED_VERSION)
end
end
end
sqlite3-1.7.3/test/helper.rb 0000644 0000041 0000041 00000001247 14620135377 015735 0 ustar www-data www-data require 'sqlite3'
require 'minitest/autorun'
if ENV['GITHUB_ACTIONS'] == 'true' || ENV['CI']
$VERBOSE = nil
end
puts "info: sqlite3-ruby version: #{SQLite3::VERSION}/#{SQLite3::VersionProxy::STRING}"
puts "info: sqlite3 version: #{SQLite3::SQLITE_VERSION}/#{SQLite3::SQLITE_LOADED_VERSION}"
puts "info: sqlcipher?: #{SQLite3.sqlcipher?}"
puts "info: threadsafe?: #{SQLite3.threadsafe?}"
unless RUBY_VERSION >= "1.9"
require 'iconv'
end
module SQLite3
class TestCase < Minitest::Test
alias :assert_not_equal :refute_equal
alias :assert_not_nil :refute_nil
alias :assert_raise :assert_raises
def assert_nothing_raised
yield
end
end
end
sqlite3-1.7.3/test/test_integration_aggregate.rb 0000644 0000041 0000041 00000020473 14620135377 022050 0 ustar www-data www-data require 'helper'
class TC_Integration_Aggregate < SQLite3::TestCase
def setup
@db = SQLite3::Database.new(":memory:")
@db.transaction do
@db.execute "create table foo ( a integer primary key, b text, c integer )"
@db.execute "insert into foo ( b, c ) values ( 'foo', 10 )"
@db.execute "insert into foo ( b, c ) values ( 'bar', 11 )"
@db.execute "insert into foo ( b, c ) values ( 'bar', 12 )"
end
end
def teardown
@db.close
end
def test_create_aggregate_without_block
step = proc do |ctx,a|
ctx[:sum] ||= 0
ctx[:sum] += a.to_i
end
final = proc { |ctx| ctx.result = ctx[:sum] }
@db.create_aggregate( "accumulate", 1, step, final )
value = @db.get_first_value( "select accumulate(a) from foo" )
assert_equal 6, value
# calling #get_first_value twice don't add up to the latest result
value = @db.get_first_value( "select accumulate(a) from foo" )
assert_equal 6, value
end
def test_create_aggregate_with_block
@db.create_aggregate( "accumulate", 1 ) do
step do |ctx,a|
ctx[:sum] ||= 0
ctx[:sum] += a.to_i
end
finalize { |ctx| ctx.result = ctx[:sum] }
end
value = @db.get_first_value( "select accumulate(a) from foo" )
assert_equal 6, value
end
def test_create_aggregate_with_group_by
@db.create_aggregate( "accumulate", 1 ) do
step do |ctx,a|
ctx[:sum] ||= 0
ctx[:sum] += a.to_i
end
finalize { |ctx| ctx.result = ctx[:sum] }
end
values = @db.execute( "select b, accumulate(c) from foo group by b order by b" )
assert_equal "bar", values[0][0]
assert_equal 23, values[0][1]
assert_equal "foo", values[1][0]
assert_equal 10, values[1][1]
end
def test_create_aggregate_with_the_same_function_twice_in_a_query
@db.create_aggregate( "accumulate", 1 ) do
step do |ctx,a|
ctx[:sum] ||= 0
ctx[:sum] += a.to_i
end
finalize { |ctx| ctx.result = ctx[:sum] }
end
values = @db.get_first_row( "select accumulate(a), accumulate(c) from foo" )
assert_equal 6, values[0]
assert_equal 33, values[1]
end
def test_create_aggregate_with_two_different_functions
@db.create_aggregate( "accumulate", 1 ) do
step do |ctx,a|
ctx[:sum] ||= 0
ctx[:sum] += a.to_i
end
finalize { |ctx| ctx.result = ctx[:sum] }
end
@db.create_aggregate( "multiply", 1 ) do
step do |ctx,a|
ctx[:sum] ||= 1
ctx[:sum] *= a.to_i
end
finalize { |ctx| ctx.result = ctx[:sum] }
end
GC.start
values = @db.get_first_row( "select accumulate(a), multiply(c) from foo" )
assert_equal 6, values[0]
assert_equal 1320, values[1]
value = @db.get_first_value( "select accumulate(c) from foo")
assert_equal 33, value
value = @db.get_first_value( "select multiply(a) from foo")
assert_equal 6, value
end
def test_create_aggregate_overwrite_function
@db.create_aggregate( "accumulate", 1 ) do
step do |ctx,a|
ctx[:sum] ||= 0
ctx[:sum] += a.to_i
end
finalize { |ctx| ctx.result = ctx[:sum] }
end
value = @db.get_first_value( "select accumulate(c) from foo")
assert_equal 33, value
GC.start
@db.create_aggregate( "accumulate", 1 ) do
step do |ctx,a|
ctx[:sum] ||= 1
ctx[:sum] *= a.to_i
end
finalize { |ctx| ctx.result = ctx[:sum] }
end
value = @db.get_first_value( "select accumulate(c) from foo")
assert_equal 1320, value
end
def test_create_aggregate_overwrite_function_with_different_arity
@db.create_aggregate( "accumulate", -1 ) do
step do |ctx,*args|
ctx[:sum] ||= 0
args.each { |a| ctx[:sum] += a.to_i }
end
finalize { |ctx| ctx.result = ctx[:sum] }
end
@db.create_aggregate( "accumulate", 2 ) do
step do |ctx,a,b|
ctx[:sum] ||= 1
ctx[:sum] *= (a.to_i + b.to_i)
end
finalize { |ctx| ctx.result = ctx[:sum] }
end
GC.start
values = @db.get_first_row( "select accumulate(c), accumulate(a,c) from foo")
assert_equal 33, values[0]
assert_equal 2145, values[1]
end
def test_create_aggregate_with_invalid_arity
assert_raise ArgumentError do
@db.create_aggregate( "accumulate", 1000 ) do
step {|ctx,*args| }
finalize { |ctx| }
end
end
end
class CustomException < Exception
end
def test_create_aggregate_with_exception_in_step
@db.create_aggregate( "raiseexception", 1 ) do
step do |ctx,a|
raise CustomException.new( "bogus aggregate handler" )
end
finalize { |ctx| ctx.result = 42 }
end
assert_raise CustomException do
@db.get_first_value( "select raiseexception(a) from foo")
end
end
def test_create_aggregate_with_exception_in_finalize
@db.create_aggregate( "raiseexception", 1 ) do
step do |ctx,a|
raise CustomException.new( "bogus aggregate handler" )
end
finalize do |ctx|
raise CustomException.new( "bogus aggregate handler" )
end
end
assert_raise CustomException do
@db.get_first_value( "select raiseexception(a) from foo")
end
end
def test_create_aggregate_with_no_data
@db.create_aggregate( "accumulate", 1 ) do
step do |ctx,a|
ctx[:sum] ||= 0
ctx[:sum] += a.to_i
end
finalize { |ctx| ctx.result = ctx[:sum] || 0 }
end
value = @db.get_first_value(
"select accumulate(a) from foo where a = 100" )
assert_equal 0, value
end
class AggregateHandler
class << self
def arity; 1; end
def text_rep; SQLite3::Constants::TextRep::ANY; end
def name; "multiply"; end
end
def step(ctx, a)
ctx[:buffer] ||= 1
ctx[:buffer] *= a.to_i
end
def finalize(ctx); ctx.result = ctx[:buffer]; end
end
def test_aggregate_initialized_twice
initialized = 0
handler = Class.new(AggregateHandler) do
define_method(:initialize) do
initialized += 1
super()
end
end
@db.create_aggregate_handler handler
@db.get_first_value( "select multiply(a) from foo" )
@db.get_first_value( "select multiply(a) from foo" )
assert_equal 2, initialized
end
def test_create_aggregate_handler_call_with_wrong_arity
@db.create_aggregate_handler AggregateHandler
assert_raise(SQLite3::SQLException) do
@db.get_first_value( "select multiply(a,c) from foo" )
end
end
class RaiseExceptionStepAggregateHandler
class << self
def arity; 1; end
def text_rep; SQLite3::Constants::TextRep::ANY; end
def name; "raiseexception"; end
end
def step(ctx, a)
raise CustomException.new( "bogus aggregate handler" )
end
def finalize(ctx); ctx.result = nil; end
end
def test_create_aggregate_handler_with_exception_step
@db.create_aggregate_handler RaiseExceptionStepAggregateHandler
assert_raise CustomException do
@db.get_first_value( "select raiseexception(a) from foo")
end
end
class RaiseExceptionNewAggregateHandler
class << self
def name; "raiseexception"; end
end
def initialize
raise CustomException.new( "bogus aggregate handler" )
end
def step(ctx, a); end
def finalize(ctx); ctx.result = nil; end
end
def test_create_aggregate_handler_with_exception_new
@db.create_aggregate_handler RaiseExceptionNewAggregateHandler
assert_raise CustomException do
@db.get_first_value( "select raiseexception(a) from foo")
end
end
def test_create_aggregate_handler
@db.create_aggregate_handler AggregateHandler
value = @db.get_first_value( "select multiply(a) from foo" )
assert_equal 6, value
end
class AccumulateAggregator
def step(*args)
@sum ||= 0
args.each { |a| @sum += a.to_i }
end
def finalize
@sum
end
end
class AccumulateAggregator2
def step(a, b)
@sum ||= 1
@sum *= (a.to_i + b.to_i)
end
def finalize
@sum
end
end
def test_define_aggregator_with_two_different_arities
@db.define_aggregator( "accumulate", AccumulateAggregator.new )
@db.define_aggregator( "accumulate", AccumulateAggregator2.new )
GC.start
values = @db.get_first_row( "select accumulate(c), accumulate(a,c) from foo")
assert_equal 33, values[0]
assert_equal 2145, values[1]
end
end
sqlite3-1.7.3/test/test_integration_resultset.rb 0000644 0000041 0000041 00000007321 14620135377 022151 0 ustar www-data www-data require 'helper'
class TC_ResultSet < SQLite3::TestCase
def setup
@db = SQLite3::Database.new(":memory:")
@db.transaction do
@db.execute "create table foo ( a integer primary key, b text )"
@db.execute "insert into foo ( b ) values ( 'foo' )"
@db.execute "insert into foo ( b ) values ( 'bar' )"
@db.execute "insert into foo ( b ) values ( 'baz' )"
end
@stmt = @db.prepare( "select * from foo where a in ( ?, ? )" )
@result = @stmt.execute
end
def teardown
@stmt.close
@db.close
end
def test_reset_unused
assert_nothing_raised { @result.reset }
assert @result.to_a.empty?
end
def test_reset_used
@result.to_a
assert_nothing_raised { @result.reset }
assert @result.to_a.empty?
end
def test_reset_with_bind
@result.to_a
assert_nothing_raised { @result.reset( 1, 2 ) }
assert_equal 2, @result.to_a.length
end
def test_eof_inner
@result.reset( 1 )
assert !@result.eof?
end
def test_eof_edge
@result.reset( 1 )
@result.next # to first row
@result.next # to end of result set
assert @result.eof?
end
def test_next_eof
@result.reset( 1 )
assert_not_nil @result.next
assert_nil @result.next
end
def test_next_no_type_translation_no_hash
@result.reset( 1 )
assert_equal [ 1, "foo" ], @result.next
end
def test_next_type_translation
@result.reset( 1 )
assert_equal [ 1, "foo" ], @result.next
end
def test_next_type_translation_with_untyped_column
@db.query( "select count(*) from foo" ) do |result|
assert_equal [3], result.next
end
end
def test_type_translation_with_null_column
time = '1974-07-25 14:39:00'
@db.execute "create table bar ( a integer, b time, c string )"
@db.execute "insert into bar (a, b, c) values (NULL, '#{time}', 'hello')"
@db.execute "insert into bar (a, b, c) values (1, NULL, 'hello')"
@db.execute "insert into bar (a, b, c) values (2, '#{time}', NULL)"
@db.query( "select * from bar" ) do |result|
assert_equal [nil, time, 'hello'], result.next
assert_equal [1, nil, 'hello'], result.next
assert_equal [2, time, nil], result.next
end
end
def test_real_translation
@db.execute('create table foo_real(a real)')
@db.execute('insert into foo_real values (42)' )
@db.query('select a, sum(a), typeof(a), typeof(sum(a)) from foo_real') do |result|
result = result.next
assert result[0].is_a?(Float)
assert result[1].is_a?(Float)
assert result[2].is_a?(String)
assert result[3].is_a?(String)
end
end
def test_next_results_as_hash
@db.results_as_hash = true
@result.reset( 1 )
hash = @result.next
assert_equal( { "a" => 1, "b" => "foo" },
hash )
assert_equal hash[@result.columns[0]], 1
assert_equal hash[@result.columns[1]], "foo"
end
def test_each
called = 0
@result.reset( 1, 2 )
@result.each { |row| called += 1 }
assert_equal 2, called
end
def test_enumerable
@result.reset( 1, 2 )
assert_equal 2, @result.to_a.length
end
def test_types
assert_equal [ "integer", "text" ], @result.types
end
def test_columns
assert_equal [ "a", "b" ], @result.columns
end
def test_close
stmt = @db.prepare( "select * from foo" )
result = stmt.execute
assert !result.closed?
result.close
assert result.closed?
assert stmt.closed?
assert_raise( SQLite3::Exception ) { result.reset }
assert_raise( SQLite3::Exception ) { result.next }
assert_raise( SQLite3::Exception ) { result.each }
assert_raise( SQLite3::Exception ) { result.close }
assert_raise( SQLite3::Exception ) { result.types }
assert_raise( SQLite3::Exception ) { result.columns }
end
end
sqlite3-1.7.3/test/test_result_set.rb 0000644 0000041 0000041 00000002044 14620135377 017702 0 ustar www-data www-data require 'helper'
module SQLite3
class TestResultSet < SQLite3::TestCase
def setup
@db = SQLite3::Database.new ':memory:'
super
end
def teardown
super
@db.close
end
def test_each_hash
@db.execute "create table foo ( a integer primary key, b text )"
list = ('a'..'z').to_a
list.each do |t|
@db.execute "insert into foo (b) values (\"#{t}\")"
end
rs = @db.prepare('select * from foo').execute
rs.each_hash do |hash|
assert_equal list[hash['a'] - 1], hash['b']
end
rs.close
end
def test_next_hash
@db.execute "create table foo ( a integer primary key, b text )"
list = ('a'..'z').to_a
list.each do |t|
@db.execute "insert into foo (b) values (\"#{t}\")"
end
rs = @db.prepare('select * from foo').execute
rows = []
while row = rs.next_hash
rows << row
end
rows.each do |hash|
assert_equal list[hash['a'] - 1], hash['b']
end
rs.close
end
end
end
sqlite3-1.7.3/test/test_integration_statement.rb 0000644 0000041 0000041 00000011725 14620135377 022126 0 ustar www-data www-data require 'helper'
class TC_Statement < SQLite3::TestCase
def setup
@db = SQLite3::Database.new(":memory:")
@db.transaction do
@db.execute "create table foo ( a integer primary key, b text )"
@db.execute "insert into foo ( b ) values ( 'foo' )"
@db.execute "insert into foo ( b ) values ( 'bar' )"
@db.execute "insert into foo ( b ) values ( 'baz' )"
end
@stmt = @db.prepare( "select * from foo where a in ( ?, :named )" )
end
def teardown
@stmt.close
@db.close
end
def test_remainder_empty
assert_equal "", @stmt.remainder
end
def test_remainder_nonempty
called = false
@db.prepare( "select * from foo;\n blah" ) do |stmt|
called = true
assert_equal "\n blah", stmt.remainder
end
assert called
end
def test_bind_params_empty
assert_nothing_raised { @stmt.bind_params }
assert @stmt.execute!.empty?
end
def test_bind_params_array
@stmt.bind_params 1, 2
assert_equal 2, @stmt.execute!.length
end
def test_bind_params_hash
@stmt.bind_params ":named" => 2
assert_equal 1, @stmt.execute!.length
end
def test_bind_params_hash_without_colon
@stmt.bind_params "named" => 2
assert_equal 1, @stmt.execute!.length
end
def test_bind_params_hash_as_symbol
@stmt.bind_params :named => 2
assert_equal 1, @stmt.execute!.length
end
def test_bind_params_mixed
@stmt.bind_params( 1, ":named" => 2 )
assert_equal 2, @stmt.execute!.length
end
def test_bind_param_by_index
@stmt.bind_params( 1, 2 )
assert_equal 2, @stmt.execute!.length
end
def test_bind_param_by_name_bad
assert_raise( SQLite3::Exception ) { @stmt.bind_param( "@named", 2 ) }
end
def test_bind_param_by_name_good
@stmt.bind_param( ":named", 2 )
assert_equal 1, @stmt.execute!.length
end
def test_bind_param_with_various_types
@db.transaction do
@db.execute "create table all_types ( a integer primary key, b float, c string, d integer )"
@db.execute "insert into all_types ( b, c, d ) values ( 1.5, 'hello', 68719476735 )"
end
assert_equal 1, @db.execute( "select * from all_types where b = ?", 1.5 ).length
assert_equal 1, @db.execute( "select * from all_types where c = ?", 'hello').length
assert_equal 1, @db.execute( "select * from all_types where d = ?", 68719476735).length
end
def test_execute_no_bind_no_block
assert_instance_of SQLite3::ResultSet, @stmt.execute
end
def test_execute_with_bind_no_block
assert_instance_of SQLite3::ResultSet, @stmt.execute( 1, 2 )
end
def test_execute_no_bind_with_block
called = false
@stmt.execute { |row| called = true }
assert called
end
def test_execute_with_bind_with_block
called = 0
@stmt.execute( 1, 2 ) { |row| called += 1 }
assert_equal 1, called
end
def test_reexecute
r = @stmt.execute( 1, 2 )
assert_equal 2, r.to_a.length
assert_nothing_raised { r = @stmt.execute( 1, 2 ) }
assert_equal 2, r.to_a.length
end
def test_execute_bang_no_bind_no_block
assert @stmt.execute!.empty?
end
def test_execute_bang_with_bind_no_block
assert_equal 2, @stmt.execute!( 1, 2 ).length
end
def test_execute_bang_no_bind_with_block
called = 0
@stmt.execute! { |row| called += 1 }
assert_equal 0, called
end
def test_execute_bang_with_bind_with_block
called = 0
@stmt.execute!( 1, 2 ) { |row| called += 1 }
assert_equal 2, called
end
def test_columns
c1 = @stmt.columns
c2 = @stmt.columns
assert_same c1, c2
assert_equal 2, c1.length
end
def test_columns_computed
called = false
@db.prepare( "select count(*) from foo" ) do |stmt|
called = true
assert_equal [ "count(*)" ], stmt.columns
end
assert called
end
def test_types
t1 = @stmt.types
t2 = @stmt.types
assert_same t1, t2
assert_equal 2, t1.length
end
def test_types_computed
called = false
@db.prepare( "select count(*) from foo" ) do |stmt|
called = true
assert_equal [ nil ], stmt.types
end
assert called
end
def test_close
stmt = @db.prepare( "select * from foo" )
assert !stmt.closed?
stmt.close
assert stmt.closed?
assert_raise( SQLite3::Exception ) { stmt.execute }
assert_raise( SQLite3::Exception ) { stmt.execute! }
assert_raise( SQLite3::Exception ) { stmt.close }
assert_raise( SQLite3::Exception ) { stmt.bind_params 5 }
assert_raise( SQLite3::Exception ) { stmt.bind_param 1, 5 }
assert_raise( SQLite3::Exception ) { stmt.columns }
assert_raise( SQLite3::Exception ) { stmt.types }
end
def test_committing_tx_with_statement_active
called = false
@db.prepare( "select count(*) from foo" ) do |stmt|
called = true
count = stmt.execute!.first.first.to_i
@db.transaction do
@db.execute "insert into foo ( b ) values ( 'hello' )"
end
new_count = stmt.execute!.first.first.to_i
assert_equal new_count, count+1
end
assert called
end
end
sqlite3-1.7.3/test/test_statement.rb 0000644 0000041 0000041 00000016666 14620135377 017534 0 ustar www-data www-data require 'helper'
module SQLite3
class TestStatement < SQLite3::TestCase
def setup
@db = SQLite3::Database.new(':memory:')
@stmt = SQLite3::Statement.new(@db, "select 'foo'")
end
def teardown
@stmt.close if !@stmt.closed?
@db.close
end
def test_double_close_does_not_segv
@db.execute 'CREATE TABLE "things" ("number" float NOT NULL)'
stmt = @db.prepare 'INSERT INTO things (number) VALUES (?)'
assert_raises(SQLite3::ConstraintException) { stmt.execute(nil) }
stmt.close
assert_raises(SQLite3::Exception) { stmt.close }
end
def test_raises_type_error
assert_raises(TypeError) do
SQLite3::Statement.new( @db, nil )
end
end
def test_insert_duplicate_records
@db.execute 'CREATE TABLE "things" ("name" varchar(20) CONSTRAINT "index_things_on_name" UNIQUE)'
stmt = @db.prepare("INSERT INTO things(name) VALUES(?)")
stmt.execute('ruby')
exception = assert_raises(SQLite3::ConstraintException) { stmt.execute('ruby') }
# SQLite 3.8.2 returns new error message:
# UNIQUE constraint failed: *table_name*.*column_name*
# Older versions of SQLite return:
# column *column_name* is not unique
assert_match(/(column(s)? .* (is|are) not unique|UNIQUE constraint failed: .*)/, exception.message)
stmt.close
end
###
# This method may not exist depending on how sqlite3 was compiled
def test_database_name
@db.execute('create table foo(text BLOB)')
@db.execute('insert into foo(text) values (?)',SQLite3::Blob.new('hello'))
stmt = @db.prepare('select text from foo')
if stmt.respond_to?(:database_name)
assert_equal 'main', stmt.database_name(0)
end
stmt.close
end
def test_prepare_blob
@db.execute('create table foo(text BLOB)')
stmt = @db.prepare('insert into foo(text) values (?)')
stmt.bind_param(1, SQLite3::Blob.new('hello'))
stmt.step
stmt.close
end
def test_select_blob
@db.execute('create table foo(text BLOB)')
@db.execute('insert into foo(text) values (?)',SQLite3::Blob.new('hello'))
assert_equal 'hello', @db.execute('select * from foo').first.first
end
def test_new
assert @stmt
end
def test_new_closed_handle
@db = SQLite3::Database.new(':memory:')
@db.close
assert_raises(ArgumentError) do
SQLite3::Statement.new(@db, 'select "foo"')
end
end
def test_new_with_remainder
stmt = SQLite3::Statement.new(@db, "select 'foo';bar")
assert_equal 'bar', stmt.remainder
stmt.close
end
def test_empty_remainder
assert_equal '', @stmt.remainder
end
def test_close
@stmt.close
assert @stmt.closed?
end
def test_double_close
@stmt.close
assert_raises(SQLite3::Exception) do
@stmt.close
end
end
def test_bind_param_string
stmt = SQLite3::Statement.new(@db, "select ?")
stmt.bind_param(1, "hello")
result = nil
stmt.each { |x| result = x }
assert_equal ['hello'], result
stmt.close
end
def test_bind_param_int
stmt = SQLite3::Statement.new(@db, "select ?")
stmt.bind_param(1, 10)
result = nil
stmt.each { |x| result = x }
assert_equal [10], result
stmt.close
end
def test_bind_nil
stmt = SQLite3::Statement.new(@db, "select ?")
stmt.bind_param(1, nil)
result = nil
stmt.each { |x| result = x }
assert_equal [nil], result
stmt.close
end
def test_bind_blob
@db.execute('create table foo(text BLOB)')
stmt = SQLite3::Statement.new(@db, 'insert into foo(text) values (?)')
stmt.bind_param(1, SQLite3::Blob.new('hello'))
stmt.execute
row = @db.execute('select * from foo')
stmt.close
assert_equal ['hello'], row.first
capture_io do # hush deprecation warning
assert_equal ['blob'], row.first.types
end
end
def test_bind_64
stmt = SQLite3::Statement.new(@db, "select ?")
stmt.bind_param(1, 2 ** 31)
result = nil
stmt.each { |x| result = x }
assert_equal [2 ** 31], result
stmt.close
end
def test_bind_double
stmt = SQLite3::Statement.new(@db, "select ?")
stmt.bind_param(1, 2.2)
result = nil
stmt.each { |x| result = x }
assert_equal [2.2], result
stmt.close
end
def test_named_bind
stmt = SQLite3::Statement.new(@db, "select :foo")
stmt.bind_param(':foo', 'hello')
result = nil
stmt.each { |x| result = x }
assert_equal ['hello'], result
stmt.close
end
def test_named_bind_no_colon
stmt = SQLite3::Statement.new(@db, "select :foo")
stmt.bind_param('foo', 'hello')
result = nil
stmt.each { |x| result = x }
assert_equal ['hello'], result
stmt.close
end
def test_named_bind_symbol
stmt = SQLite3::Statement.new(@db, "select :foo")
stmt.bind_param(:foo, 'hello')
result = nil
stmt.each { |x| result = x }
assert_equal ['hello'], result
stmt.close
end
def test_named_bind_not_found
stmt = SQLite3::Statement.new(@db, "select :foo")
assert_raises(SQLite3::Exception) do
stmt.bind_param('bar', 'hello')
end
stmt.close
end
def test_each
r = nil
@stmt.each do |row|
r = row
end
assert_equal(['foo'], r)
end
def test_reset!
r = []
@stmt.each { |row| r << row }
@stmt.reset!
@stmt.each { |row| r << row }
assert_equal [['foo'], ['foo']], r
end
def test_step
r = @stmt.step
assert_equal ['foo'], r
end
def test_step_twice
assert_not_nil @stmt.step
assert !@stmt.done?
assert_nil @stmt.step
assert @stmt.done?
@stmt.reset!
assert !@stmt.done?
end
def test_step_never_moves_past_done
10.times { @stmt.step }
@stmt.done?
end
def test_column_count
assert_equal 1, @stmt.column_count
end
def test_column_name
assert_equal "'foo'", @stmt.column_name(0)
assert_nil @stmt.column_name(10)
end
def test_bind_parameter_count
stmt = SQLite3::Statement.new(@db, "select ?, ?, ?")
assert_equal 3, stmt.bind_parameter_count
stmt.close
end
def test_execute_with_varargs
stmt = @db.prepare('select ?, ?')
assert_equal [[nil, nil]], stmt.execute(nil, nil).to_a
stmt.close
end
def test_execute_with_hash
stmt = @db.prepare('select :n, :h')
assert_equal [[10, nil]], stmt.execute('n' => 10, 'h' => nil).to_a
stmt.close
end
def test_with_error
@db.execute('CREATE TABLE "employees" ("name" varchar(20) NOT NULL CONSTRAINT "index_employees_on_name" UNIQUE)')
stmt = @db.prepare("INSERT INTO Employees(name) VALUES(?)")
stmt.execute('employee-1')
stmt.execute('employee-1') rescue SQLite3::ConstraintException
stmt.reset!
assert stmt.execute('employee-2')
stmt.close
end
def test_clear_bindings!
stmt = @db.prepare('select ?, ?')
stmt.bind_param 1, "foo"
stmt.bind_param 2, "bar"
# We can't fetch bound parameters back out of sqlite3, so just call
# the clear_bindings! method and assert that nil is returned
stmt.clear_bindings!
while x = stmt.step
assert_equal [nil, nil], x
end
stmt.close
end
end
end
sqlite3-1.7.3/test/test_deprecated.rb 0000644 0000041 0000041 00000002204 14620135377 017607 0 ustar www-data www-data require 'helper'
module SQLite3
class TestDeprecated < SQLite3::TestCase
def setup
super
@warn_before = $-w
$-w = false
@db = SQLite3::Database.new(':memory:')
@db.execute 'CREATE TABLE test_table (name text, age int)'
end
def teardown
super
$-w = @warn_before
@db.close
end
def test_query_with_many_bind_params_not_nil
rs = @db.query('select ?, ?', 1, 2)
assert_equal [[1, 2]], rs.to_a
rs.close
end
def test_execute_with_many_bind_params_not_nil
assert_equal [[1, 2]], @db.execute("select ?, ?", 1, 2).to_a
end
def test_query_with_many_bind_params
rs = @db.query("select ?, ?", nil, 1)
assert_equal [[nil, 1]], rs.to_a
rs.close
end
def test_query_with_nil_bind_params
rs = @db.query("select 'foo'", nil)
assert_equal [['foo']], rs.to_a
rs.close
end
def test_execute_with_many_bind_params
assert_equal [[nil, 1]], @db.execute("select ?, ?", nil, 1)
end
def test_execute_with_nil_bind_params
assert_equal [['foo']], @db.execute("select 'foo'", nil)
end
end
end
sqlite3-1.7.3/test/test_database.rb 0000644 0000041 0000041 00000045725 14620135377 017272 0 ustar www-data www-data require 'helper'
require 'tempfile'
require 'pathname'
module SQLite3
class TestDatabase < SQLite3::TestCase
attr_reader :db
def setup
@db = SQLite3::Database.new(':memory:')
super
end
def teardown
@db.close unless @db.closed?
end
def test_segv
assert_raises { SQLite3::Database.new 1 }
end
def test_db_filename
tf = nil
assert_equal '', @db.filename('main')
tf = Tempfile.new 'thing'
@db = SQLite3::Database.new tf.path
assert_equal File.realdirpath(tf.path), File.realdirpath(@db.filename('main'))
ensure
tf.unlink if tf
end
def test_filename
tf = nil
assert_equal '', @db.filename
tf = Tempfile.new 'thing'
@db = SQLite3::Database.new tf.path
assert_equal File.realdirpath(tf.path), File.realdirpath(@db.filename)
ensure
tf.unlink if tf
end
def test_filename_with_attachment
tf = nil
assert_equal '', @db.filename
tf = Tempfile.new 'thing'
@db.execute "ATTACH DATABASE '#{tf.path}' AS 'testing'"
assert_equal File.realdirpath(tf.path), File.realdirpath(@db.filename('testing'))
ensure
tf.unlink if tf
end
def test_filename_to_path
tf = Tempfile.new 'thing'
pn = Pathname tf.path
db = SQLite3::Database.new pn
assert_equal pn.realdirpath.to_s, File.realdirpath(db.filename)
ensure
tf.close! if tf
db.close if db
end
def test_error_code
begin
db.execute 'SELECT'
rescue SQLite3::SQLException => e
end
assert_equal 1, e.code
end
def test_extended_error_code
db.extended_result_codes = true
db.execute 'CREATE TABLE "employees" ("token" integer NOT NULL)'
begin
db.execute 'INSERT INTO employees (token) VALUES (NULL)'
rescue SQLite3::ConstraintException => e
end
assert_equal 1299, e.code
end
def test_bignum
num = 4907021672125087844
db.execute 'CREATE TABLE "employees" ("token" integer(8), "name" varchar(20) NOT NULL)'
db.execute "INSERT INTO employees(name, token) VALUES('employee-1', ?)", [num]
rows = db.execute 'select token from employees'
assert_equal num, rows.first.first
end
def test_blob
@db.execute("CREATE TABLE blobs ( id INTEGER, hash BLOB(10) )")
blob = Blob.new("foo\0bar")
@db.execute("INSERT INTO blobs VALUES (0, ?)", [blob])
assert_equal [[0, blob, blob.length, blob.length*2]], @db.execute("SELECT id, hash, length(hash), length(hex(hash)) FROM blobs")
end
def test_get_first_row
assert_equal [1], @db.get_first_row('SELECT 1')
end
def test_get_first_row_with_type_translation_and_hash_results
@db.results_as_hash = true
capture_io do # hush translation deprecation warnings
@db.type_translation = true
assert_equal({"1"=>1}, @db.get_first_row('SELECT 1'))
end
end
def test_execute_with_type_translation_and_hash
rows = []
@db.results_as_hash = true
capture_io do # hush translation deprecation warnings
@db.type_translation = true
@db.execute('SELECT 1') { |row| rows << row }
end
assert_equal({"1"=>1}, rows.first)
end
def test_encoding
assert @db.encoding, 'database has encoding'
end
def test_changes
@db.execute("CREATE TABLE items (id integer PRIMARY KEY AUTOINCREMENT, number integer)")
assert_equal 0, @db.changes
@db.execute("INSERT INTO items (number) VALUES (10)")
assert_equal 1, @db.changes
@db.execute_batch(
"UPDATE items SET number = (number + :nn) WHERE (number = :n)",
{"nn" => 20, "n" => 10})
assert_equal 1, @db.changes
assert_equal [[30]], @db.execute("select number from items")
end
def test_batch_last_comment_is_processed
# FIXME: nil as a successful return value is kinda dumb
assert_nil @db.execute_batch <<-eosql
CREATE TABLE items (id integer PRIMARY KEY AUTOINCREMENT);
-- omg
eosql
end
def test_execute_batch2
@db.results_as_hash = true
return_value = @db.execute_batch2 <<-eosql
CREATE TABLE items (id integer PRIMARY KEY AUTOINCREMENT, name string);
INSERT INTO items (name) VALUES ("foo");
INSERT INTO items (name) VALUES ("bar");
SELECT * FROM items;
eosql
assert_equal return_value, [{"id"=>"1","name"=>"foo"}, {"id"=>"2", "name"=>"bar"}]
return_value = @db.execute_batch2('SELECT * FROM items;') do |result|
result["id"] = result["id"].to_i
result
end
assert_equal return_value, [{"id"=>1,"name"=>"foo"}, {"id"=>2, "name"=>"bar"}]
return_value = @db.execute_batch2('INSERT INTO items (name) VALUES ("oof")')
assert_equal return_value, []
return_value = @db.execute_batch2(
'CREATE TABLE employees (id integer PRIMARY KEY AUTOINCREMENT, name string, age integer(3));
INSERT INTO employees (age) VALUES (30);
INSERT INTO employees (age) VALUES (40);
INSERT INTO employees (age) VALUES (20);
SELECT age FROM employees;') do |result|
result["age"] = result["age"].to_i
result
end
assert_equal return_value, [{"age"=>30}, {"age"=>40}, {"age"=>20}]
return_value = @db.execute_batch2('SELECT name FROM employees');
assert_equal return_value, [{"name"=>nil}, {"name"=>nil}, {"name"=>nil}]
@db.results_as_hash = false
return_value = @db.execute_batch2(
'CREATE TABLE managers (id integer PRIMARY KEY AUTOINCREMENT, age integer(3));
INSERT INTO managers (age) VALUES (50);
INSERT INTO managers (age) VALUES (60);
SELECT id, age from managers;') do |result|
result = result.map do |res|
res.to_i
end
result
end
assert_equal return_value, [[1, 50], [2, 60]]
assert_raises (RuntimeError) do
# "names" is not a valid column
@db.execute_batch2 'INSERT INTO items (names) VALUES ("bazz")'
end
end
def test_new
db = SQLite3::Database.new(':memory:')
assert_instance_of(SQLite3::Database, db)
ensure
db.close if db
end
def test_open
db = SQLite3::Database.open(':memory:')
assert_instance_of(SQLite3::Database, db)
ensure
db.close if db
end
def test_open_returns_block_result
result = SQLite3::Database.open(':memory:') do |db|
:foo
end
assert_equal :foo, result
end
def test_new_yields_self
thing = nil
SQLite3::Database.new(':memory:') do |db|
thing = db
end
assert_instance_of(SQLite3::Database, thing)
end
def test_open_yields_self
thing = nil
SQLite3::Database.open(':memory:') do |db|
thing = db
end
assert_instance_of(SQLite3::Database, thing)
end
def test_new_with_options
# determine if Ruby is running on Big Endian platform
utf16 = ([1].pack("I") == [1].pack("N")) ? "UTF-16BE" : "UTF-16LE"
if RUBY_VERSION >= "1.9"
db = SQLite3::Database.new(':memory:'.encode(utf16), :utf16 => true)
else
db = SQLite3::Database.new(Iconv.conv(utf16, 'UTF-8', ':memory:'),
:utf16 => true)
end
assert_instance_of(SQLite3::Database, db)
ensure
db.close if db
end
def test_close
db = SQLite3::Database.new(':memory:')
db.close
assert db.closed?
end
def test_block_closes_self
thing = nil
SQLite3::Database.new(':memory:') do |db|
thing = db
assert !thing.closed?
end
assert thing.closed?
end
def test_open_with_block_closes_self
thing = nil
SQLite3::Database.open(':memory:') do |db|
thing = db
assert !thing.closed?
end
assert thing.closed?
end
def test_block_closes_self_even_raised
thing = nil
begin
SQLite3::Database.new(':memory:') do |db|
thing = db
raise
end
rescue
end
assert thing.closed?
end
def test_open_with_block_closes_self_even_raised
thing = nil
begin
SQLite3::Database.open(':memory:') do |db|
thing = db
raise
end
rescue
end
assert thing.closed?
end
def test_prepare
db = SQLite3::Database.new(':memory:')
stmt = db.prepare('select "hello world"')
assert_instance_of(SQLite3::Statement, stmt)
ensure
stmt.close if stmt
end
def test_block_prepare_does_not_double_close
db = SQLite3::Database.new(':memory:')
r = db.prepare('select "hello world"') do |stmt|
stmt.close
:foo
end
assert_equal :foo, r
end
def test_total_changes
db = SQLite3::Database.new(':memory:')
db.execute("create table foo ( a integer primary key, b text )")
db.execute("insert into foo (b) values ('hello')")
assert_equal 1, db.total_changes
end
def test_execute_returns_list_of_hash
db = SQLite3::Database.new(':memory:', :results_as_hash => true)
db.execute("create table foo ( a integer primary key, b text )")
db.execute("insert into foo (b) values ('hello')")
rows = db.execute("select * from foo")
assert_equal [{"a"=>1, "b"=>"hello"}], rows
end
def test_execute_yields_hash
db = SQLite3::Database.new(':memory:', :results_as_hash => true)
db.execute("create table foo ( a integer primary key, b text )")
db.execute("insert into foo (b) values ('hello')")
db.execute("select * from foo") do |row|
assert_equal({"a"=>1, "b"=>"hello"}, row)
end
end
def test_table_info
db = SQLite3::Database.new(':memory:', :results_as_hash => true)
db.execute("create table foo ( a integer primary key, b text )")
info = [{
"name" => "a",
"pk" => 1,
"notnull" => 0,
"type" => "integer",
"dflt_value" => nil,
"cid" => 0
},
{
"name" => "b",
"pk" => 0,
"notnull" => 0,
"type" => "text",
"dflt_value" => nil,
"cid" => 1
}]
assert_equal info, db.table_info('foo')
end
def test_total_changes_closed
db = SQLite3::Database.new(':memory:')
db.close
assert_raise(SQLite3::Exception) do
db.total_changes
end
end
def test_trace_requires_opendb
@db.close
assert_raise(SQLite3::Exception) do
@db.trace { |x| }
end
end
def test_trace_with_block
result = nil
@db.trace { |sql| result = sql }
@db.execute "select 'foo'"
assert_equal "select 'foo'", result
end
def test_trace_with_object
obj = Class.new {
attr_accessor :result
def call sql; @result = sql end
}.new
@db.trace(obj)
@db.execute "select 'foo'"
assert_equal "select 'foo'", obj.result
end
def test_trace_takes_nil
@db.trace(nil)
@db.execute "select 'foo'"
end
def test_last_insert_row_id_closed
@db.close
assert_raise(SQLite3::Exception) do
@db.last_insert_row_id
end
end
def test_define_function
called_with = nil
@db.define_function("hello") do |value|
called_with = value
end
@db.execute("select hello(10)")
assert_equal 10, called_with
end
def test_call_func_arg_type
called_with = nil
@db.define_function("hello") do |b, c, d|
called_with = [b, c, d]
nil
end
@db.execute("select hello(2.2, 'foo', NULL)")
assert_in_delta(2.2, called_with[0], 0.0001)
assert_equal("foo", called_with[1])
assert_nil(called_with[2])
end
def test_define_varargs
called_with = nil
@db.define_function("hello") do |*args|
called_with = args
nil
end
@db.execute("select hello(2.2, 'foo', NULL)")
assert_in_delta(2.2, called_with[0], 0.0001)
assert_equal("foo", called_with[1])
assert_nil(called_with[2])
end
def test_call_func_blob
called_with = nil
@db.define_function("hello") do |a, b|
called_with = [a, b, a.length]
nil
end
blob = Blob.new("a\0fine\0kettle\0of\0fish")
@db.execute("select hello(?, length(?))", [blob, blob])
assert_equal [blob, blob.length, 21], called_with
end
def test_function_return
@db.define_function("hello") { |a| 10 }
assert_equal [10], @db.execute("select hello('world')").first
end
def test_function_return_types
[10, 2.2, nil, "foo", Blob.new("foo\0bar")].each do |thing|
@db.define_function("hello") { |a| thing }
assert_equal [thing], @db.execute("select hello('world')").first
end
end
def test_function_gc_segfault
@db.create_function("bug", -1) { |func, *values| func.result = values.join }
# With a lot of data and a lot of threads, try to induce a GC segfault.
params = Array.new(127, "?" * 28000)
proc = Proc.new {
db.execute("select bug(#{Array.new(params.length, "?").join(",")})", params)
}
m = Mutex.new
30.times.map { Thread.new { m.synchronize { proc.call } } }.each(&:join)
end
def test_function_return_type_round_trip
[10, 2.2, nil, "foo", Blob.new("foo\0bar")].each do |thing|
@db.define_function("hello") { |a| a }
assert_equal [thing], @db.execute("select hello(hello(?))", [thing]).first
end
end
def test_define_function_closed
@db.close
assert_raise(SQLite3::Exception) do
@db.define_function('foo') { }
end
end
def test_inerrupt_closed
@db.close
assert_raise(SQLite3::Exception) do
@db.interrupt
end
end
def test_define_aggregate
@db.execute "create table foo ( a integer primary key, b text )"
@db.execute "insert into foo ( b ) values ( 'foo' )"
@db.execute "insert into foo ( b ) values ( 'bar' )"
@db.execute "insert into foo ( b ) values ( 'baz' )"
acc = Class.new {
attr_reader :sum
alias :finalize :sum
def initialize
@sum = 0
end
def step a
@sum += a
end
}.new
@db.define_aggregator("accumulate", acc)
value = @db.get_first_value( "select accumulate(a) from foo" )
assert_equal 6, value
end
def test_authorizer_ok
statements = []
@db.authorizer = Class.new {
def call action, a, b, c, d; true end
}.new
statements << @db.prepare("select 'fooooo'")
@db.authorizer = Class.new {
def call action, a, b, c, d; 0 end
}.new
statements << @db.prepare("select 'fooooo'")
ensure
statements.each(&:close)
end
def test_authorizer_ignore
@db.authorizer = Class.new {
def call action, a, b, c, d; nil end
}.new
stmt = @db.prepare("select 'fooooo'")
assert_nil stmt.step
ensure
stmt.close if stmt
end
def test_authorizer_fail
@db.authorizer = Class.new {
def call action, a, b, c, d; false end
}.new
assert_raises(SQLite3::AuthorizationException) do
@db.prepare("select 'fooooo'")
end
end
def test_remove_auth
@db.authorizer = Class.new {
def call action, a, b, c, d; false end
}.new
assert_raises(SQLite3::AuthorizationException) do
@db.prepare("select 'fooooo'")
end
@db.authorizer = nil
s = @db.prepare("select 'fooooo'")
ensure
s.close if s
end
def test_close_with_open_statements
s = @db.prepare("select 'foo'")
assert_raises(SQLite3::BusyException) do
@db.close
end
ensure
s.close if s
end
def test_execute_with_empty_bind_params
assert_equal [['foo']], @db.execute("select 'foo'", [])
end
def test_query_with_named_bind_params
resultset = @db.query("select :n", {'n' => 'foo'})
assert_equal [['foo']], resultset.to_a
ensure
resultset.close if resultset
end
def test_execute_with_named_bind_params
assert_equal [['foo']], @db.execute("select :n", {'n' => 'foo'})
end
def test_strict_mode
unless Gem::Requirement.new(">= 3.29.0").satisfied_by?(Gem::Version.new(SQLite3::SQLITE_VERSION))
skip("strict mode feature not available in #{SQLite3::SQLITE_VERSION}")
end
db = SQLite3::Database.new(':memory:')
db.execute('create table numbers (val int);')
db.execute('create index index_numbers_nope ON numbers ("nope");') # nothing raised
db = SQLite3::Database.new(':memory:', :strict => true)
db.execute('create table numbers (val int);')
error = assert_raises SQLite3::SQLException do
db.execute('create index index_numbers_nope ON numbers ("nope");')
end
assert_includes error.message, "no such column: nope"
end
def test_load_extension_with_nonstring_argument
db = SQLite3::Database.new(':memory:')
skip("extensions are not enabled") unless db.respond_to?(:load_extension)
assert_raises(TypeError) { db.load_extension(1) }
assert_raises(TypeError) { db.load_extension(Pathname.new("foo.so")) }
end
def test_raw_float_infinity
# https://github.com/sparklemotion/sqlite3-ruby/issues/396
skip if SQLite3::SQLITE_LOADED_VERSION >= "3.43.0"
db = SQLite3::Database.new ":memory:"
db.execute("create table foo (temperature float)")
db.execute("insert into foo values (?)", 37.5)
db.execute("insert into foo values (?)", Float::INFINITY)
assert_equal Float::INFINITY, db.execute("select avg(temperature) from foo").first.first
end
def test_default_transaction_mode
tf = Tempfile.new 'database_default_transaction_mode'
SQLite3::Database.new(tf.path) do |db|
db.execute("create table foo (score int)")
db.execute("insert into foo values (?)", 1)
end
test_cases = [
{mode: nil, read: true, write: true},
{mode: :deferred, read: true, write: true},
{mode: :immediate, read: true, write: false},
{mode: :exclusive, read: false, write: false},
]
test_cases.each do |item|
db = SQLite3::Database.new tf.path, default_transaction_mode: item[:mode]
db2 = SQLite3::Database.new tf.path
db.transaction do
sql_for_read_test = "select * from foo"
if item[:read]
assert_nothing_raised{ db2.execute(sql_for_read_test) }
else
assert_raises(SQLite3::BusyException){ db2.execute(sql_for_read_test) }
end
sql_for_write_test = "insert into foo values (2)"
if item[:write]
assert_nothing_raised{ db2.execute(sql_for_write_test) }
else
assert_raises(SQLite3::BusyException){ db2.execute(sql_for_write_test) }
end
end
ensure
db.close if db && !db.closed?
db2.close if db2 && !db2.closed?
end
ensure
tf.unlink if tf
end
end
end
sqlite3-1.7.3/test/test_database_readwrite.rb 0000644 0000041 0000041 00000002320 14620135377 021320 0 ustar www-data www-data require 'helper'
module SQLite3
class TestDatabaseReadwrite < SQLite3::TestCase
def setup
File.unlink 'test-readwrite.db' if File.exist?('test-readwrite.db')
@db = SQLite3::Database.new('test-readwrite.db')
@db.execute("CREATE TABLE foos (id integer)")
@db.close
end
def teardown
@db.close unless @db.closed?
File.unlink 'test-readwrite.db' if File.exist?('test-readwrite.db')
end
def test_open_readwrite_database
@db = SQLite3::Database.new('test-readwrite.db', :readwrite => true)
assert !@db.readonly?
end
def test_open_readwrite_readonly_database
assert_raise(RuntimeError) do
@db = SQLite3::Database.new('test-readwrite.db', :readwrite => true, :readonly => true)
end
end
def test_open_readwrite_not_exists_database
File.unlink 'test-readwrite.db'
assert_raise(SQLite3::CantOpenException) do
@db = SQLite3::Database.new('test-readwrite.db', :readonly => true)
end
end
def test_insert_readwrite_database
@db = SQLite3::Database.new('test-readwrite.db', :readwrite => true)
@db.execute("INSERT INTO foos (id) VALUES (12)")
assert @db.changes == 1
end
end
end
sqlite3-1.7.3/test/test_encoding.rb 0000644 0000041 0000041 00000011567 14620135377 017311 0 ustar www-data www-data # -*- coding: utf-8 -*-
require 'helper'
module SQLite3
class TestEncoding < SQLite3::TestCase
def setup
@db = SQLite3::Database.new(':memory:')
@create = "create table ex(id int, data string)"
@insert = "insert into ex(id, data) values (?, ?)"
@db.execute(@create);
end
def teardown
@db.close
end
def test_select_encoding_on_utf_16
str = "foo"
utf16 = ([1].pack("I") == [1].pack("N")) ? "UTF-16BE" : "UTF-16LE"
db = SQLite3::Database.new(':memory:'.encode(utf16))
db.execute @create
db.execute "insert into ex (id, data) values (1, \"#{str}\")"
stmt = db.prepare 'select * from ex where data = ?'
['US-ASCII', utf16, 'EUC-JP', 'UTF-8'].each do |enc|
stmt.bind_param 1, str.encode(enc)
assert_equal 1, stmt.to_a.length
stmt.reset!
end
stmt.close
end
def test_insert_encoding
str = "foo"
utf16 = ([1].pack("I") == [1].pack("N")) ? "UTF-16BE" : "UTF-16LE"
db = SQLite3::Database.new(':memory:'.encode(utf16))
db.execute @create
stmt = db.prepare @insert
['US-ASCII', utf16, 'EUC-JP', 'UTF-8'].each_with_index do |enc,i|
stmt.bind_param 1, i
stmt.bind_param 2, str.encode(enc)
stmt.to_a
stmt.reset!
end
stmt.close
db.execute('select data from ex').flatten.each do |s|
assert_equal str, s
end
end
def test_default_internal_is_honored
warn_before = $-w
$-w = false
before_enc = Encoding.default_internal
str = "壁に耳あり、障子に目あり"
stmt = @db.prepare('insert into ex(data) values (?)')
stmt.bind_param 1, str
stmt.step
stmt.close
Encoding.default_internal = 'EUC-JP'
string = @db.execute('select data from ex').first.first
assert_equal Encoding.default_internal, string.encoding
assert_equal str.encode('EUC-JP'), string
assert_equal str, string.encode(str.encoding)
ensure
Encoding.default_internal = before_enc
$-w = warn_before
end
def test_blob_is_binary
str = "猫舌"
@db.execute('create table foo(data text)')
stmt = @db.prepare('insert into foo(data) values (?)')
stmt.bind_param(1, SQLite3::Blob.new(str))
stmt.step
stmt.close
string = @db.execute('select data from foo').first.first
assert_equal Encoding.find('ASCII-8BIT'), string.encoding
assert_equal str, string.force_encoding('UTF-8')
end
def test_blob_is_ascii8bit
str = "猫舌"
@db.execute('create table foo(data text)')
stmt = @db.prepare('insert into foo(data) values (?)')
stmt.bind_param(1, str.dup.force_encoding("ASCII-8BIT"))
stmt.step
stmt.close
string = @db.execute('select data from foo').first.first
assert_equal Encoding.find('ASCII-8BIT'), string.encoding
assert_equal str, string.force_encoding('UTF-8')
end
def test_blob_with_eucjp
str = "猫舌".encode("EUC-JP")
@db.execute('create table foo(data text)')
stmt = @db.prepare('insert into foo(data) values (?)')
stmt.bind_param(1, SQLite3::Blob.new(str))
stmt.step
stmt.close
string = @db.execute('select data from foo').first.first
assert_equal Encoding.find('ASCII-8BIT'), string.encoding
assert_equal str, string.force_encoding('EUC-JP')
end
def test_db_with_eucjp
db = SQLite3::Database.new(':memory:'.encode('EUC-JP'))
assert_equal(Encoding.find('UTF-8'), db.encoding)
end
def test_db_with_utf16
utf16 = ([1].pack("I") == [1].pack("N")) ? "UTF-16BE" : "UTF-16LE"
db = SQLite3::Database.new(':memory:'.encode(utf16))
assert_equal(Encoding.find(utf16), db.encoding)
end
def test_statement_eucjp
str = "猫舌"
@db.execute("insert into ex(data) values ('#{str}')".encode('EUC-JP'))
row = @db.execute("select data from ex")
assert_equal @db.encoding, row.first.first.encoding
assert_equal str, row.first.first
end
def test_statement_utf8
str = "猫舌"
@db.execute("insert into ex(data) values ('#{str}')")
row = @db.execute("select data from ex")
assert_equal @db.encoding, row.first.first.encoding
assert_equal str, row.first.first
end
def test_encoding
assert_equal Encoding.find("UTF-8"), @db.encoding
end
def test_utf_8
str = "猫舌"
@db.execute(@insert, [10, str])
row = @db.execute("select data from ex")
assert_equal @db.encoding, row.first.first.encoding
assert_equal str, row.first.first
end
def test_euc_jp
str = "猫舌".encode('EUC-JP')
@db.execute(@insert, [10, str])
row = @db.execute("select data from ex")
assert_equal @db.encoding, row.first.first.encoding
assert_equal str.encode('UTF-8'), row.first.first
end
end if RUBY_VERSION >= '1.9.1'
end
sqlite3-1.7.3/test/test_database_readonly.rb 0000644 0000041 0000041 00000002033 14620135377 021150 0 ustar www-data www-data require 'helper'
module SQLite3
class TestDatabaseReadonly < SQLite3::TestCase
def setup
File.unlink 'test-readonly.db' if File.exist?('test-readonly.db')
@db = SQLite3::Database.new('test-readonly.db')
@db.execute("CREATE TABLE foos (id integer)")
@db.close
end
def teardown
@db.close unless @db.closed?
File.unlink 'test-readonly.db' if File.exist?('test-readonly.db')
end
def test_open_readonly_database
@db = SQLite3::Database.new('test-readonly.db', :readonly => true)
assert @db.readonly?
end
def test_open_readonly_not_exists_database
File.unlink 'test-readonly.db'
assert_raise(SQLite3::CantOpenException) do
@db = SQLite3::Database.new('test-readonly.db', :readonly => true)
end
end
def test_insert_readonly_database
@db = SQLite3::Database.new('test-readonly.db', :readonly => true)
assert_raise(SQLite3::ReadOnlyException) do
@db.execute("INSERT INTO foos (id) VALUES (12)")
end
end
end
end
sqlite3-1.7.3/ports/ 0000755 0000041 0000041 00000000000 14620135377 014315 5 ustar www-data www-data sqlite3-1.7.3/ports/archives/ 0000755 0000041 0000041 00000000000 14620135377 016121 5 ustar www-data www-data sqlite3-1.7.3/ports/archives/sqlite-autoconf-3450200.tar.gz 0000600 0000041 0000041 00014254332 14620135377 023206 0 ustar www-data www-data [{Wƶѧ:B!c[8ɣI1V%q~{fdHr]Z g==c0HeɝGV^VO}ֶO|SެnlmR{mVFl}M$>LU&B|ѭ?O'A([Íob\mss~xoEeD5r;DDHHTL#mXD).GyI0I/^ZT(UՍ]q_7, Gx\GzM'R^