]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Repair _execute_scalar for WITH_UNICODE mode
authorMike Bayer <mike_mp@zzzcomputing.com>
Mon, 13 Mar 2017 16:27:51 +0000 (12:27 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Mon, 13 Mar 2017 18:36:45 +0000 (14:36 -0400)
cx_Oracle 5.3 seems to code this flag ON now, so
remove the warning and ensure WITH_UNICODE handling works.

Additionally, the XE setup on jenkins is having more
problems here, in particular low-connections mode is
causing cx_Oracle to fail more frequently now.  Turning
off low-connections fixes those but then we get the
TNS errors, so adding an emergency "retry" flag that
is not yet a feature available to users.  Real world
applications are not dropping/creating thousands of
tables the way our test suite is.

Change-Id: Ie95b0e697276c404d3264c2e624e870463d966d6
Fixes: #3937
doc/build/changelog/changelog_10.rst
lib/sqlalchemy/dialects/oracle/cx_oracle.py
lib/sqlalchemy/testing/provision.py
test/dialect/test_oracle.py
tox_1_1.ini

index 4b97415ea3aab1f99bfa1d9d1b733cab6c5913aa..c9d9a7fe8c49c1e860fa68a7d6ecfe60e4b23683 100644 (file)
     .. include:: changelog_07.rst
         :start-line: 5
 
+
 .. changelog::
     :version: 1.0.18
 
+    .. change:: 3937
+        :tags: bug, oracle
+        :tickets: 3937
+        :versions: 1.1.7
+
+        A fix to cx_Oracle's WITH_UNICODE mode which was uncovered by the
+        fact that cx_Oracle 5.3 now seems to hardcode this flag on in
+        the build; an internal method that uses this mode wasn't using
+        the correct signature.
+
+
+.. changelog::
+    :version: 1.0.18
+
+    .. change:: 3937
+        :tags: bug, oracle
+        :tickets: 3937
+        :versions: 1.1.7
+
+        A fix to cx_Oracle's WITH_UNICODE mode which was uncovered by the
+        fact that cx_Oracle 5.3 now seems to hardcode this flag on in
+        the build; an internal method that uses this mode wasn't using
+        the correct signature.
+
 .. changelog::
     :version: 1.0.17
     :released: January 17, 2017
index add35f24290c5ead2b8032bc756fe67ee8e497db..6b9b1b289481037e717f4580c4978804a6afaf53 100644 (file)
@@ -298,6 +298,7 @@ import random
 import collections
 import decimal
 import re
+import time
 
 
 class _OracleNumeric(sqltypes.Numeric):
@@ -606,9 +607,9 @@ class OracleExecutionContext_cx_oracle_with_unicode(
         OracleExecutionContext_cx_oracle.__init__(self, *arg, **kw)
         self.statement = util.text_type(self.statement)
 
-    def _execute_scalar(self, stmt):
+    def _execute_scalar(self, stmt, type_):
         return super(OracleExecutionContext_cx_oracle_with_unicode, self).\
-            _execute_scalar(util.text_type(stmt))
+            _execute_scalar(util.text_type(stmt), type_)
 
 
 class ReturningResultProxy(_result.FullyBufferedResultProxy):
@@ -676,7 +677,8 @@ class OracleDialect_cx_oracle(OracleDialect):
                  allow_twophase=True,
                  coerce_to_decimal=True,
                  coerce_to_unicode=False,
-                 arraysize=50, **kwargs):
+                 arraysize=50, _retry_on_12516=False,
+                 **kwargs):
         OracleDialect.__init__(self, **kwargs)
         self.threaded = threaded
         self.arraysize = arraysize
@@ -685,6 +687,7 @@ class OracleDialect_cx_oracle(OracleDialect):
             hasattr(self.dbapi, 'TIMESTAMP')
         self.auto_setinputsizes = auto_setinputsizes
         self.auto_convert_lobs = auto_convert_lobs
+        self._retry_on_12516 = _retry_on_12516
 
         if hasattr(self.dbapi, 'version'):
             self.cx_oracle_ver = tuple([int(x) for x in
@@ -732,18 +735,8 @@ class OracleDialect_cx_oracle(OracleDialect):
 
             if util.py2k:
                 # There's really no reason to run with WITH_UNICODE under
-                # Python 2.x.  Give the user a hint.
-                util.warn(
-                    "cx_Oracle is compiled under Python 2.xx using the "
-                    "WITH_UNICODE flag.  Consider recompiling cx_Oracle "
-                    "without this flag, which is in no way necessary for "
-                    "full support of Unicode. Otherwise, all string-holding "
-                    "bind parameters must be explicitly typed using "
-                    "SQLAlchemy's String type or one of its subtypes,"
-                    "or otherwise be passed as Python unicode.  "
-                    "Plain Python strings passed as bind parameters will be "
-                    "silently corrupted by cx_Oracle."
-                )
+                # Python 2.x.  However as of cx_oracle 5.3 it seems to be
+                # set to ON for default builds
                 self.execution_ctx_cls = \
                     OracleExecutionContext_cx_oracle_with_unicode
         else:
@@ -769,6 +762,22 @@ class OracleDialect_cx_oracle(OracleDialect):
         import cx_Oracle
         return cx_Oracle
 
+    def connect(self, *cargs, **cparams):
+        if self._retry_on_12516:
+            # emergency flag for the SQLAlchemy test suite, which has
+            # decreased in stability since cx_oracle 5.3; generalized
+            # "retry on connect" functionality is part of an upcoming
+            # SQLAlchemy feature
+            try:
+                return self.dbapi.connect(*cargs, **cparams)
+            except self.dbapi.DatabaseError as err:
+                if "ORA-12516" in str(err):
+                    time.sleep(2)
+                    return self.dbapi.connect(*cargs, **cparams)
+        else:
+            return super(OracleDialect_cx_oracle, self).connect(
+                *cargs, **cparams)
+
     def initialize(self, connection):
         super(OracleDialect_cx_oracle, self).initialize(connection)
         if self._is_oracle_8:
index 88d166981415662543cfd28af869ad12fd8cba7e..bb50a7ca7a984bd14776a5ce4a2612fa54fb9dc0 100644 (file)
@@ -126,6 +126,7 @@ def _mssql_update_db_opts(db_url, db_opts):
     db_opts['legacy_schema_aliasing'] = False
 
 
+
 @_follower_url_from_main.for_db("sqlite")
 def _sqlite_follower_url_from_main(url, ident):
     url = sa_url.make_url(url)
@@ -270,6 +271,11 @@ def _oracle_drop_db(cfg, eng, ident):
         _ora_drop_ignore(conn, "%s_ts2" % ident)
 
 
+@_update_db_opts.for_db("oracle")
+def _oracle_update_db_opts(db_url, db_opts):
+    db_opts['_retry_on_12516'] = True
+
+
 def reap_oracle_dbs(eng, idents_file):
     log.info("Reaping Oracle dbs...")
     with eng.connect() as conn:
index 359259b4b594935998aa5977f522979cbe19d71d..1a391642776431a1d64bd884a184d8bad00b4719 100644 (file)
@@ -1685,12 +1685,10 @@ class TypesTest(fixtures.TestBase):
     @testing.provide_metadata
     def test_reflect_nvarchar(self):
         metadata = self.metadata
-        Table('t', metadata,
-            Column('data', sqltypes.NVARCHAR(255))
-        )
+        Table('tnv', metadata, Column('data', sqltypes.NVARCHAR(255)))
         metadata.create_all()
         m2 = MetaData(testing.db)
-        t2 = Table('t', m2, autoload=True)
+        t2 = Table('tnv', m2, autoload=True)
         assert isinstance(t2.c.data.type, sqltypes.NVARCHAR)
 
         if testing.against('oracle+cx_oracle'):
index 7b683acf06ddfc99d002b6087a3d8c7ecf78cf30..299b0d6c099b006e45c53c4d905e10c7d5c5a8bb 100644 (file)
@@ -54,7 +54,7 @@ setenv=
     sqlite: SQLITE=--db sqlite
     postgresql: POSTGRESQL=--db postgresql
     mysql: MYSQL=--db mysql --db pymysql
-    oracle: ORACLE=--db oracle --low-connections --write-idents oracle_idents.txt
+    oracle: ORACLE=--db oracle --write-idents oracle_idents.txt
     mssql: MSSQL=--db pyodbc --db pymssql
     backendonly: BACKENDONLY=--backend-only