Skip to content

Commit

Permalink
- cx_Oracle.makedsn can now be passed service_name; squash
Browse files Browse the repository at this point in the history
commit of pr152
  • Loading branch information
slafs authored and zzzeek committed Apr 2, 2014
1 parent a147292 commit 3db84b1
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 2 deletions.
8 changes: 8 additions & 0 deletions doc/build/changelog/changelog_10.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@
series as well. For changes that are specific to 1.0 with an emphasis
on compatibility concerns, see :doc:`/changelog/migration_10`.

.. change::
:tags: feature, oracle
:pullreq: github:152

Added support for cx_oracle connections to a specific service
name, as opposed to a tns name, by passing ``?service_name=<name>``
to the URL. Pull request courtesy Sławomir Ehlert.

.. change::
:tags: feature, mysql
:tickets: 3155
Expand Down
22 changes: 20 additions & 2 deletions lib/sqlalchemy/dialects/oracle/cx_oracle.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@
Defaults to ``True``. Note that this is the opposite default of the
cx_Oracle DBAPI itself.
* ``service_name`` - An option to use connection string (DSN) with
``SERVICE_NAME`` instead of ``SID``. It can't be passed when a ``database``
part is given.
E.g. ``oracle+cx_oracle://scott:tiger@host:1521/?service_name=hr``
is a valid url. This value is only available as a URL query string argument.
.. _cx_oracle_unicode:
Unicode
Expand Down Expand Up @@ -862,14 +868,26 @@ def create_connect_args(self, url):
util.coerce_kw_type(dialect_opts, opt, bool)
setattr(self, opt, dialect_opts[opt])

if url.database:
database = url.database
service_name = dialect_opts.get('service_name', None)
if database or service_name:
# if we have a database, then we have a remote host
port = url.port
if port:
port = int(port)
else:
port = 1521
dsn = self.dbapi.makedsn(url.host, port, url.database)

if database and service_name:
raise exc.InvalidRequestError(
'"service_name" option shouldn\'t '
'be used with a "database" part of the url')
if database:
makedsn_kwargs = {'sid': database}
if service_name:
makedsn_kwargs = {'service_name': service_name}

dsn = self.dbapi.makedsn(url.host, port, **makedsn_kwargs)
else:
# we have a local tnsname
dsn = url.host
Expand Down
20 changes: 20 additions & 0 deletions test/dialect/test_oracle.py
Original file line number Diff line number Diff line change
Expand Up @@ -2074,3 +2074,23 @@ def test_reflection(self):
autoload_with=testing.db, oracle_resolve_synonyms=True)
eq_(list(t.c.keys()), ['id', 'data'])
eq_(list(t.primary_key), [t.c.id])


class ServiceNameTest(fixtures.TestBase):
__only_on__ = 'oracle+cx_oracle'

def test_cx_oracle_service_name(self):
url_string = 'oracle+cx_oracle://scott:tiger@host/?service_name=hr'
eng = create_engine(url_string, _initialize=False)
cargs, cparams = eng.dialect.create_connect_args(eng.url)

assert 'SERVICE_NAME=hr' in cparams['dsn']
assert 'SID=hr' not in cparams['dsn']

def test_cx_oracle_service_name_bad(self):
url_string = 'oracle+cx_oracle://scott:tiger@host/hr1?service_name=hr2'
assert_raises(
exc.InvalidRequestError,
create_engine, url_string,
_initialize=False
)

0 comments on commit 3db84b1

Please sign in to comment.