diff --git a/README.md b/README.md index 9279b406..4a5f084a 100644 --- a/README.md +++ b/README.md @@ -120,6 +120,22 @@ plsql.activerecord_class = ActiveRecord::Base and then you do not need to specify plsql.connection (this is also safer when ActiveRecord reestablishes connection to database). +### JRuby JDBC connection: + +When using JRuby, the `connect!` method with `:host` and `:database` options uses the thin-style service name syntax by default: + +```ruby +# Connects using service name syntax: jdbc:oracle:thin:@//localhost:1521/MYSERVICENAME +plsql.connect! username: "hr", password: "hr", host: "localhost", database: "MYSERVICENAME" +``` + +If you need to connect using the legacy SID syntax (for Oracle databases older than 12c), prefix the database name with a colon: + +```ruby +# Connects using SID syntax: jdbc:oracle:thin:@localhost:1521:MYSID +plsql.connect! username: "hr", password: "hr", host: "localhost", database: ":MYSID" +``` + ### Cheat Sheet: You may have a look at this [Cheat Sheet](http://cheatography.com/jgebal/cheat-sheets/ruby-plsql-cheat-sheet/) for instructions on how to use ruby-plsql diff --git a/lib/plsql/jdbc_connection.rb b/lib/plsql/jdbc_connection.rb index 9f479a80..162b0ee0 100644 --- a/lib/plsql/jdbc_connection.rb +++ b/lib/plsql/jdbc_connection.rb @@ -48,14 +48,31 @@ module PLSQL class JDBCConnection < Connection # :nodoc: def self.create_raw(params) + url = jdbc_connection_url(params) + new(java.sql.DriverManager.getConnection(url, params[:username], params[:password])) + end + + def self.jdbc_connection_url(params) database = params[:database] - url = if ENV["TNS_ADMIN"] && database && !params[:host] && !params[:url] + if ENV["TNS_ADMIN"] && database && database !~ %r{\A[:/]} && !params[:host] && !params[:url] "jdbc:oracle:thin:@#{database}" else - database = ":#{database}" unless database.match(/^(\:|\/)/) - params[:url] || "jdbc:oracle:thin:@#{params[:host] || 'localhost'}:#{params[:port] || 1521}#{database}" + return params[:url] if params[:url] + + raise ArgumentError, "database or url option is required" if database.nil? || database.empty? + + host = params[:host] || "localhost" + port = params[:port] || 1521 + + if database =~ /^:/ + # SID syntax: jdbc:oracle:thin:@host:port:SID + "jdbc:oracle:thin:@#{host}:#{port}#{database}" + else + # service name syntax: jdbc:oracle:thin:@//host:port/service_name + database = "/#{database}" unless database =~ /^\// + "jdbc:oracle:thin:@//#{host}:#{port}#{database}" + end end - new(java.sql.DriverManager.getConnection(url, params[:username], params[:password])) end def set_time_zone(time_zone = nil) diff --git a/lib/plsql/schema.rb b/lib/plsql/schema.rb index 4dfc1274..165811a0 100644 --- a/lib/plsql/schema.rb +++ b/lib/plsql/schema.rb @@ -41,7 +41,7 @@ def raw_connection=(raw_conn) # :nodoc: # or # # plsql.connection = java.sql.DriverManager.getConnection( - # "jdbc:oracle:thin:@#{database_host}:#{database_port}/#{database_service_name}", + # "jdbc:oracle:thin:@//#{database_host}:#{database_port}/#{database_service_name}", # database_user, database_password) # def connection=(conn) diff --git a/spec/plsql/connection_spec.rb b/spec/plsql/connection_spec.rb index 24213e64..d03e6653 100644 --- a/spec/plsql/connection_spec.rb +++ b/spec/plsql/connection_spec.rb @@ -467,6 +467,78 @@ end + describe "JDBC connection URL" do + it "should use service name syntax by default" do + url = PLSQL::JDBCConnection.jdbc_connection_url(host: "myhost", port: 1521, database: "MYSERVICENAME") + expect(url).to eq "jdbc:oracle:thin:@//myhost:1521/MYSERVICENAME" + end + + it "should use default host and port when not specified" do + original_tns_admin = ENV.delete("TNS_ADMIN") + begin + url = PLSQL::JDBCConnection.jdbc_connection_url(database: "/MYSERVICENAME") + expect(url).to eq "jdbc:oracle:thin:@//localhost:1521/MYSERVICENAME" + ensure + ENV["TNS_ADMIN"] = original_tns_admin + end + end + + it "should use SID syntax when database starts with colon" do + url = PLSQL::JDBCConnection.jdbc_connection_url(host: "myhost", port: 1521, database: ":MYSID") + expect(url).to eq "jdbc:oracle:thin:@myhost:1521:MYSID" + end + + it "should use service name syntax when database starts with slash" do + url = PLSQL::JDBCConnection.jdbc_connection_url(host: "myhost", port: 1521, database: "/MYSERVICENAME") + expect(url).to eq "jdbc:oracle:thin:@//myhost:1521/MYSERVICENAME" + end + + it "should use TNS alias when TNS_ADMIN is set and no host specified" do + original_tns_admin = ENV["TNS_ADMIN"] + ENV["TNS_ADMIN"] = "/path/to/tns" + begin + url = PLSQL::JDBCConnection.jdbc_connection_url(database: "MYALIAS") + expect(url).to eq "jdbc:oracle:thin:@MYALIAS" + ensure + ENV["TNS_ADMIN"] = original_tns_admin + end + end + + it "should use service name syntax when TNS_ADMIN is set and database starts with slash" do + original_tns_admin = ENV["TNS_ADMIN"] + ENV["TNS_ADMIN"] = "/path/to/tns" + begin + url = PLSQL::JDBCConnection.jdbc_connection_url(database: "/MYSERVICENAME") + expect(url).to eq "jdbc:oracle:thin:@//localhost:1521/MYSERVICENAME" + ensure + ENV["TNS_ADMIN"] = original_tns_admin + end + end + + it "should use SID syntax when TNS_ADMIN is set and database starts with colon" do + original_tns_admin = ENV["TNS_ADMIN"] + ENV["TNS_ADMIN"] = "/path/to/tns" + begin + url = PLSQL::JDBCConnection.jdbc_connection_url(database: ":MYSID") + expect(url).to eq "jdbc:oracle:thin:@localhost:1521:MYSID" + ensure + ENV["TNS_ADMIN"] = original_tns_admin + end + end + + it "should raise ArgumentError when database and url are not provided" do + expect { + PLSQL::JDBCConnection.jdbc_connection_url(host: "myhost") + }.to raise_error(ArgumentError, /database or url option is required/) + end + + it "should use custom URL when provided" do + custom_url = "jdbc:oracle:thin:@//custom:1522/MYSERVICENAME" + url = PLSQL::JDBCConnection.jdbc_connection_url(host: "myhost", database: "MYSERVICENAME", url: custom_url) + expect(url).to eq custom_url + end + end if defined?(JRuby) + describe "logoff" do before(:each) do # restore connection before each test diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 5b33c327..bee44ff9 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -45,8 +45,7 @@ DATABASE_NAME = ENV["DATABASE_NAME"] || "orcl" end -DATABASE_SERVICE_NAME = (defined?(JRUBY_VERSION) ? "/" : "") + - (ENV["DATABASE_SERVICE_NAME"] || DATABASE_NAME) +DATABASE_SERVICE_NAME = ENV["DATABASE_SERVICE_NAME"] || DATABASE_NAME DATABASE_HOST = ENV["DATABASE_HOST"] || "localhost" DATABASE_PORT = (ENV["DATABASE_PORT"] || 1521).to_i DATABASE_USERS_AND_PASSWORDS = [ @@ -77,7 +76,7 @@ def get_connection_url unless defined?(JRUBY_VERSION) (ENV["DATABASE_USE_TNS"] == "NO") ? get_eazy_connect_url("/") : DATABASE_NAME else - "jdbc:oracle:thin:@#{get_eazy_connect_url}" + "jdbc:oracle:thin:@//#{get_eazy_connect_url("/")}" end end diff --git a/spec/support/test_db.rb b/spec/support/test_db.rb index c03e94fa..2a0bcb5e 100644 --- a/spec/support/test_db.rb +++ b/spec/support/test_db.rb @@ -20,7 +20,7 @@ def connection Timeout::timeout(5) { if defined?(JRUBY_VERSION) @connection = java.sql.DriverManager.get_connection( - "jdbc:oracle:thin:@127.0.0.1:1521/XE", + "jdbc:oracle:thin:@//127.0.0.1:1521/XE", "system", "oracle" )