activerecord-oracle_enhanced-adapter 1.1.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord-oracle_enhanced-adapter might be problematic. Click here for more details.

data/History.txt CHANGED
@@ -1,3 +1,13 @@
1
+ == 1.1.1 2008-06-28
2
+
3
+ * Enhancements:
4
+ * Added ignore_table_columns option
5
+ * Added support for TIMESTAMP columns (without fractional seconds)
6
+ * NLS_DATE_FORMAT and NLS_TIMESTAMP_FORMAT independent DATE and TIMESTAMP columns support
7
+ * Bug fixes:
8
+ * Checks if CGI::Session::ActiveRecordStore::Session does not have enhanced_write_lobs callback before adding it
9
+ (Rails 2.0 does not add this callback, Rails 2.1 does)
10
+
1
11
  == 1.1.0 2008-05-05
2
12
 
3
13
  * Forked from original activerecord-oracle-adapter-1.0.0.9216
@@ -11,6 +21,3 @@
11
21
  * Added emulate_dates_by_column_name option
12
22
  * Added emulate_integers_by_column_name option
13
23
  * Added emulate_booleans_from_strings option
14
-
15
-
16
-
data/README.txt CHANGED
@@ -27,14 +27,19 @@ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_
27
27
  * set to true if columns with ID at the end of column name should be emulated as Fixnum (and not as BigDecimal which is default)
28
28
  ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_integers_by_column_name = true
29
29
 
30
- * set to true if CHAR(1), VARCHAR2(1) columns or or VARCHAR2 columns with FLAG or YN at the end of their name
30
+ * set to true if CHAR(1), VARCHAR2(1) columns or VARCHAR2 columns with FLAG or YN at the end of their name
31
31
  should be emulated as booleans (and do not use NUMBER(1) as type for booleans which is default)
32
32
  ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = true
33
33
 
34
+ The following model class definitions are available:
35
+ * specify which table columns should be ignored by ActiveRecord
36
+ ignore_table_columns :column1, :column2, :column3
37
+
38
+ See History.txt for other enhancements to original Oracle adapter.
34
39
 
35
40
  == REQUIREMENTS:
36
41
 
37
- * Works with ActiveRecord version 2.0 (which is included in Rails 2.0)
42
+ * Works with ActiveRecord version 2.0 and 2.1 (which is included in Rails 2.0 and 2.1)
38
43
  * Requires ruby-oci8 library to connect to Oracle
39
44
 
40
45
  == INSTALL:
@@ -39,6 +39,12 @@ end if defined?(RAILS_ROOT)
39
39
  begin
40
40
  require_library_or_gem 'oci8' unless self.class.const_defined? :OCI8
41
41
 
42
+ # RSI: added mapping for TIMESTAMP / WITH TIME ZONE / LOCAL TIME ZONE types
43
+ # currently Ruby-OCI8 does not support fractional seconds for timestamps
44
+ OCI8::BindType::Mapping[OCI8::SQLT_TIMESTAMP] = OCI8::BindType::OraDate
45
+ OCI8::BindType::Mapping[OCI8::SQLT_TIMESTAMP_TZ] = OCI8::BindType::OraDate
46
+ OCI8::BindType::Mapping[OCI8::SQLT_TIMESTAMP_LTZ] = OCI8::BindType::OraDate
47
+
42
48
  module ActiveRecord
43
49
  class Base
44
50
  def self.oracle_enhanced_connection(config) #:nodoc:
@@ -46,6 +52,11 @@ begin
46
52
  ConnectionAdapters::OracleEnhancedAdapter.new OCI8EnhancedAutoRecover.new(config), logger
47
53
  end
48
54
 
55
+ # RSI: specify table columns which should be ifnored
56
+ def self.ignore_table_columns(*args)
57
+ connection.ignore_table_columns(table_name,*args)
58
+ end
59
+
49
60
  # After setting large objects to empty, select the OCI8::LOB
50
61
  # and write back the data.
51
62
  after_save :enhanced_write_lobs
@@ -87,6 +98,7 @@ begin
87
98
  when /date/i
88
99
  return :date if OracleEnhancedAdapter.emulate_dates_by_column_name && OracleEnhancedAdapter.is_date_column?(name)
89
100
  :datetime
101
+ when /timestamp/i then :timestamp
90
102
  when /time/i then :datetime
91
103
  when /decimal|numeric|number/i
92
104
  return :integer if extract_scale(field_type) == 0
@@ -187,7 +199,9 @@ begin
187
199
  :float => { :name => "NUMBER" },
188
200
  :decimal => { :name => "DECIMAL" },
189
201
  :datetime => { :name => "DATE" },
190
- :timestamp => { :name => "DATE" },
202
+ # RSI: changed to native TIMESTAMP type
203
+ # :timestamp => { :name => "DATE" },
204
+ :timestamp => { :name => "TIMESTAMP" },
191
205
  :time => { :name => "DATE" },
192
206
  :date => { :name => "DATE" },
193
207
  :binary => { :name => "BLOB" },
@@ -221,8 +235,20 @@ begin
221
235
  end
222
236
 
223
237
  def quote(value, column = nil) #:nodoc:
224
- if value && column && [:text, :binary].include?(column.type)
225
- %Q{empty_#{ column.sql_type.downcase rescue 'blob' }()}
238
+ if value && column
239
+ case column.type
240
+ when :text, :binary
241
+ %Q{empty_#{ column.sql_type.downcase rescue 'blob' }()}
242
+ # RSI: TIMESTAMP support
243
+ when :timestamp
244
+ # add up to 9 digits of fractional seconds to inserted time
245
+ "TO_TIMESTAMP('#{value.to_s(:db)}.#{("%.9f"%value.to_f).split('.')[1]}','YYYY-MM-DD HH24:MI:SS:FF9')"
246
+ # RSI: NLS_DATE_FORMAT independent DATE support
247
+ when :date, :time, :datetime
248
+ "TO_DATE('#{value.to_s(:db)}','YYYY-MM-DD HH24:MI:SS')"
249
+ else
250
+ super
251
+ end
226
252
  else
227
253
  super
228
254
  end
@@ -384,8 +410,24 @@ begin
384
410
 
385
411
  indexes
386
412
  end
387
-
413
+
414
+ # RSI: set ignored columns for table
415
+ def ignore_table_columns(table_name, *args)
416
+ @ignore_table_columns ||= {}
417
+ @ignore_table_columns[table_name] ||= []
418
+ @ignore_table_columns[table_name] += args.map{|a| a.to_s.downcase}
419
+ @ignore_table_columns[table_name].uniq!
420
+ end
421
+
422
+ def ignored_table_columns(table_name)
423
+ @ignore_table_columns ||= {}
424
+ @ignore_table_columns[table_name]
425
+ end
426
+
388
427
  def columns(table_name, name = nil) #:nodoc:
428
+ # RSI: get ignored_columns by original table name
429
+ ignored_columns = ignored_table_columns(table_name)
430
+
389
431
  (owner, table_name) = @connection.describe(table_name)
390
432
 
391
433
  table_cols = <<-SQL
@@ -402,7 +444,10 @@ begin
402
444
  order by column_id
403
445
  SQL
404
446
 
405
- select_all(table_cols, name).map do |row|
447
+ # RSI: added deletion of ignored columns
448
+ select_all(table_cols, name).delete_if do |row|
449
+ ignored_columns && ignored_columns.include?(row['name'].downcase)
450
+ end.map do |row|
406
451
  limit, scale = row['limit'], row['scale']
407
452
  if limit || scale
408
453
  row['sql_type'] << "(#{(limit || 38).to_i}" + ((scale = scale.to_i) > 0 ? ",#{scale})" : ")")
@@ -794,7 +839,8 @@ end
794
839
 
795
840
  # RSI: Added LOB writing callback for sessions stored in database
796
841
  # Otherwise it is not working as Session class is defined before OracleAdapter is loaded in Rails 2.0
797
- if defined?(CGI::Session::ActiveRecordStore::Session)
842
+ if defined?(CGI::Session::ActiveRecordStore::Session) &&
843
+ CGI::Session::ActiveRecordStore::Session.after_save_callback_chain.detect{|cb| cb.method == :enhanced_write_lobs}.nil?
798
844
  class CGI::Session::ActiveRecordStore::Session
799
845
  after_save :enhanced_write_lobs
800
846
  end
@@ -3,7 +3,7 @@ module ActiveRecord #:nodoc:
3
3
  module OracleEnhancedVersion #:nodoc:
4
4
  MAJOR = 1
5
5
  MINOR = 1
6
- TINY = 0
6
+ TINY = 1
7
7
 
8
8
  STRING = [MAJOR, MINOR, TINY].join('.')
9
9
  end
@@ -63,6 +63,7 @@ describe "OracleEnhancedAdapter database session store" do
63
63
  id NUMBER(38,0) NOT NULL,
64
64
  session_id VARCHAR2(255) DEFAULT NULL,
65
65
  data CLOB DEFAULT NULL,
66
+ created_at DATE DEFAULT NULL,
66
67
  updated_at DATE DEFAULT NULL,
67
68
  PRIMARY KEY (ID)
68
69
  )
@@ -83,12 +84,27 @@ describe "OracleEnhancedAdapter database session store" do
83
84
  end
84
85
 
85
86
  it "should save session data" do
86
- @session = CGI::Session::ActiveRecordStore::Session.new :session_id => "123456", :data => "something", :updated_at => Time.now
87
+ @session = CGI::Session::ActiveRecordStore::Session.new :session_id => "111111", :data => "something" #, :updated_at => Time.now
87
88
  @session.save!
88
- @session = CGI::Session::ActiveRecordStore::Session.find_by_session_id("123456")
89
+ @session = CGI::Session::ActiveRecordStore::Session.find_by_session_id("111111")
89
90
  @session.data.should == "something"
90
91
  end
91
92
 
93
+ it "should change session data when partial updates enabled" do
94
+ CGI::Session::ActiveRecordStore::Session.partial_updates = true
95
+ @session = CGI::Session::ActiveRecordStore::Session.new :session_id => "222222", :data => "something" #, :updated_at => Time.now
96
+ @session.save!
97
+ @session = CGI::Session::ActiveRecordStore::Session.find_by_session_id("222222")
98
+ @session.data = "other thing"
99
+ @session.save!
100
+ @session = CGI::Session::ActiveRecordStore::Session.find_by_session_id("222222")
101
+ @session.data.should == "other thing"
102
+ end
103
+
104
+ it "should have one enhanced_write_lobs callback" do
105
+ CGI::Session::ActiveRecordStore::Session.after_save_callback_chain.select{|cb| cb.method == :enhanced_write_lobs}.should have(1).record
106
+ end
107
+
92
108
  end
93
109
 
94
110
  describe "OracleEnhancedAdapter date type detection based on column names" do
@@ -448,3 +464,239 @@ describe "OracleEnhancedAdapter boolean type detection based on string column ty
448
464
 
449
465
  end
450
466
 
467
+
468
+ describe "OracleEnhancedAdapter ignore specified table columns" do
469
+ before(:all) do
470
+ ActiveRecord::Base.establish_connection(:adapter => "oracle_enhanced",
471
+ :database => "xe",
472
+ :username => "hr",
473
+ :password => "hr")
474
+ @conn = ActiveRecord::Base.connection
475
+ @conn.execute <<-SQL
476
+ CREATE TABLE test_employees (
477
+ id NUMBER,
478
+ first_name VARCHAR2(20),
479
+ last_name VARCHAR2(25),
480
+ email VARCHAR2(25),
481
+ phone_number VARCHAR2(20),
482
+ hire_date DATE,
483
+ job_id NUMBER,
484
+ salary NUMBER,
485
+ commission_pct NUMBER(2,2),
486
+ manager_id NUMBER(6),
487
+ department_id NUMBER(4,0),
488
+ created_at DATE
489
+ )
490
+ SQL
491
+ @conn.execute <<-SQL
492
+ CREATE SEQUENCE test_employees_seq MINVALUE 1
493
+ INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER NOCYCLE
494
+ SQL
495
+ end
496
+
497
+ after(:all) do
498
+ @conn.execute "DROP TABLE test_employees"
499
+ @conn.execute "DROP SEQUENCE test_employees_seq"
500
+ end
501
+
502
+ after(:each) do
503
+ Object.send(:remove_const, "TestEmployee")
504
+ end
505
+
506
+ it "should ignore specified table columns" do
507
+ class TestEmployee < ActiveRecord::Base
508
+ ignore_table_columns :phone_number, :hire_date
509
+ end
510
+ TestEmployee.connection.columns('test_employees').select{|c| ['phone_number','hire_date'].include?(c.name) }.should be_empty
511
+ end
512
+
513
+ it "should ignore specified table columns specified in several lines" do
514
+ class TestEmployee < ActiveRecord::Base
515
+ ignore_table_columns :phone_number
516
+ ignore_table_columns :hire_date
517
+ end
518
+ TestEmployee.connection.columns('test_employees').select{|c| ['phone_number','hire_date'].include?(c.name) }.should be_empty
519
+ end
520
+
521
+ it "should not ignore unspecified table columns" do
522
+ class TestEmployee < ActiveRecord::Base
523
+ ignore_table_columns :phone_number, :hire_date
524
+ end
525
+ TestEmployee.connection.columns('test_employees').select{|c| c.name == 'email' }.should_not be_empty
526
+ end
527
+
528
+
529
+ end
530
+
531
+
532
+ describe "OracleEnhancedAdapter timestamp with timezone support" do
533
+ before(:all) do
534
+ ActiveRecord::Base.establish_connection(:adapter => "oracle_enhanced",
535
+ :database => "xe",
536
+ :username => "hr",
537
+ :password => "hr")
538
+ @conn = ActiveRecord::Base.connection
539
+ @conn.execute <<-SQL
540
+ CREATE TABLE test_employees (
541
+ employee_id NUMBER(6,0),
542
+ first_name VARCHAR2(20),
543
+ last_name VARCHAR2(25),
544
+ email VARCHAR2(25),
545
+ phone_number VARCHAR2(20),
546
+ hire_date DATE,
547
+ job_id NUMBER(6,0),
548
+ salary NUMBER(8,2),
549
+ commission_pct NUMBER(2,2),
550
+ manager_id NUMBER(6,0),
551
+ department_id NUMBER(4,0),
552
+ created_at TIMESTAMP,
553
+ created_at_tz TIMESTAMP WITH TIME ZONE,
554
+ created_at_ltz TIMESTAMP WITH LOCAL TIME ZONE
555
+ )
556
+ SQL
557
+ @conn.execute <<-SQL
558
+ CREATE SEQUENCE test_employees_seq MINVALUE 1
559
+ INCREMENT BY 1 CACHE 20 NOORDER NOCYCLE
560
+ SQL
561
+ end
562
+
563
+ after(:all) do
564
+ @conn.execute "DROP TABLE test_employees"
565
+ @conn.execute "DROP SEQUENCE test_employees_seq"
566
+ end
567
+
568
+ it "should set TIMESTAMP columns type as datetime" do
569
+ columns = @conn.columns('test_employees')
570
+ ts_columns = columns.select{|c| c.name =~ /created_at/}
571
+ ts_columns.each {|c| c.type.should == :timestamp}
572
+ end
573
+
574
+ describe "/ TIMESTAMP WITH TIME ZONE values from ActiveRecord model" do
575
+ before(:all) do
576
+ class TestEmployee < ActiveRecord::Base
577
+ set_primary_key :employee_id
578
+ end
579
+ end
580
+
581
+ after(:all) do
582
+ Object.send(:remove_const, "TestEmployee")
583
+ end
584
+
585
+ it "should return Time value from TIMESTAMP columns" do
586
+ # currently fractional seconds are not retrieved from database
587
+ @now = Time.local(2008,5,26,23,11,11,0)
588
+ @employee = TestEmployee.create(
589
+ :created_at => @now,
590
+ :created_at_tz => @now,
591
+ :created_at_ltz => @now
592
+ )
593
+ @employee.reload
594
+ [:created_at, :created_at_tz, :created_at_ltz].each do |c|
595
+ @employee.send(c).class.should == Time
596
+ @employee.send(c).to_f.should == @now.to_f
597
+ end
598
+ end
599
+
600
+ it "should return Time value without fractional seconds from TIMESTAMP columns" do
601
+ # currently fractional seconds are not retrieved from database
602
+ @now = Time.local(2008,5,26,23,11,11,10)
603
+ @employee = TestEmployee.create(
604
+ :created_at => @now,
605
+ :created_at_tz => @now,
606
+ :created_at_ltz => @now
607
+ )
608
+ @employee.reload
609
+ [:created_at, :created_at_tz, :created_at_ltz].each do |c|
610
+ @employee.send(c).class.should == Time
611
+ @employee.send(c).to_f.should == @now.to_f.to_i.to_f # remove fractional seconds
612
+ end
613
+ end
614
+
615
+ end
616
+
617
+ end
618
+
619
+
620
+ describe "OracleEnhancedAdapter date and timestamp with different NLS date formats" do
621
+ before(:all) do
622
+ ActiveRecord::Base.establish_connection(:adapter => "oracle_enhanced",
623
+ :database => "xe",
624
+ :username => "hr",
625
+ :password => "hr")
626
+ @conn = ActiveRecord::Base.connection
627
+ @conn.execute <<-SQL
628
+ CREATE TABLE test_employees (
629
+ employee_id NUMBER(6,0),
630
+ first_name VARCHAR2(20),
631
+ last_name VARCHAR2(25),
632
+ email VARCHAR2(25),
633
+ phone_number VARCHAR2(20),
634
+ hire_date DATE,
635
+ job_id NUMBER(6,0),
636
+ salary NUMBER(8,2),
637
+ commission_pct NUMBER(2,2),
638
+ manager_id NUMBER(6,0),
639
+ department_id NUMBER(4,0),
640
+ created_at DATE,
641
+ created_at_ts TIMESTAMP
642
+ )
643
+ SQL
644
+ @conn.execute <<-SQL
645
+ CREATE SEQUENCE test_employees_seq MINVALUE 1
646
+ INCREMENT BY 1 CACHE 20 NOORDER NOCYCLE
647
+ SQL
648
+ class TestEmployee < ActiveRecord::Base
649
+ set_primary_key :employee_id
650
+ end
651
+ # @conn.execute %q{alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS'}
652
+ @conn.execute %q{alter session set nls_date_format = 'DD-MON-YYYY HH24:MI:SS'}
653
+ # @conn.execute %q{alter session set nls_timestamp_format = 'YYYY-MM-DD HH24:MI:SS'}
654
+ @conn.execute %q{alter session set nls_timestamp_format = 'DD-MON-YYYY HH24:MI:SS'}
655
+ end
656
+
657
+ after(:all) do
658
+ Object.send(:remove_const, "TestEmployee")
659
+ @conn.execute "DROP TABLE test_employees"
660
+ @conn.execute "DROP SEQUENCE test_employees_seq"
661
+ end
662
+
663
+ before(:each) do
664
+ @today = Date.new(2008,6,28)
665
+ @now = Time.local(2008,6,28,13,34,33)
666
+ @employee = TestEmployee.create(
667
+ :first_name => "First",
668
+ :last_name => "Last",
669
+ :hire_date => @today,
670
+ :created_at => @now,
671
+ :created_at_ts => @now
672
+ )
673
+ end
674
+
675
+ it "should return Time value from DATE column if emulate_dates_by_column_name is false" do
676
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = false
677
+ @employee.reload
678
+ @employee.hire_date.class.should == Time
679
+ @employee.hire_date.should == @today.to_time
680
+ end
681
+
682
+ it "should return Date value from DATE column if column name contains 'date' and emulate_dates_by_column_name is true" do
683
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = true
684
+ @employee.reload
685
+ @employee.hire_date.class.should == Date
686
+ @employee.hire_date.should == @today
687
+ end
688
+
689
+ it "should return Time value from DATE column if column name does not contain 'date' and emulate_dates_by_column_name is true" do
690
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = true
691
+ @employee.reload
692
+ @employee.created_at.class.should == Time
693
+ @employee.created_at.should == @now
694
+ end
695
+
696
+ it "should return Time value from TIMESTAMP columns" do
697
+ @employee.reload
698
+ @employee.created_at_ts.class.should == Time
699
+ @employee.created_at_ts.should == @now
700
+ end
701
+
702
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-oracle_enhanced-adapter
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Raimonds Simanovskis
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-05-13 00:00:00 +03:00
12
+ date: 2008-06-28 00:00:00 +03:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -58,7 +58,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
58
58
  requirements: []
59
59
 
60
60
  rubyforge_project: oracle-enhanced
61
- rubygems_version: 1.0.1
61
+ rubygems_version: 1.2.0
62
62
  signing_key:
63
63
  specification_version: 2
64
64
  summary: Oracle enhaced adapter for Active Record