| Viewing file:  zxjdbc.py (7.92 KB)      -rw-r--r-- Select action/file-type:
 
  (+) |  (+) |  (+) | Code (+) | Session (+) |  (+) | SDB (+) |  (+) |  (+) |  (+) |  (+) |  (+) | 
 
# oracle/zxjdbc.py# Copyright (C) 2005-2016 the SQLAlchemy authors and contributors
 # <see AUTHORS file>
 #
 # This module is part of SQLAlchemy and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
 
 """
 .. dialect:: oracle+zxjdbc
 :name: zxJDBC for Jython
 :dbapi: zxjdbc
 :connectstring: oracle+zxjdbc://user:pass@host/dbname
 :driverurl: http://www.oracle.com/technetwork/database/features/jdbc/index-091264.html
 
 .. note:: Jython is not supported by current versions of SQLAlchemy.  The
 zxjdbc dialect should be considered as experimental.
 
 """
 import decimal
 import re
 
 from sqlalchemy import sql, types as sqltypes, util
 from sqlalchemy.connectors.zxJDBC import ZxJDBCConnector
 from sqlalchemy.dialects.oracle.base import (OracleCompiler,
 OracleDialect,
 OracleExecutionContext)
 from sqlalchemy.engine import result as _result
 from sqlalchemy.sql import expression
 import collections
 
 SQLException = zxJDBC = None
 
 
 class _ZxJDBCDate(sqltypes.Date):
 
 def result_processor(self, dialect, coltype):
 def process(value):
 if value is None:
 return None
 else:
 return value.date()
 return process
 
 
 class _ZxJDBCNumeric(sqltypes.Numeric):
 
 def result_processor(self, dialect, coltype):
 # XXX: does the dialect return Decimal or not???
 # if it does (in all cases), we could use a None processor as well as
 # the to_float generic processor
 if self.asdecimal:
 def process(value):
 if isinstance(value, decimal.Decimal):
 return value
 else:
 return decimal.Decimal(str(value))
 else:
 def process(value):
 if isinstance(value, decimal.Decimal):
 return float(value)
 else:
 return value
 return process
 
 
 class OracleCompiler_zxjdbc(OracleCompiler):
 
 def returning_clause(self, stmt, returning_cols):
 self.returning_cols = list(
 expression._select_iterables(returning_cols))
 
 # within_columns_clause=False so that labels (foo AS bar) don't render
 columns = [self.process(c, within_columns_clause=False)
 for c in self.returning_cols]
 
 if not hasattr(self, 'returning_parameters'):
 self.returning_parameters = []
 
 binds = []
 for i, col in enumerate(self.returning_cols):
 dbtype = col.type.dialect_impl(
 self.dialect).get_dbapi_type(self.dialect.dbapi)
 self.returning_parameters.append((i + 1, dbtype))
 
 bindparam = sql.bindparam(
 "ret_%d" % i, value=ReturningParam(dbtype))
 self.binds[bindparam.key] = bindparam
 binds.append(
 self.bindparam_string(self._truncate_bindparam(bindparam)))
 
 return 'RETURNING ' + ', '.join(columns) + " INTO " + ", ".join(binds)
 
 
 class OracleExecutionContext_zxjdbc(OracleExecutionContext):
 
 def pre_exec(self):
 if hasattr(self.compiled, 'returning_parameters'):
 # prepare a zxJDBC statement so we can grab its underlying
 # OraclePreparedStatement's getReturnResultSet later
 self.statement = self.cursor.prepare(self.statement)
 
 def get_result_proxy(self):
 if hasattr(self.compiled, 'returning_parameters'):
 rrs = None
 try:
 try:
 rrs = self.statement.__statement__.getReturnResultSet()
 next(rrs)
 except SQLException as sqle:
 msg = '%s [SQLCode: %d]' % (
 sqle.getMessage(), sqle.getErrorCode())
 if sqle.getSQLState() is not None:
 msg += ' [SQLState: %s]' % sqle.getSQLState()
 raise zxJDBC.Error(msg)
 else:
 row = tuple(
 self.cursor.datahandler.getPyObject(
 rrs, index, dbtype)
 for index, dbtype in
 self.compiled.returning_parameters)
 return ReturningResultProxy(self, row)
 finally:
 if rrs is not None:
 try:
 rrs.close()
 except SQLException:
 pass
 self.statement.close()
 
 return _result.ResultProxy(self)
 
 def create_cursor(self):
 cursor = self._dbapi_connection.cursor()
 cursor.datahandler = self.dialect.DataHandler(cursor.datahandler)
 return cursor
 
 
 class ReturningResultProxy(_result.FullyBufferedResultProxy):
 
 """ResultProxy backed by the RETURNING ResultSet results."""
 
 def __init__(self, context, returning_row):
 self._returning_row = returning_row
 super(ReturningResultProxy, self).__init__(context)
 
 def _cursor_description(self):
 ret = []
 for c in self.context.compiled.returning_cols:
 if hasattr(c, 'name'):
 ret.append((c.name, c.type))
 else:
 ret.append((c.anon_label, c.type))
 return ret
 
 def _buffer_rows(self):
 return collections.deque([self._returning_row])
 
 
 class ReturningParam(object):
 
 """A bindparam value representing a RETURNING parameter.
 
 Specially handled by OracleReturningDataHandler.
 """
 
 def __init__(self, type):
 self.type = type
 
 def __eq__(self, other):
 if isinstance(other, ReturningParam):
 return self.type == other.type
 return NotImplemented
 
 def __ne__(self, other):
 if isinstance(other, ReturningParam):
 return self.type != other.type
 return NotImplemented
 
 def __repr__(self):
 kls = self.__class__
 return '<%s.%s object at 0x%x type=%s>' % (
 kls.__module__, kls.__name__, id(self), self.type)
 
 
 class OracleDialect_zxjdbc(ZxJDBCConnector, OracleDialect):
 jdbc_db_name = 'oracle'
 jdbc_driver_name = 'oracle.jdbc.OracleDriver'
 
 statement_compiler = OracleCompiler_zxjdbc
 execution_ctx_cls = OracleExecutionContext_zxjdbc
 
 colspecs = util.update_copy(
 OracleDialect.colspecs,
 {
 sqltypes.Date: _ZxJDBCDate,
 sqltypes.Numeric: _ZxJDBCNumeric
 }
 )
 
 def __init__(self, *args, **kwargs):
 super(OracleDialect_zxjdbc, self).__init__(*args, **kwargs)
 global SQLException, zxJDBC
 from java.sql import SQLException
 from com.ziclix.python.sql import zxJDBC
 from com.ziclix.python.sql.handler import OracleDataHandler
 
 class OracleReturningDataHandler(OracleDataHandler):
 """zxJDBC DataHandler that specially handles ReturningParam."""
 
 def setJDBCObject(self, statement, index, object, dbtype=None):
 if type(object) is ReturningParam:
 statement.registerReturnParameter(index, object.type)
 elif dbtype is None:
 OracleDataHandler.setJDBCObject(
 self, statement, index, object)
 else:
 OracleDataHandler.setJDBCObject(
 self, statement, index, object, dbtype)
 self.DataHandler = OracleReturningDataHandler
 
 def initialize(self, connection):
 super(OracleDialect_zxjdbc, self).initialize(connection)
 self.implicit_returning = \
 connection.connection.driverversion >= '10.2'
 
 def _create_jdbc_url(self, url):
 return 'jdbc:oracle:thin:@%s:%s:%s' % (
 url.host, url.port or 1521, url.database)
 
 def _get_server_version_info(self, connection):
 version = re.search(
 r'Release ([\d\.]+)', connection.connection.dbversion).group(1)
 return tuple(int(x) for x in version.split('.'))
 
 dialect = OracleDialect_zxjdbc
 
 |