Changeset 3025
- Timestamp:
- 11/14/05 10:01:09 (3 years ago)
- Files:
-
- trunk/activerecord/CHANGELOG (modified) (2 diffs)
- trunk/activerecord/lib/active_record/connection_adapters/oci_adapter.rb (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/activerecord/CHANGELOG
r3021 r3025 1 1 *SVN* 2 2 3 * Oracle: active? and reconnect! methods for handling stale connections. Optionally retry queries after reconnect. #428 [Michael Schoen <schoenm@earthlink.net>] 4 3 5 * Correct documentation for Base.delete_all. #1568 [Newhydra] 4 6 … … 7 9 * Update documentation for Migrations. #2861 [Tom Werner <tom@cube6media.com>] 8 10 9 * When AbstractAdapter#log rescues an exception, attempt to detect and reconnect to an inactive database connection. Connection adapter must respond to the active? and reconnect! instance methods. Initial support for PostgreSQL, MySQL, and SQLite. Make certain that all statements which may need reconnection are performed within a logged block: for example, this means no avoiding log(sql, name) { } if @logger.nil? [Jeremy Kemper]11 * When AbstractAdapter#log rescues an exception, attempt to detect and reconnect to an inactive database connection. Connection adapter must respond to the active? and reconnect! instance methods. Initial support for PostgreSQL, MySQL, and SQLite. Make certain that all statements which may need reconnection are performed within a logged block: for example, this means no avoiding log(sql, name) { } if @logger.nil? #428 [Jeremy Kemper] 10 12 11 13 * Oracle: Much faster column reflection. #2848 [Michael Schoen <schoenm@earthlink.net>] trunk/activerecord/lib/active_record/connection_adapters/oci_adapter.rb
r3019 r3025 24 24 25 25 require 'active_record/connection_adapters/abstract_adapter' 26 require 'delegate' 26 27 27 28 begin … … 31 32 class Base 32 33 def self.oci_connection(config) #:nodoc: 33 conn = OCI8.new config[:username], config[:password], config[:host] 34 conn.exec %q{alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS'} 35 conn.exec %q{alter session set nls_timestamp_format = 'YYYY-MM-DD HH24:MI:SS'} 36 conn.autocommit = true 37 ConnectionAdapters::OCIAdapter.new conn, logger 34 # Use OCI8AutoRecover instead of normal OCI8 driver. 35 ConnectionAdapters::OCIAdapter.new OCI8AutoRecover.new(config), logger 38 36 end 39 37 … … 214 212 215 213 214 # CONNECTION MANAGEMENT ====================================# 215 216 # Returns true if the connection is active. 217 def active? 218 # Just checks the active flag, which is set false if the last exec 219 # got an error indicating a bad connection. An alternative would be 220 # to call #ping, which is more expensive (and should always get 221 # the same result). 222 @connection.active? 223 end 224 225 # Reconnects to the database. 226 def reconnect! 227 begin 228 @connection.reset! 229 rescue OCIError => e 230 @logger.warn "#{adapter_name} automatic reconnection failed: #{e.message}" 231 end 232 end 233 234 216 235 # DATABASE STATEMENTS ====================================== 217 236 # … … 338 357 end 339 358 340 select_all(table_cols ).map do |row|359 select_all(table_cols, name).map do |row| 341 360 row['data_default'].sub!(/^'(.*)'\s*$/, '\1') if row['data_default'] 342 361 OCIColumn.new( … … 486 505 else define_a_column_pre_ar i 487 506 end 488 end 489 end 507 end 508 end 509 end 510 511 512 # The OCIConnectionFactory factors out the code necessary to connect and 513 # configure an OCI connection. 514 class OCIConnectionFactory 515 def new_connection(username, password, host) 516 conn = OCI8.new username, password, host 517 conn.exec %q{alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS'} 518 conn.exec %q{alter session set nls_timestamp_format = 'YYYY-MM-DD HH24:MI:SS'} 519 conn.autocommit = true 520 conn 521 end 522 end 523 524 525 # The OCI8AutoRecover class enhances the OCI8 driver with auto-recover and 526 # reset functionality. If a call to #exec fails, and autocommit is turned on 527 # (ie., we're not in the middle of a longer transaction), it will 528 # automatically reconnect and try again. If autocommit is turned off, 529 # this would be dangerous (as the earlier part of the implied transaction 530 # may have failed silently if the connection died) -- so instead the 531 # connection is marked as dead, to be reconnected on it's next use. 532 class OCI8AutoRecover < DelegateClass(OCI8) 533 attr_accessor :active 534 alias :active? :active 535 536 cattr_accessor :auto_retry 537 class << self 538 alias :auto_retry? :auto_retry 539 end 540 @@auto_retry = false 541 542 def initialize(config, factory = OCIConnectionFactory.new) 543 @active = true 544 @username, @password, @host = config[:username], config[:password], config[:host] 545 @factory = factory 546 @connection = @factory.new_connection @username, @password, @host 547 super @connection 548 end 549 550 # Checks connection, returns true if active. Note that ping actively 551 # checks the connection, while #active? simply returns the last 552 # known state. 553 def ping 554 @active = true 555 begin 556 @connection.commit 557 rescue 558 @active = false 559 end 560 active? 561 end 562 563 # Resets connection, by logging off and creating a new connection. 564 def reset! 565 logoff rescue nil 566 begin 567 @connection = @factory.new_connection @username, @password, @host 568 __setobj__ @connection 569 @active = true 570 rescue 571 @active = false 572 raise 573 end 574 end 575 576 # ORA-00028: your session has been killed 577 # ORA-01012: not logged on 578 # ORA-03113: end-of-file on communication channel 579 # ORA-03114: not connected to ORACLE 580 LOST_CONNECTION_ERROR_CODES = [ 28, 1012, 3113, 3114 ] 581 582 # Adds auto-recovery functionality. 583 # 584 # See: http://www.jiubao.org/ruby-oci8/api.en.html#label-11 585 def exec(sql, *bindvars) 586 should_retry = self.class.auto_retry? && autocommit? 587 588 begin 589 @connection.exec(sql, *bindvars) 590 rescue OCIError => e 591 raise unless LOST_CONNECTION_ERROR_CODES.include?(e.code) 592 @active = false 593 raise unless should_retry 594 should_retry = false 595 reset! rescue nil 596 retry 597 end 598 end 599 490 600 end 491 601