From: Mike Bayer Date: Mon, 13 Mar 2017 16:27:51 +0000 (-0400) Subject: Repair _execute_scalar for WITH_UNICODE mode X-Git-Tag: rel_1_2_0b1~162 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fb33f9c54be842e191c893c91b3233cd1ae545bc;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Repair _execute_scalar for WITH_UNICODE mode 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 --- diff --git a/doc/build/changelog/changelog_10.rst b/doc/build/changelog/changelog_10.rst index c33b43a0aa..b0047dd8e7 100644 --- a/doc/build/changelog/changelog_10.rst +++ b/doc/build/changelog/changelog_10.rst @@ -15,6 +15,21 @@ .. 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.17 :released: January 17, 2017 diff --git a/lib/sqlalchemy/dialects/oracle/cx_oracle.py b/lib/sqlalchemy/dialects/oracle/cx_oracle.py index 5d1167684a..9b3e3b8a12 100644 --- a/lib/sqlalchemy/dialects/oracle/cx_oracle.py +++ b/lib/sqlalchemy/dialects/oracle/cx_oracle.py @@ -298,6 +298,7 @@ import random import collections import decimal import re +import time class _OracleNumeric(sqltypes.Numeric): @@ -621,9 +622,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): @@ -692,7 +693,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 @@ -701,6 +703,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 @@ -748,18 +751,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: @@ -785,6 +778,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: diff --git a/lib/sqlalchemy/testing/provision.py b/lib/sqlalchemy/testing/provision.py index 23d504b848..7e44544656 100644 --- a/lib/sqlalchemy/testing/provision.py +++ b/lib/sqlalchemy/testing/provision.py @@ -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: diff --git a/test/dialect/test_oracle.py b/test/dialect/test_oracle.py index bb3f565687..f6e1e14c78 100644 --- a/test/dialect/test_oracle.py +++ b/test/dialect/test_oracle.py @@ -1706,10 +1706,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'): diff --git a/tox.ini b/tox.ini index 56aedbb384..2f743914fe 100644 --- a/tox.ini +++ b/tox.ini @@ -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