Skip to content

Commit

Permalink
Add foreign_keys accessor to SQLite Database objects, which modifies …
Browse files Browse the repository at this point in the history
…the foreign_keys PRAGMA available in 3.6.19+

I hadn't noticed this before, but all PRAGMA modification operations
in the shared SQLite adapter are not thread safe.  The only reason
this wasn't caught before is because it's likely few people use them
and few people run SQLite in a threaded environment, and the
intersection of those groups is probably very small.

A future commit will address this by making all PRAGMA modification
operators apply directly on the underlying connection objects
inside Database#connect, by specifying the options as database
options when calling Sequel.connect.  That's the only thread-safe
simple way to do it.
  • Loading branch information
jeremyevans committed Apr 8, 2010
1 parent e63f16a commit 34dbeb5
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG
@@ -1,5 +1,7 @@
=== HEAD

* Add foreign_keys accessor to SQLite Database objects, which modifies the foreign_keys PRAGMA available in 3.6.19+ (jeremyevans)

* Add an Database#sqlite_version method when connecting to SQLite, used to determine feature support (jeremyevans)

* Fix rolling back transactions when connecting to Oracle via JDBC (jeremyevans)
Expand Down
12 changes: 12 additions & 0 deletions lib/sequel/adapters/shared/sqlite.rb
Expand Up @@ -31,6 +31,18 @@ def auto_vacuum=(value)
def database_type
:sqlite
end

# Boolean signifying the value of the foreign_keys PRAGMA, or nil
# if not using SQLite 3.6.19+.
def foreign_keys
pragma_get(:foreign_keys).to_i == 1 if sqlite_version >= 30619
end

# Set the foreign_keys PRAGMA using the given boolean value, if using
# SQLite 3.6.19+. If not using 3.6.19+, no error is raised.
def foreign_keys=(value)
pragma_set(:foreign_keys, !!value ? 'on' : 'off') if sqlite_version >= 30619
end

# Return a hash containing index information. Hash keys are index name symbols.
# Values are subhashes with two keys, :columns and :unique. The value of :columns
Expand Down
28 changes: 28 additions & 0 deletions spec/adapters/sqlite_spec.rb
Expand Up @@ -36,6 +36,34 @@
end
end

specify "should provide the SQLite version as an integer" do
@db.sqlite_version.should be_a_kind_of(Integer)
end

specify "should support setting and getting the foreign_keys pragma" do
(@db.sqlite_version >= 30619 ? [true, false] : [nil]).should include(@db.foreign_keys)
@db.foreign_keys = true
@db.foreign_keys = false
end

if SQLITE_DB.sqlite_version >= 30619
specify "should enforce foreign key integrity if foreign_keys pragma is set" do
@db.foreign_keys = true
@db.create_table!(:fk){primary_key :id; foreign_key :parent_id, :fk}
@db[:fk].insert(1, nil)
@db[:fk].insert(2, 1)
@db[:fk].insert(3, 3)
proc{@db[:fk].insert(4, 5)}.should raise_error(Sequel::Error)
end
end

specify "should not enforce foreign key integrity if foreign_keys pragma is unset" do
@db.foreign_keys = false
@db.create_table!(:fk){primary_key :id; foreign_key :parent_id, :fk}
@db[:fk].insert(1, 2)
@db[:fk].all.should == [{:id=>1, :parent_id=>2}]
end

specify "should provide a list of existing tables" do
@db.drop_table(:testing) rescue nil
@db.tables.should be_a_kind_of(Array)
Expand Down

0 comments on commit 34dbeb5

Please sign in to comment.