diff --git a/lib/sequel/adapters/shared/sqlite.rb b/lib/sequel/adapters/shared/sqlite.rb index c04e59a67..18c82fa74 100644 --- a/lib/sequel/adapters/shared/sqlite.rb +++ b/lib/sequel/adapters/shared/sqlite.rb @@ -145,6 +145,11 @@ def supports_savepoints? sqlite_version >= 30608 end + # SQLite 3.8.2+ supports the without rowid table constraint + def support_without_rowid? + sqlite_version >= 30802 + end + # Override the default setting for whether to use timezones in timestamps. # It is set to +false+ by default, as SQLite's date/time methods do not # support timezones in timestamps. @@ -344,9 +349,17 @@ def connection_pragmas ps end - # Support creating STRICT tables via :strict option + # Support creating STRICT AND/OR WITHOUT ROWID tables via :strict and :without_rowid options def create_table_sql(name, generator, options) - "#{super}#{' STRICT' if options[:strict]}" + if options[:strict] && options[:without_rowid] + "#{super} STRICT, WITHOUT ROWID" + elsif options[:strict] + "#{super} STRICT" + elsif options[:without_rowid] + "#{super} WITHOUT ROWID" + else + super + end end # SQLite support creating temporary views. diff --git a/lib/sequel/database/schema_methods.rb b/lib/sequel/database/schema_methods.rb index fbcc69954..921180c6e 100644 --- a/lib/sequel/database/schema_methods.rb +++ b/lib/sequel/database/schema_methods.rb @@ -191,6 +191,12 @@ def create_join_table?(hash, options=OPTS) # The +any+ type is treated like a SQLite column in a non-strict table, # allowing any type of data to be stored. This option is supported on # SQLite 3.37.0+. + # :without_rowid :: Create a WITHOUT ROWID table. Every row in SQLite has a special + # 'rowid' column, that uniquely identifies that row within the table. + # If this option is used, the 'rowid' column is omitted, which can + # sometimes provide some space and speed advantages. Note that you + # must then provide an explicit primary key when you create the table. + # This option is supported on SQLite 3.8.2+. # # See Schema::CreateTableGenerator and the {"Schema Modification" guide}[rdoc-ref:doc/schema_modification.rdoc]. def create_table(name, options=OPTS, &block) diff --git a/spec/adapters/sqlite_spec.rb b/spec/adapters/sqlite_spec.rb index 43ab17c8f..e1d205a74 100644 --- a/spec/adapters/sqlite_spec.rb +++ b/spec/adapters/sqlite_spec.rb @@ -774,6 +774,61 @@ end end if DB.sqlite_version >= 33700 +describe 'SQLite WITHOUT ROWID tables' do + before do + @db = DB + end + after do + @db.drop_table?(:without_rowid_table) + end + + it "supports creation via :without_rowid option" do + @db = DB + @db.create_table(:without_rowid_table, :without_rowid=>true) do + int :id + primary_key [:id] + end + + ds = @db[:without_rowid_table] + ds.insert(:id=>1) + ds.all.must_equal [{:id=>1}] + proc{ds.select(:rowid).all}.must_raise Sequel::DatabaseError + end +end if DB.sqlite_version >= 30802 + +describe 'SQLite STRICT and WITHOUT ROWID tables' do + before do + @db = DB + end + after do + @db.drop_table?(:strict_without_rowid_table) + end + + it "supports creation via both :strict and :without_rowid option" do + @db = DB + @db.create_table(:strict_without_rowid_table, :strict=>true, :without_rowid=>true) do + int :id + int :a + integer :b + real :c + text :d + blob :e + any :f + + primary_key [:id] + end + ds = @db[:strict_without_rowid_table] + ds.insert(:id=>1, :a=>2, :b=>3, :c=>1.2, :d=>'foo', :e=>Sequel.blob("\0\1\2\3"), :f=>'f') + proc{ds.select(:rowid).all}.must_raise Sequel::DatabaseError + ds.all.must_equal [{:id=>1, :a=>2, :b=>3, :c=>1.2, :d=>'foo', :e=>Sequel.blob("\0\1\2\3"), :f=>'f'}] + proc{ds.insert(:a=>'a')}.must_raise Sequel::ConstraintViolation + proc{ds.insert(:b=>'a')}.must_raise Sequel::ConstraintViolation + proc{ds.insert(:c=>'a')}.must_raise Sequel::ConstraintViolation + proc{ds.insert(:d=>Sequel.blob("\0\1\2\3"))}.must_raise Sequel::ConstraintViolation + proc{ds.insert(:e=>1)}.must_raise Sequel::ConstraintViolation + end +end if DB.sqlite_version >= 33700 + describe 'SQLite Database' do it 'supports operations/functions with sqlite_json_ops' do Sequel.extension :sqlite_json_ops