Skip to content

Commit 5ae82ad

Browse files
yahondaclaude
andcommitted
Use thin-style service name syntax for JDBC connections
Change the default JDBC connection URL format from SID syntax (jdbc:oracle:thin:@host:port:DB) to service name syntax (jdbc:oracle:thin:@//host:port/DB), which is required for Oracle 12c+ with pluggable databases (PDB). - Extract jdbc_connection_url method for testability - Skip TNS-alias path when database starts with `/` or `:` so that explicit service-name/SID syntax is respected even when TNS_ADMIN is set - Raise ArgumentError when both :database and :url are missing - Add specs for all JDBC URL generation paths - Document JRuby JDBC connection options in README Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 39cf870 commit 5ae82ad

File tree

6 files changed

+113
-9
lines changed

6 files changed

+113
-9
lines changed

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,22 @@ plsql.activerecord_class = ActiveRecord::Base
120120
and then you do not need to specify plsql.connection (this is also safer when ActiveRecord reestablishes connection to database).
121121

122122

123+
### JRuby JDBC connection:
124+
125+
When using JRuby, the `connect!` method with `:host` and `:database` options uses the thin-style service name syntax by default:
126+
127+
```ruby
128+
# Connects using service name syntax: jdbc:oracle:thin:@//localhost:1521/MYSERVICENAME
129+
plsql.connect! username: "hr", password: "hr", host: "localhost", database: "MYSERVICENAME"
130+
```
131+
132+
If you need to connect using the legacy SID syntax (for Oracle databases older than 12c), prefix the database name with a colon:
133+
134+
```ruby
135+
# Connects using SID syntax: jdbc:oracle:thin:@localhost:1521:MYSID
136+
plsql.connect! username: "hr", password: "hr", host: "localhost", database: ":MYSID"
137+
```
138+
123139
### Cheat Sheet:
124140

125141
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

lib/plsql/jdbc_connection.rb

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,31 @@
4848
module PLSQL
4949
class JDBCConnection < Connection # :nodoc:
5050
def self.create_raw(params)
51+
url = jdbc_connection_url(params)
52+
new(java.sql.DriverManager.getConnection(url, params[:username], params[:password]))
53+
end
54+
55+
def self.jdbc_connection_url(params)
5156
database = params[:database]
52-
url = if ENV["TNS_ADMIN"] && database && !params[:host] && !params[:url]
57+
if ENV["TNS_ADMIN"] && database && database !~ %r{\A[:/]} && !params[:host] && !params[:url]
5358
"jdbc:oracle:thin:@#{database}"
5459
else
55-
database = ":#{database}" unless database.match(/^(\:|\/)/)
56-
params[:url] || "jdbc:oracle:thin:@#{params[:host] || 'localhost'}:#{params[:port] || 1521}#{database}"
60+
return params[:url] if params[:url]
61+
62+
raise ArgumentError, "database or url option is required" if database.nil? || database.empty?
63+
64+
host = params[:host] || "localhost"
65+
port = params[:port] || 1521
66+
67+
if database =~ /^:/
68+
# SID syntax: jdbc:oracle:thin:@host:port:SID
69+
"jdbc:oracle:thin:@#{host}:#{port}#{database}"
70+
else
71+
# service name syntax: jdbc:oracle:thin:@//host:port/service_name
72+
database = "/#{database}" unless database =~ /^\//
73+
"jdbc:oracle:thin:@//#{host}:#{port}#{database}"
74+
end
5775
end
58-
new(java.sql.DriverManager.getConnection(url, params[:username], params[:password]))
5976
end
6077

6178
def set_time_zone(time_zone = nil)

lib/plsql/schema.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def raw_connection=(raw_conn) # :nodoc:
4141
# or
4242
#
4343
# plsql.connection = java.sql.DriverManager.getConnection(
44-
# "jdbc:oracle:thin:@#{database_host}:#{database_port}/#{database_service_name}",
44+
# "jdbc:oracle:thin:@//#{database_host}:#{database_port}/#{database_service_name}",
4545
# database_user, database_password)
4646
#
4747
def connection=(conn)

spec/plsql/connection_spec.rb

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,78 @@
467467

468468
end
469469

470+
describe "JDBC connection URL" do
471+
it "should use service name syntax by default" do
472+
url = PLSQL::JDBCConnection.jdbc_connection_url(host: "myhost", port: 1521, database: "MYSERVICENAME")
473+
expect(url).to eq "jdbc:oracle:thin:@//myhost:1521/MYSERVICENAME"
474+
end
475+
476+
it "should use default host and port when not specified" do
477+
original_tns_admin = ENV.delete("TNS_ADMIN")
478+
begin
479+
url = PLSQL::JDBCConnection.jdbc_connection_url(database: "/MYSERVICENAME")
480+
expect(url).to eq "jdbc:oracle:thin:@//localhost:1521/MYSERVICENAME"
481+
ensure
482+
ENV["TNS_ADMIN"] = original_tns_admin
483+
end
484+
end
485+
486+
it "should use SID syntax when database starts with colon" do
487+
url = PLSQL::JDBCConnection.jdbc_connection_url(host: "myhost", port: 1521, database: ":MYSID")
488+
expect(url).to eq "jdbc:oracle:thin:@myhost:1521:MYSID"
489+
end
490+
491+
it "should use service name syntax when database starts with slash" do
492+
url = PLSQL::JDBCConnection.jdbc_connection_url(host: "myhost", port: 1521, database: "/MYSERVICENAME")
493+
expect(url).to eq "jdbc:oracle:thin:@//myhost:1521/MYSERVICENAME"
494+
end
495+
496+
it "should use TNS alias when TNS_ADMIN is set and no host specified" do
497+
original_tns_admin = ENV["TNS_ADMIN"]
498+
ENV["TNS_ADMIN"] = "/path/to/tns"
499+
begin
500+
url = PLSQL::JDBCConnection.jdbc_connection_url(database: "MYALIAS")
501+
expect(url).to eq "jdbc:oracle:thin:@MYALIAS"
502+
ensure
503+
ENV["TNS_ADMIN"] = original_tns_admin
504+
end
505+
end
506+
507+
it "should use service name syntax when TNS_ADMIN is set and database starts with slash" do
508+
original_tns_admin = ENV["TNS_ADMIN"]
509+
ENV["TNS_ADMIN"] = "/path/to/tns"
510+
begin
511+
url = PLSQL::JDBCConnection.jdbc_connection_url(database: "/MYSERVICENAME")
512+
expect(url).to eq "jdbc:oracle:thin:@//localhost:1521/MYSERVICENAME"
513+
ensure
514+
ENV["TNS_ADMIN"] = original_tns_admin
515+
end
516+
end
517+
518+
it "should use SID syntax when TNS_ADMIN is set and database starts with colon" do
519+
original_tns_admin = ENV["TNS_ADMIN"]
520+
ENV["TNS_ADMIN"] = "/path/to/tns"
521+
begin
522+
url = PLSQL::JDBCConnection.jdbc_connection_url(database: ":MYSID")
523+
expect(url).to eq "jdbc:oracle:thin:@localhost:1521:MYSID"
524+
ensure
525+
ENV["TNS_ADMIN"] = original_tns_admin
526+
end
527+
end
528+
529+
it "should raise ArgumentError when database and url are not provided" do
530+
expect {
531+
PLSQL::JDBCConnection.jdbc_connection_url(host: "myhost")
532+
}.to raise_error(ArgumentError, /database or url option is required/)
533+
end
534+
535+
it "should use custom URL when provided" do
536+
custom_url = "jdbc:oracle:thin:@//custom:1522/MYSERVICENAME"
537+
url = PLSQL::JDBCConnection.jdbc_connection_url(host: "myhost", database: "MYSERVICENAME", url: custom_url)
538+
expect(url).to eq custom_url
539+
end
540+
end if defined?(JRuby)
541+
470542
describe "logoff" do
471543
before(:each) do
472544
# restore connection before each test

spec/spec_helper.rb

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,7 @@
4545
DATABASE_NAME = ENV["DATABASE_NAME"] || "orcl"
4646
end
4747

48-
DATABASE_SERVICE_NAME = (defined?(JRUBY_VERSION) ? "/" : "") +
49-
(ENV["DATABASE_SERVICE_NAME"] || DATABASE_NAME)
48+
DATABASE_SERVICE_NAME = ENV["DATABASE_SERVICE_NAME"] || DATABASE_NAME
5049
DATABASE_HOST = ENV["DATABASE_HOST"] || "localhost"
5150
DATABASE_PORT = (ENV["DATABASE_PORT"] || 1521).to_i
5251
DATABASE_USERS_AND_PASSWORDS = [
@@ -77,7 +76,7 @@ def get_connection_url
7776
unless defined?(JRUBY_VERSION)
7877
(ENV["DATABASE_USE_TNS"] == "NO") ? get_eazy_connect_url("/") : DATABASE_NAME
7978
else
80-
"jdbc:oracle:thin:@#{get_eazy_connect_url}"
79+
"jdbc:oracle:thin:@//#{get_eazy_connect_url("/")}"
8180
end
8281
end
8382

spec/support/test_db.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def connection
2020
Timeout::timeout(5) {
2121
if defined?(JRUBY_VERSION)
2222
@connection = java.sql.DriverManager.get_connection(
23-
"jdbc:oracle:thin:@127.0.0.1:1521/XE",
23+
"jdbc:oracle:thin:@//127.0.0.1:1521/XE",
2424
"system",
2525
"oracle"
2626
)

0 commit comments

Comments
 (0)