SEQUEL_ADAPTER_TEST = :oracle require_relative 'spec_helper' unless DB.opts[:autosequence] warn "Running oracle adapter specs without :autosequence Database option results in many errors, use the :autosequence Database option when testing" end describe "An Oracle database" do before(:all) do DB.create_table!(:items) do String :name, :size => 50 Integer :value Date :date_created index :value end DB.create_table!(:books) do Integer :id String :title, :size => 50 Integer :category_id end DB.create_table!(:categories) do Integer :id String :cat_name, :size => 50 end DB.create_table!(:notes) do Integer :id String :title, :size => 50 String :content, :text => true end @d = DB[:items] end after do @d.delete end after(:all) do DB.drop_table?(:items, :books, :categories, :notes) end it "should allow limit and offset with clob columns" do notes = [] notes << {:id => 1, :title => 'abc', :content => 'zyx'} notes << {:id => 2, :title => 'def', :content => 'wvu'} notes << {:id => 3, :title => 'ghi', :content => 'tsr'} notes << {:id => 4, :title => 'jkl', :content => 'qpo'} notes << {:id => 5, :title => 'mno', :content => 'nml'} DB[:notes].multi_insert(notes) DB[:notes].sort_by{|x| x[:id]}.must_equal notes rows = DB[:notes].limit(3, 0).all rows.length.must_equal 3 rows.all?{|v| notes.must_include(v)} end it "should provide disconnect functionality" do DB.execute("select user from dual") DB.pool.size.must_equal 1 DB.disconnect DB.pool.size.must_equal 0 end it "should have working view_exists?" do begin DB.view_exists?(:cats).must_equal false DB.create_view(:cats, DB[:categories]) DB.view_exists?(:cats).must_equal true if IDENTIFIER_MANGLING && !DB.frozen? om = DB.identifier_output_method im = DB.identifier_input_method DB.identifier_output_method = :reverse DB.identifier_input_method = :reverse DB.view_exists?(:STAC).must_equal true DB.view_exists?(:cats).must_equal false end ensure if IDENTIFIER_MANGLING && !DB.frozen? DB.identifier_output_method = om DB.identifier_input_method = im end DB.drop_view(:cats) end end it "should be able to get current sequence value with SQL" do begin DB.create_table!(:foo){primary_key :id} DB.fetch('SELECT seq_foo_id.nextval FROM DUAL').single_value.must_equal 1 ensure DB.drop_table(:foo) end end it "should provide schema information" do books_schema = [[:id, [:integer, false, true, nil]], [:title, [:string, false, true, nil]], [:category_id, [:integer, false, true, nil]]] categories_schema = [[:id, [:integer, false, true, nil]], [:cat_name, [:string, false, true, nil]]] items_schema = [[:name, [:string, false, true, nil]], [:value, [:integer, false, true, nil]], [:date_created, [:datetime, false, true, nil]]] {:books => books_schema, :categories => categories_schema, :items => items_schema}.each_pair do |table, expected_schema| schema = DB.schema(table) schema.wont_equal nil schema.map{|c, s| [c, s.values_at(:type, :primary_key, :allow_null, :ruby_default)]}.must_equal expected_schema end end it "should create a temporary table" do DB.create_table! :test_tmp, :temp => true do varchar2 :name, :size => 50 primary_key :id, :null => false index :name, :unique => true end DB.drop_table?(:test_tmp) end it "should return the correct record count" do @d.count.must_equal 0 @d.insert(:name => 'abc', :value => 123) @d.insert(:name => 'abc', :value => 456) @d.insert(:name => 'def', :value => 789) @d.count.must_equal 3 end it "should return the correct records" do @d.to_a.must_equal [] @d.insert(:name => 'abc', :value => 123) @d.insert(:name => 'abc', :value => 456) @d.insert(:name => 'def', :value => 789) @d.order(:value).to_a.must_equal [ {:date_created=>nil, :name => 'abc', :value => 123}, {:date_created=>nil, :name => 'abc', :value => 456}, {:date_created=>nil, :name => 'def', :value => 789} ] @d.select(:name).distinct.order_by(:name).to_a.must_equal [ {:name => 'abc'}, {:name => 'def'} ] @d.order(Sequel.desc(:value)).limit(1).to_a.must_equal [ {:date_created=>nil, :name => 'def', :value => 789} ] @d.filter(:name => 'abc').order(:value).to_a.must_equal [ {:date_created=>nil, :name => 'abc', :value => 123}, {:date_created=>nil, :name => 'abc', :value => 456} ] @d.order(Sequel.desc(:value)).filter(:name => 'abc').to_a.must_equal [ {:date_created=>nil, :name => 'abc', :value => 456}, {:date_created=>nil, :name => 'abc', :value => 123} ] @d.filter(:name => 'abc').order(:value).limit(1).to_a.must_equal [ {:date_created=>nil, :name => 'abc', :value => 123} ] @d.filter(:name => 'abc').order(Sequel.desc(:value)).limit(1).to_a.must_equal [ {:date_created=>nil, :name => 'abc', :value => 456} ] @d.filter(:name => 'abc').order(:value).limit(1).to_a.must_equal [ {:date_created=>nil, :name => 'abc', :value => 123} ] @d.order(:value).limit(1).to_a.must_equal [ {:date_created=>nil, :name => 'abc', :value => 123} ] @d.order(:value).limit(1, 1).to_a.must_equal [ {:date_created=>nil, :name => 'abc', :value => 456} ] @d.order(:value).limit(1, 2).to_a.must_equal [ {:date_created=>nil, :name => 'def', :value => 789} ] @d.avg(:value).to_i.must_equal((789+123+456)/3) @d.max(:value).to_i.must_equal 789 @d.select(:name, Sequel.function(:AVG, :value).as(:avg)).filter(:name => 'abc').group(:name).to_a.must_equal [ {:name => 'abc', :avg => (456+123)/2.0} ] @d.select(Sequel.function(:AVG, :value).as(:avg)).group(:name).order(:name).limit(1).to_a.must_equal [ {:avg => (456+123)/2.0} ] @d.select(:name, Sequel.function(:AVG, :value).as(:avg)).group(:name).order(:name).to_a.must_equal [ {:name => 'abc', :avg => (456+123)/2.0}, {:name => 'def', :avg => 789*1.0} ] @d.select(:name, Sequel.function(:AVG, :value).as(:avg)).group(:name).order(:name).to_a.must_equal [ {:name => 'abc', :avg => (456+123)/2.0}, {:name => 'def', :avg => 789*1.0} ] @d.select(:name, Sequel.function(:AVG, :value).as(:avg)).group(:name).having(:name => ['abc', 'def']).order(:name).to_a.must_equal [ {:name => 'abc', :avg => (456+123)/2.0}, {:name => 'def', :avg => 789*1.0} ] @d.select(:name, :value).filter(:name => 'abc').union(@d.select(:name, :value).filter(:name => 'def')).order(:value).to_a.must_equal [ {:name => 'abc', :value => 123}, {:name => 'abc', :value => 456}, {:name => 'def', :value => 789} ] end it "should update records correctly" do @d.insert(:name => 'abc', :value => 123) @d.insert(:name => 'abc', :value => 456) @d.insert(:name => 'def', :value => 789) @d.filter(:name => 'abc').update(:value => 530) @d[:name => 'def'][:value].must_equal 789 @d.filter(:value => 530).count.must_equal 2 end it "should translate values correctly" do @d.insert(:name => 'abc', :value => 456) @d.insert(:name => 'def', :value => 789) @d.filter{value > 500}.update(:date_created => Sequel.lit("to_timestamp('2009-09-09', 'YYYY-MM-DD')")) @d[:name => 'def'][:date_created].strftime('%F').must_equal '2009-09-09' end it "should delete records correctly" do @d.insert(:name => 'abc', :value => 123) @d.insert(:name => 'abc', :value => 456) @d.insert(:name => 'def', :value => 789) @d.filter(:name => 'abc').delete @d.count.must_equal 1 @d.first[:name].must_equal 'def' end it "should be able to literalize booleans" do @d.literal(true) @d.literal(false) end it "should support transactions" do DB.transaction do @d.insert(:name => 'abc', :value => 1) end @d.count.must_equal 1 end it "should return correct result" do @d1 = DB[:books] @d1.delete @d1.insert(:id => 1, :title => 'aaa', :category_id => 100) @d1.insert(:id => 2, :title => 'bbb', :category_id => 100) @d1.insert(:id => 3, :title => 'ccc', :category_id => 101) @d1.insert(:id => 4, :title => 'ddd', :category_id => 102) @d2 = DB[:categories] @d2.delete @d2.insert(:id => 100, :cat_name => 'ruby') @d2.insert(:id => 101, :cat_name => 'rails') @d1.join(:categories, :id => :category_id).select(Sequel[:books][:id], :title, :cat_name).order(Sequel[:books][:id]).to_a.must_equal [ {:id => 1, :title => 'aaa', :cat_name => 'ruby'}, {:id => 2, :title => 'bbb', :cat_name => 'ruby'}, {:id => 3, :title => 'ccc', :cat_name => 'rails'} ] @d1.join(:categories, :id => :category_id).select(Sequel[:books][:id], :title, :cat_name).order(Sequel[:books][:id]).limit(2, 1).to_a.must_equal [ {:id => 2, :title => 'bbb', :cat_name => 'ruby'}, {:id => 3, :title => 'ccc', :cat_name => 'rails'}, ] @d1.left_outer_join(:categories, :id => :category_id).select(Sequel[:books][:id], :title, :cat_name).order(Sequel[:books][:id]).to_a.must_equal [ {:id => 1, :title => 'aaa', :cat_name => 'ruby'}, {:id => 2, :title => 'bbb', :cat_name => 'ruby'}, {:id => 3, :title => 'ccc', :cat_name => 'rails'}, {:id => 4, :title => 'ddd', :cat_name => nil} ] @d1.left_outer_join(:categories, :id => :category_id).select(Sequel[:books][:id], :title, :cat_name).reverse_order(Sequel[:books][:id]).limit(2, 0).to_a.must_equal [ {:id => 4, :title => 'ddd', :cat_name => nil}, {:id => 3, :title => 'ccc', :cat_name => 'rails'} ] end it "should allow columns to be renamed" do @d1 = DB[:books] @d1.delete @d1.insert(:id => 1, :title => 'aaa', :category_id => 100) @d1.insert(:id => 2, :title => 'bbb', :category_id => 100) @d1.insert(:id => 3, :title => 'bbb', :category_id => 100) @d1.select(Sequel.as(:title, :name)).order_by(:id).to_a.must_equal [ { :name => 'aaa' }, { :name => 'bbb' }, { :name => 'bbb' }, ] DB[:books].select(:title).group_by(:title).count.must_equal 2 end end describe "An Oracle database with xml types" do before(:all) do DB.create_table!(:xml_test){xmltype :xml_col} end after(:all) do DB.drop_table(:xml_test) end it "should work correctly with temporary clobs" do DB[:xml_test].insert("c") DB.from(Sequel.lit('xml_test x')).select(Sequel.lit("x.xml_col.getCLOBVal() v")).all.must_equal [{:v=>"c\n"}] end end describe "Clob Bound Argument Type" do before(:all) do @db = DB @db.create_table!(:items) do primary_key :id clob :c end @ds = @db[:items] end before do @ds.delete end after(:all) do @db.drop_table?(:items) end it "should handle clob type in prepared statement arguments" do @ds.delete clob = "\"'[]`a0 " @ds.prepare(:insert, :ps_clob, {:c=>@db.adapter_scheme == :oracle ? :$c__clob : :$c}).call(:c=>clob) @ds.get(:c).must_equal clob end end describe "CLOB Returning Procedure" do before do DB.run < [[nil, 'clob']]}) {|c| c[1].read } res.must_equal 'Hello World CLOB OUT parameter' end end if DB.adapter_scheme == :oracle