Remove Elixir library
Update SQLAlchemy
This commit is contained in:
@@ -1,15 +1,14 @@
|
||||
# oracle/base.py
|
||||
# Copyright (C) 2005-2013 the SQLAlchemy authors and contributors <see AUTHORS file>
|
||||
# Copyright (C) 2005-2014 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
|
||||
|
||||
"""Support for the Oracle database.
|
||||
"""
|
||||
.. dialect:: oracle
|
||||
:name: Oracle
|
||||
|
||||
Oracle version 8 through current (11g at the time of this writing) are supported.
|
||||
|
||||
For information on connecting via specific drivers, see the documentation
|
||||
for that driver.
|
||||
Oracle version 8 through current (11g at the time of this writing) are supported.
|
||||
|
||||
Connect Arguments
|
||||
-----------------
|
||||
@@ -17,12 +16,12 @@ Connect Arguments
|
||||
The dialect supports several :func:`~sqlalchemy.create_engine()` arguments which
|
||||
affect the behavior of the dialect regardless of driver in use.
|
||||
|
||||
* *use_ansi* - Use ANSI JOIN constructs (see the section on Oracle 8). Defaults
|
||||
* ``use_ansi`` - Use ANSI JOIN constructs (see the section on Oracle 8). Defaults
|
||||
to ``True``. If ``False``, Oracle-8 compatible constructs are used for joins.
|
||||
|
||||
* *optimize_limits* - defaults to ``False``. see the section on LIMIT/OFFSET.
|
||||
* ``optimize_limits`` - defaults to ``False``. see the section on LIMIT/OFFSET.
|
||||
|
||||
* *use_binds_for_limits* - defaults to ``True``. see the section on LIMIT/OFFSET.
|
||||
* ``use_binds_for_limits`` - defaults to ``True``. see the section on LIMIT/OFFSET.
|
||||
|
||||
Auto Increment Behavior
|
||||
-----------------------
|
||||
@@ -100,6 +99,41 @@ http://www.sqlalchemy.org/trac/wiki/UsageRecipes/WindowFunctionsByDefault
|
||||
which installs a select compiler that overrides the generation of limit/offset with
|
||||
a window function.
|
||||
|
||||
RETURNING Support
|
||||
-----------------
|
||||
|
||||
The Oracle database supports a limited form of RETURNING, in order to retrieve result
|
||||
sets of matched rows from INSERT, UPDATE and DELETE statements. Oracle's
|
||||
RETURNING..INTO syntax only supports one row being returned, as it relies upon
|
||||
OUT parameters in order to function. In addition, supported DBAPIs have further
|
||||
limitations (see :ref:`cx_oracle_returning`).
|
||||
|
||||
SQLAlchemy's "implicit returning" feature, which employs RETURNING within an INSERT
|
||||
and sometimes an UPDATE statement in order to fetch newly generated primary key values
|
||||
and other SQL defaults and expressions, is normally enabled on the Oracle
|
||||
backend. By default, "implicit returning" typically only fetches the value of a
|
||||
single ``nextval(some_seq)`` expression embedded into an INSERT in order to increment
|
||||
a sequence within an INSERT statement and get the value back at the same time.
|
||||
To disable this feature across the board, specify ``implicit_returning=False`` to
|
||||
:func:`.create_engine`::
|
||||
|
||||
engine = create_engine("oracle://scott:tiger@dsn", implicit_returning=False)
|
||||
|
||||
Implicit returning can also be disabled on a table-by-table basis as a table option::
|
||||
|
||||
# Core Table
|
||||
my_table = Table("my_table", metadata, ..., implicit_returning=False)
|
||||
|
||||
|
||||
# declarative
|
||||
class MyClass(Base):
|
||||
__tablename__ = 'my_table'
|
||||
__table_args__ = {"implicit_returning": False}
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`cx_oracle_returning` - additional cx_oracle-specific restrictions on implicit returning.
|
||||
|
||||
ON UPDATE CASCADE
|
||||
-----------------
|
||||
|
||||
@@ -134,16 +168,16 @@ Synonym/DBLINK Reflection
|
||||
-------------------------
|
||||
|
||||
When using reflection with Table objects, the dialect can optionally search for tables
|
||||
indicated by synonyms that reference DBLINK-ed tables by passing the flag
|
||||
oracle_resolve_synonyms=True as a keyword argument to the Table construct. If DBLINK
|
||||
is not in use this flag should be left off.
|
||||
indicated by synonyms, either in local or remote schemas or accessed over DBLINK,
|
||||
by passing the flag oracle_resolve_synonyms=True as a
|
||||
keyword argument to the Table construct. If synonyms are not in use
|
||||
this flag should be left off.
|
||||
|
||||
"""
|
||||
|
||||
import random, re
|
||||
import re
|
||||
|
||||
from sqlalchemy import schema as sa_schema
|
||||
from sqlalchemy import util, sql, log
|
||||
from sqlalchemy import util, sql
|
||||
from sqlalchemy.engine import default, base, reflection
|
||||
from sqlalchemy.sql import compiler, visitors, expression
|
||||
from sqlalchemy.sql import operators as sql_operators, functions as sql_functions
|
||||
@@ -165,18 +199,22 @@ RESERVED_WORDS = \
|
||||
NO_ARG_FNS = set('UID CURRENT_DATE SYSDATE USER '
|
||||
'CURRENT_TIME CURRENT_TIMESTAMP'.split())
|
||||
|
||||
|
||||
class RAW(sqltypes._Binary):
|
||||
__visit_name__ = 'RAW'
|
||||
OracleRaw = RAW
|
||||
|
||||
|
||||
class NCLOB(sqltypes.Text):
|
||||
__visit_name__ = 'NCLOB'
|
||||
|
||||
|
||||
class VARCHAR2(VARCHAR):
|
||||
__visit_name__ = 'VARCHAR2'
|
||||
|
||||
NVARCHAR2 = NVARCHAR
|
||||
|
||||
|
||||
class NUMBER(sqltypes.Numeric, sqltypes.Integer):
|
||||
__visit_name__ = 'NUMBER'
|
||||
|
||||
@@ -202,18 +240,22 @@ class NUMBER(sqltypes.Numeric, sqltypes.Integer):
|
||||
|
||||
class DOUBLE_PRECISION(sqltypes.Numeric):
|
||||
__visit_name__ = 'DOUBLE_PRECISION'
|
||||
|
||||
def __init__(self, precision=None, scale=None, asdecimal=None):
|
||||
if asdecimal is None:
|
||||
asdecimal = False
|
||||
|
||||
super(DOUBLE_PRECISION, self).__init__(precision=precision, scale=scale, asdecimal=asdecimal)
|
||||
|
||||
|
||||
class BFILE(sqltypes.LargeBinary):
|
||||
__visit_name__ = 'BFILE'
|
||||
|
||||
|
||||
class LONG(sqltypes.Text):
|
||||
__visit_name__ = 'LONG'
|
||||
|
||||
|
||||
class INTERVAL(sqltypes.TypeEngine):
|
||||
__visit_name__ = 'INTERVAL'
|
||||
|
||||
@@ -244,6 +286,7 @@ class INTERVAL(sqltypes.TypeEngine):
|
||||
def _type_affinity(self):
|
||||
return sqltypes.Interval
|
||||
|
||||
|
||||
class ROWID(sqltypes.TypeEngine):
|
||||
"""Oracle ROWID type.
|
||||
|
||||
@@ -253,33 +296,32 @@ class ROWID(sqltypes.TypeEngine):
|
||||
__visit_name__ = 'ROWID'
|
||||
|
||||
|
||||
|
||||
class _OracleBoolean(sqltypes.Boolean):
|
||||
def get_dbapi_type(self, dbapi):
|
||||
return dbapi.NUMBER
|
||||
|
||||
colspecs = {
|
||||
sqltypes.Boolean : _OracleBoolean,
|
||||
sqltypes.Interval : INTERVAL,
|
||||
sqltypes.Boolean: _OracleBoolean,
|
||||
sqltypes.Interval: INTERVAL,
|
||||
}
|
||||
|
||||
ischema_names = {
|
||||
'VARCHAR2' : VARCHAR,
|
||||
'NVARCHAR2' : NVARCHAR,
|
||||
'CHAR' : CHAR,
|
||||
'DATE' : DATE,
|
||||
'NUMBER' : NUMBER,
|
||||
'BLOB' : BLOB,
|
||||
'BFILE' : BFILE,
|
||||
'CLOB' : CLOB,
|
||||
'NCLOB' : NCLOB,
|
||||
'TIMESTAMP' : TIMESTAMP,
|
||||
'TIMESTAMP WITH TIME ZONE' : TIMESTAMP,
|
||||
'INTERVAL DAY TO SECOND' : INTERVAL,
|
||||
'RAW' : RAW,
|
||||
'FLOAT' : FLOAT,
|
||||
'DOUBLE PRECISION' : DOUBLE_PRECISION,
|
||||
'LONG' : LONG,
|
||||
'VARCHAR2': VARCHAR,
|
||||
'NVARCHAR2': NVARCHAR,
|
||||
'CHAR': CHAR,
|
||||
'DATE': DATE,
|
||||
'NUMBER': NUMBER,
|
||||
'BLOB': BLOB,
|
||||
'BFILE': BFILE,
|
||||
'CLOB': CLOB,
|
||||
'NCLOB': NCLOB,
|
||||
'TIMESTAMP': TIMESTAMP,
|
||||
'TIMESTAMP WITH TIME ZONE': TIMESTAMP,
|
||||
'INTERVAL DAY TO SECOND': INTERVAL,
|
||||
'RAW': RAW,
|
||||
'FLOAT': FLOAT,
|
||||
'DOUBLE PRECISION': DOUBLE_PRECISION,
|
||||
'LONG': LONG,
|
||||
}
|
||||
|
||||
|
||||
@@ -336,9 +378,11 @@ class OracleTypeCompiler(compiler.GenericTypeCompiler):
|
||||
if precision is None:
|
||||
return name
|
||||
elif scale is None:
|
||||
return "%(name)s(%(precision)s)" % {'name':name,'precision': precision}
|
||||
n = "%(name)s(%(precision)s)"
|
||||
return n % {'name': name, 'precision': precision}
|
||||
else:
|
||||
return "%(name)s(%(precision)s, %(scale)s)" % {'name':name,'precision': precision, 'scale' : scale}
|
||||
n = "%(name)s(%(precision)s, %(scale)s)"
|
||||
return n % {'name': name, 'precision': precision, 'scale': scale}
|
||||
|
||||
def visit_string(self, type_):
|
||||
return self.visit_VARCHAR2(type_)
|
||||
@@ -354,13 +398,14 @@ class OracleTypeCompiler(compiler.GenericTypeCompiler):
|
||||
return self._visit_varchar(type_, '', '')
|
||||
|
||||
def _visit_varchar(self, type_, n, num):
|
||||
if not n and self.dialect._supports_char_length:
|
||||
return "VARCHAR%(two)s(%(length)s CHAR)" % {
|
||||
'length' : type_.length,
|
||||
'two':num}
|
||||
if not type_.length:
|
||||
return "%(n)sVARCHAR%(two)s" % {'two': num, 'n': n}
|
||||
elif not n and self.dialect._supports_char_length:
|
||||
varchar = "VARCHAR%(two)s(%(length)s CHAR)"
|
||||
return varchar % {'length': type_.length, 'two': num}
|
||||
else:
|
||||
return "%(n)sVARCHAR%(two)s(%(length)s)" % {'length' : type_.length,
|
||||
'two':num, 'n':n}
|
||||
varchar = "%(n)sVARCHAR%(two)s(%(length)s)"
|
||||
return varchar % {'length': type_.length, 'two': num, 'n': n}
|
||||
|
||||
def visit_text(self, type_):
|
||||
return self.visit_CLOB(type_)
|
||||
@@ -382,13 +427,14 @@ class OracleTypeCompiler(compiler.GenericTypeCompiler):
|
||||
|
||||
def visit_RAW(self, type_):
|
||||
if type_.length:
|
||||
return "RAW(%(length)s)" % {'length' : type_.length}
|
||||
return "RAW(%(length)s)" % {'length': type_.length}
|
||||
else:
|
||||
return "RAW"
|
||||
|
||||
def visit_ROWID(self, type_):
|
||||
return "ROWID"
|
||||
|
||||
|
||||
class OracleCompiler(compiler.SQLCompiler):
|
||||
"""Oracle compiler modifies the lexical structure of Select
|
||||
statements to work under non-ANSI configured Oracle databases, if
|
||||
@@ -398,7 +444,7 @@ class OracleCompiler(compiler.SQLCompiler):
|
||||
compound_keywords = util.update_copy(
|
||||
compiler.SQLCompiler.compound_keywords,
|
||||
{
|
||||
expression.CompoundSelect.EXCEPT : 'MINUS'
|
||||
expression.CompoundSelect.EXCEPT: 'MINUS'
|
||||
}
|
||||
)
|
||||
|
||||
@@ -407,8 +453,9 @@ class OracleCompiler(compiler.SQLCompiler):
|
||||
self._quoted_bind_names = {}
|
||||
super(OracleCompiler, self).__init__(*args, **kwargs)
|
||||
|
||||
def visit_mod(self, binary, **kw):
|
||||
return "mod(%s, %s)" % (self.process(binary.left), self.process(binary.right))
|
||||
def visit_mod_binary(self, binary, operator, **kw):
|
||||
return "mod(%s, %s)" % (self.process(binary.left, **kw),
|
||||
self.process(binary.right, **kw))
|
||||
|
||||
def visit_now_func(self, fn, **kw):
|
||||
return "CURRENT_TIMESTAMP"
|
||||
@@ -416,8 +463,15 @@ class OracleCompiler(compiler.SQLCompiler):
|
||||
def visit_char_length_func(self, fn, **kw):
|
||||
return "LENGTH" + self.function_argspec(fn, **kw)
|
||||
|
||||
def visit_match_op(self, binary, **kw):
|
||||
return "CONTAINS (%s, %s)" % (self.process(binary.left), self.process(binary.right))
|
||||
def visit_match_op_binary(self, binary, operator, **kw):
|
||||
return "CONTAINS (%s, %s)" % (self.process(binary.left),
|
||||
self.process(binary.right))
|
||||
|
||||
def visit_true(self, expr, **kw):
|
||||
return '1'
|
||||
|
||||
def visit_false(self, expr, **kw):
|
||||
return '0'
|
||||
|
||||
def get_select_hint_text(self, byfroms):
|
||||
return " ".join(
|
||||
@@ -444,8 +498,13 @@ class OracleCompiler(compiler.SQLCompiler):
|
||||
return compiler.SQLCompiler.visit_join(self, join, **kwargs)
|
||||
else:
|
||||
kwargs['asfrom'] = True
|
||||
if isinstance(join.right, expression.FromGrouping):
|
||||
right = join.right.element
|
||||
else:
|
||||
right = join.right
|
||||
return self.process(join.left, **kwargs) + \
|
||||
", " + self.process(join.right, **kwargs)
|
||||
", " + self.process(right, **kwargs)
|
||||
|
||||
|
||||
def _get_nonansi_join_whereclause(self, froms):
|
||||
clauses = []
|
||||
@@ -454,18 +513,20 @@ class OracleCompiler(compiler.SQLCompiler):
|
||||
if join.isouter:
|
||||
def visit_binary(binary):
|
||||
if binary.operator == sql_operators.eq:
|
||||
if binary.left.table is join.right:
|
||||
if join.right.is_derived_from(binary.left.table):
|
||||
binary.left = _OuterJoinColumn(binary.left)
|
||||
elif binary.right.table is join.right:
|
||||
elif join.right.is_derived_from(binary.right.table):
|
||||
binary.right = _OuterJoinColumn(binary.right)
|
||||
clauses.append(visitors.cloned_traverse(join.onclause, {},
|
||||
{'binary':visit_binary}))
|
||||
{'binary': visit_binary}))
|
||||
else:
|
||||
clauses.append(join.onclause)
|
||||
|
||||
for j in join.left, join.right:
|
||||
if isinstance(j, expression.Join):
|
||||
visit_join(j)
|
||||
elif isinstance(j, expression.FromGrouping):
|
||||
visit_join(j.element)
|
||||
|
||||
for f in froms:
|
||||
if isinstance(f, expression.Join):
|
||||
@@ -498,20 +559,25 @@ class OracleCompiler(compiler.SQLCompiler):
|
||||
return self.process(alias.original, **kwargs)
|
||||
|
||||
def returning_clause(self, stmt, returning_cols):
|
||||
columns = []
|
||||
binds = []
|
||||
for i, column in enumerate(expression._select_iterables(returning_cols)):
|
||||
if column.type._has_column_expression:
|
||||
col_expr = column.type.column_expression(column)
|
||||
else:
|
||||
col_expr = column
|
||||
outparam = sql.outparam("ret_%d" % i, type_=column.type)
|
||||
self.binds[outparam.key] = outparam
|
||||
binds.append(self.bindparam_string(self._truncate_bindparam(outparam)))
|
||||
columns.append(self.process(col_expr, within_columns_clause=False))
|
||||
self.result_map[outparam.key] = (
|
||||
outparam.key,
|
||||
(column, getattr(column, 'name', None),
|
||||
getattr(column, 'key', None)),
|
||||
column.type
|
||||
)
|
||||
|
||||
def create_out_param(col, i):
|
||||
bindparam = sql.outparam("ret_%d" % i, type_=col.type)
|
||||
self.binds[bindparam.key] = bindparam
|
||||
return self.bindparam_string(self._truncate_bindparam(bindparam))
|
||||
|
||||
columnlist = 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, result_map=self.result_map) for c in columnlist]
|
||||
|
||||
binds = [create_out_param(c, i) for i, c in enumerate(columnlist)]
|
||||
|
||||
return 'RETURNING ' + ', '.join(columns) + " INTO " + ", ".join(binds)
|
||||
return 'RETURNING ' + ', '.join(columns) + " INTO " + ", ".join(binds)
|
||||
|
||||
def _TODO_visit_compound_select(self, select):
|
||||
"""Need to determine how to get ``LIMIT``/``OFFSET`` into a ``UNION`` for Oracle."""
|
||||
@@ -524,12 +590,8 @@ class OracleCompiler(compiler.SQLCompiler):
|
||||
|
||||
if not getattr(select, '_oracle_visit', None):
|
||||
if not self.dialect.use_ansi:
|
||||
if self.stack and 'from' in self.stack[-1]:
|
||||
existingfroms = self.stack[-1]['from']
|
||||
else:
|
||||
existingfroms = None
|
||||
|
||||
froms = select._get_display_froms(existingfroms)
|
||||
froms = self._display_froms_for_select(
|
||||
select, kwargs.get('asfrom', False))
|
||||
whereclause = self._get_nonansi_join_whereclause(froms)
|
||||
if whereclause is not None:
|
||||
select = select.where(whereclause)
|
||||
@@ -570,7 +632,7 @@ class OracleCompiler(compiler.SQLCompiler):
|
||||
|
||||
# If needed, add the ora_rn, and wrap again with offset.
|
||||
if select._offset is None:
|
||||
limitselect.for_update = select.for_update
|
||||
limitselect._for_update_arg = select._for_update_arg
|
||||
select = limitselect
|
||||
else:
|
||||
limitselect = limitselect.column(
|
||||
@@ -579,7 +641,7 @@ class OracleCompiler(compiler.SQLCompiler):
|
||||
limitselect._is_wrapper = True
|
||||
|
||||
offsetselect = sql.select(
|
||||
[c for c in limitselect.c if c.key!='ora_rn'])
|
||||
[c for c in limitselect.c if c.key != 'ora_rn'])
|
||||
offsetselect._oracle_visit = True
|
||||
offsetselect._is_wrapper = True
|
||||
|
||||
@@ -587,9 +649,9 @@ class OracleCompiler(compiler.SQLCompiler):
|
||||
if not self.dialect.use_binds_for_limits:
|
||||
offset_value = sql.literal_column("%d" % offset_value)
|
||||
offsetselect.append_whereclause(
|
||||
sql.literal_column("ora_rn")>offset_value)
|
||||
sql.literal_column("ora_rn") > offset_value)
|
||||
|
||||
offsetselect.for_update = select.for_update
|
||||
offsetselect._for_update_arg = select._for_update_arg
|
||||
select = offsetselect
|
||||
|
||||
kwargs['iswrapper'] = getattr(select, '_is_wrapper', False)
|
||||
@@ -601,10 +663,20 @@ class OracleCompiler(compiler.SQLCompiler):
|
||||
def for_update_clause(self, select):
|
||||
if self.is_subquery():
|
||||
return ""
|
||||
elif select.for_update == "nowait":
|
||||
return " FOR UPDATE NOWAIT"
|
||||
else:
|
||||
return super(OracleCompiler, self).for_update_clause(select)
|
||||
|
||||
tmp = ' FOR UPDATE'
|
||||
|
||||
if select._for_update_arg.of:
|
||||
tmp += ' OF ' + ', '.join(
|
||||
self.process(elem) for elem in
|
||||
select._for_update_arg.of
|
||||
)
|
||||
|
||||
if select._for_update_arg.nowait:
|
||||
tmp += " NOWAIT"
|
||||
|
||||
return tmp
|
||||
|
||||
|
||||
class OracleDDLCompiler(compiler.DDLCompiler):
|
||||
|
||||
@@ -623,17 +695,22 @@ class OracleDDLCompiler(compiler.DDLCompiler):
|
||||
|
||||
return text
|
||||
|
||||
def visit_create_index(self, create, **kw):
|
||||
return super(OracleDDLCompiler, self).\
|
||||
visit_create_index(create, include_schema=True)
|
||||
|
||||
|
||||
class OracleIdentifierPreparer(compiler.IdentifierPreparer):
|
||||
|
||||
reserved_words = set([x.lower() for x in RESERVED_WORDS])
|
||||
illegal_initial_characters = set(xrange(0, 10)).union(["_", "$"])
|
||||
illegal_initial_characters = set(range(0, 10)).union(["_", "$"])
|
||||
|
||||
def _bindparam_requires_quotes(self, value):
|
||||
"""Return True if the given identifier requires quoting."""
|
||||
lc_value = value.lower()
|
||||
return (lc_value in self.reserved_words
|
||||
or value[0] in self.illegal_initial_characters
|
||||
or not self.legal_characters.match(unicode(value))
|
||||
or not self.legal_characters.match(util.text_type(value))
|
||||
)
|
||||
|
||||
def format_savepoint(self, savepoint):
|
||||
@@ -647,6 +724,7 @@ class OracleExecutionContext(default.DefaultExecutionContext):
|
||||
self.dialect.identifier_preparer.format_sequence(seq) +
|
||||
".nextval FROM DUAL", type_)
|
||||
|
||||
|
||||
class OracleDialect(default.DefaultDialect):
|
||||
name = 'oracle'
|
||||
supports_alter = True
|
||||
@@ -736,10 +814,9 @@ class OracleDialect(default.DefaultDialect):
|
||||
def normalize_name(self, name):
|
||||
if name is None:
|
||||
return None
|
||||
# Py2K
|
||||
if isinstance(name, str):
|
||||
name = name.decode(self.encoding)
|
||||
# end Py2K
|
||||
if util.py2k:
|
||||
if isinstance(name, str):
|
||||
name = name.decode(self.encoding)
|
||||
if name.upper() == name and \
|
||||
not self.identifier_preparer._requires_quotes(name.lower()):
|
||||
return name.lower()
|
||||
@@ -751,16 +828,15 @@ class OracleDialect(default.DefaultDialect):
|
||||
return None
|
||||
elif name.lower() == name and not self.identifier_preparer._requires_quotes(name.lower()):
|
||||
name = name.upper()
|
||||
# Py2K
|
||||
if not self.supports_unicode_binds:
|
||||
name = name.encode(self.encoding)
|
||||
else:
|
||||
name = unicode(name)
|
||||
# end Py2K
|
||||
if util.py2k:
|
||||
if not self.supports_unicode_binds:
|
||||
name = name.encode(self.encoding)
|
||||
else:
|
||||
name = unicode(name)
|
||||
return name
|
||||
|
||||
def _get_default_schema_name(self, connection):
|
||||
return self.normalize_name(connection.execute(u'SELECT USER FROM DUAL').scalar())
|
||||
return self.normalize_name(connection.execute('SELECT USER FROM DUAL').scalar())
|
||||
|
||||
def _resolve_synonym(self, connection, desired_owner=None, desired_synonym=None, desired_table=None):
|
||||
"""search for a local synonym matching the given desired owner/name.
|
||||
@@ -770,14 +846,15 @@ class OracleDialect(default.DefaultDialect):
|
||||
returns the actual name, owner, dblink name, and synonym name if found.
|
||||
"""
|
||||
|
||||
q = "SELECT owner, table_owner, table_name, db_link, synonym_name FROM all_synonyms WHERE "
|
||||
q = "SELECT owner, table_owner, table_name, db_link, "\
|
||||
"synonym_name FROM all_synonyms WHERE "
|
||||
clauses = []
|
||||
params = {}
|
||||
if desired_synonym:
|
||||
clauses.append("synonym_name = :synonym_name")
|
||||
params['synonym_name'] = desired_synonym
|
||||
if desired_owner:
|
||||
clauses.append("table_owner = :desired_owner")
|
||||
clauses.append("owner = :desired_owner")
|
||||
params['desired_owner'] = desired_owner
|
||||
if desired_table:
|
||||
clauses.append("table_name = :tname")
|
||||
@@ -808,19 +885,29 @@ class OracleDialect(default.DefaultDialect):
|
||||
|
||||
if resolve_synonyms:
|
||||
actual_name, owner, dblink, synonym = self._resolve_synonym(
|
||||
connection,
|
||||
desired_owner=self.denormalize_name(schema),
|
||||
desired_synonym=self.denormalize_name(table_name)
|
||||
)
|
||||
connection,
|
||||
desired_owner=self.denormalize_name(schema),
|
||||
desired_synonym=self.denormalize_name(table_name)
|
||||
)
|
||||
else:
|
||||
actual_name, owner, dblink, synonym = None, None, None, None
|
||||
if not actual_name:
|
||||
actual_name = self.denormalize_name(table_name)
|
||||
if not dblink:
|
||||
dblink = ''
|
||||
if not owner:
|
||||
|
||||
if dblink:
|
||||
# using user_db_links here since all_db_links appears
|
||||
# to have more restricted permissions.
|
||||
# http://docs.oracle.com/cd/B28359_01/server.111/b28310/ds_admin005.htm
|
||||
# will need to hear from more users if we are doing
|
||||
# the right thing here. See [ticket:2619]
|
||||
owner = connection.scalar(
|
||||
sql.text("SELECT username FROM user_db_links "
|
||||
"WHERE db_link=:link"), link=dblink)
|
||||
dblink = "@" + dblink
|
||||
elif not owner:
|
||||
owner = self.denormalize_name(schema or self.default_schema_name)
|
||||
return (actual_name, owner, dblink, synonym)
|
||||
|
||||
return (actual_name, owner, dblink or '', synonym)
|
||||
|
||||
@reflection.cache
|
||||
def get_schema_names(self, connection, **kw):
|
||||
@@ -843,7 +930,6 @@ class OracleDialect(default.DefaultDialect):
|
||||
cursor = connection.execute(s, owner=schema)
|
||||
return [self.normalize_name(row[0]) for row in cursor]
|
||||
|
||||
|
||||
@reflection.cache
|
||||
def get_view_names(self, connection, schema=None, **kw):
|
||||
schema = self.denormalize_name(schema or self.default_schema_name)
|
||||
@@ -877,18 +963,24 @@ class OracleDialect(default.DefaultDialect):
|
||||
else:
|
||||
char_length_col = 'data_length'
|
||||
|
||||
c = connection.execute(sql.text(
|
||||
"SELECT column_name, data_type, %(char_length_col)s, data_precision, data_scale, "
|
||||
"nullable, data_default FROM ALL_TAB_COLUMNS%(dblink)s "
|
||||
"WHERE table_name = :table_name AND owner = :owner "
|
||||
"ORDER BY column_id" % {'dblink': dblink, 'char_length_col':char_length_col}),
|
||||
table_name=table_name, owner=schema)
|
||||
params = {"table_name": table_name}
|
||||
text = "SELECT column_name, data_type, %(char_length_col)s, "\
|
||||
"data_precision, data_scale, "\
|
||||
"nullable, data_default FROM ALL_TAB_COLUMNS%(dblink)s "\
|
||||
"WHERE table_name = :table_name"
|
||||
if schema is not None:
|
||||
params['owner'] = schema
|
||||
text += " AND owner = :owner "
|
||||
text += " ORDER BY column_id"
|
||||
text = text % {'dblink': dblink, 'char_length_col': char_length_col}
|
||||
|
||||
c = connection.execute(sql.text(text), **params)
|
||||
|
||||
for row in c:
|
||||
(colname, orig_colname, coltype, length, precision, scale, nullable, default) = \
|
||||
(self.normalize_name(row[0]), row[0], row[1], row[2], row[3], row[4], row[5]=='Y', row[6])
|
||||
(self.normalize_name(row[0]), row[0], row[1], row[2], row[3], row[4], row[5] == 'Y', row[6])
|
||||
|
||||
if coltype == 'NUMBER' :
|
||||
if coltype == 'NUMBER':
|
||||
coltype = NUMBER(precision, scale)
|
||||
elif coltype in ('VARCHAR2', 'NVARCHAR2', 'CHAR'):
|
||||
coltype = self.ischema_names.get(coltype)(length)
|
||||
@@ -908,7 +1000,7 @@ class OracleDialect(default.DefaultDialect):
|
||||
'type': coltype,
|
||||
'nullable': nullable,
|
||||
'default': default,
|
||||
'autoincrement':default is None
|
||||
'autoincrement': default is None
|
||||
}
|
||||
if orig_colname.lower() == orig_colname:
|
||||
cdict['quote'] = True
|
||||
@@ -920,33 +1012,40 @@ class OracleDialect(default.DefaultDialect):
|
||||
def get_indexes(self, connection, table_name, schema=None,
|
||||
resolve_synonyms=False, dblink='', **kw):
|
||||
|
||||
|
||||
info_cache = kw.get('info_cache')
|
||||
(table_name, schema, dblink, synonym) = \
|
||||
self._prepare_reflection_args(connection, table_name, schema,
|
||||
resolve_synonyms, dblink,
|
||||
info_cache=info_cache)
|
||||
indexes = []
|
||||
q = sql.text("""
|
||||
SELECT a.index_name, a.column_name, b.uniqueness
|
||||
FROM ALL_IND_COLUMNS%(dblink)s a,
|
||||
ALL_INDEXES%(dblink)s b
|
||||
WHERE
|
||||
a.index_name = b.index_name
|
||||
AND a.table_owner = b.table_owner
|
||||
AND a.table_name = b.table_name
|
||||
|
||||
AND a.table_name = :table_name
|
||||
AND a.table_owner = :schema
|
||||
ORDER BY a.index_name, a.column_position""" % {'dblink': dblink})
|
||||
rp = connection.execute(q, table_name=self.denormalize_name(table_name),
|
||||
schema=self.denormalize_name(schema))
|
||||
params = {'table_name': table_name}
|
||||
text = \
|
||||
"SELECT a.index_name, a.column_name, b.uniqueness "\
|
||||
"\nFROM ALL_IND_COLUMNS%(dblink)s a, "\
|
||||
"\nALL_INDEXES%(dblink)s b "\
|
||||
"\nWHERE "\
|
||||
"\na.index_name = b.index_name "\
|
||||
"\nAND a.table_owner = b.table_owner "\
|
||||
"\nAND a.table_name = b.table_name "\
|
||||
"\nAND a.table_name = :table_name "
|
||||
|
||||
if schema is not None:
|
||||
params['schema'] = schema
|
||||
text += "AND a.table_owner = :schema "
|
||||
|
||||
text += "ORDER BY a.index_name, a.column_position"
|
||||
|
||||
text = text % {'dblink': dblink}
|
||||
|
||||
q = sql.text(text)
|
||||
rp = connection.execute(q, **params)
|
||||
indexes = []
|
||||
last_index_name = None
|
||||
pkeys = self.get_primary_keys(connection, table_name, schema,
|
||||
resolve_synonyms=resolve_synonyms,
|
||||
dblink=dblink,
|
||||
info_cache=kw.get('info_cache'))
|
||||
pk_constraint = self.get_pk_constraint(
|
||||
connection, table_name, schema, resolve_synonyms=resolve_synonyms,
|
||||
dblink=dblink, info_cache=kw.get('info_cache'))
|
||||
pkeys = pk_constraint['constrained_columns']
|
||||
uniqueness = dict(NONUNIQUE=False, UNIQUE=True)
|
||||
|
||||
oracle_sys_col = re.compile(r'SYS_NC\d+\$', re.IGNORECASE)
|
||||
@@ -982,46 +1081,43 @@ class OracleDialect(default.DefaultDialect):
|
||||
def _get_constraint_data(self, connection, table_name, schema=None,
|
||||
dblink='', **kw):
|
||||
|
||||
rp = connection.execute(
|
||||
sql.text("""SELECT
|
||||
ac.constraint_name,
|
||||
ac.constraint_type,
|
||||
loc.column_name AS local_column,
|
||||
rem.table_name AS remote_table,
|
||||
rem.column_name AS remote_column,
|
||||
rem.owner AS remote_owner,
|
||||
loc.position as loc_pos,
|
||||
rem.position as rem_pos
|
||||
FROM all_constraints%(dblink)s ac,
|
||||
all_cons_columns%(dblink)s loc,
|
||||
all_cons_columns%(dblink)s rem
|
||||
WHERE ac.table_name = :table_name
|
||||
AND ac.constraint_type IN ('R','P')
|
||||
AND ac.owner = :owner
|
||||
AND ac.owner = loc.owner
|
||||
AND ac.constraint_name = loc.constraint_name
|
||||
AND ac.r_owner = rem.owner(+)
|
||||
AND ac.r_constraint_name = rem.constraint_name(+)
|
||||
AND (rem.position IS NULL or loc.position=rem.position)
|
||||
ORDER BY ac.constraint_name, loc.position""" % {'dblink': dblink}),
|
||||
table_name=table_name, owner=schema)
|
||||
params = {'table_name': table_name}
|
||||
|
||||
text = \
|
||||
"SELECT"\
|
||||
"\nac.constraint_name,"\
|
||||
"\nac.constraint_type,"\
|
||||
"\nloc.column_name AS local_column,"\
|
||||
"\nrem.table_name AS remote_table,"\
|
||||
"\nrem.column_name AS remote_column,"\
|
||||
"\nrem.owner AS remote_owner,"\
|
||||
"\nloc.position as loc_pos,"\
|
||||
"\nrem.position as rem_pos"\
|
||||
"\nFROM all_constraints%(dblink)s ac,"\
|
||||
"\nall_cons_columns%(dblink)s loc,"\
|
||||
"\nall_cons_columns%(dblink)s rem"\
|
||||
"\nWHERE ac.table_name = :table_name"\
|
||||
"\nAND ac.constraint_type IN ('R','P')"
|
||||
|
||||
if schema is not None:
|
||||
params['owner'] = schema
|
||||
text += "\nAND ac.owner = :owner"
|
||||
|
||||
text += \
|
||||
"\nAND ac.owner = loc.owner"\
|
||||
"\nAND ac.constraint_name = loc.constraint_name"\
|
||||
"\nAND ac.r_owner = rem.owner(+)"\
|
||||
"\nAND ac.r_constraint_name = rem.constraint_name(+)"\
|
||||
"\nAND (rem.position IS NULL or loc.position=rem.position)"\
|
||||
"\nORDER BY ac.constraint_name, loc.position"
|
||||
|
||||
text = text % {'dblink': dblink}
|
||||
rp = connection.execute(sql.text(text), **params)
|
||||
constraint_data = rp.fetchall()
|
||||
return constraint_data
|
||||
|
||||
def get_primary_keys(self, connection, table_name, schema=None, **kw):
|
||||
"""
|
||||
|
||||
kw arguments can be:
|
||||
|
||||
oracle_resolve_synonyms
|
||||
|
||||
dblink
|
||||
|
||||
"""
|
||||
return self._get_primary_keys(connection, table_name, schema, **kw)[0]
|
||||
|
||||
@reflection.cache
|
||||
def _get_primary_keys(self, connection, table_name, schema=None, **kw):
|
||||
def get_pk_constraint(self, connection, table_name, schema=None, **kw):
|
||||
resolve_synonyms = kw.get('oracle_resolve_synonyms', False)
|
||||
dblink = kw.get('dblink', '')
|
||||
info_cache = kw.get('info_cache')
|
||||
@@ -1037,22 +1133,13 @@ class OracleDialect(default.DefaultDialect):
|
||||
info_cache=kw.get('info_cache'))
|
||||
|
||||
for row in constraint_data:
|
||||
#print "ROW:" , row
|
||||
(cons_name, cons_type, local_column, remote_table, remote_column, remote_owner) = \
|
||||
row[0:2] + tuple([self.normalize_name(x) for x in row[2:6]])
|
||||
if cons_type == 'P':
|
||||
if constraint_name is None:
|
||||
constraint_name = self.normalize_name(cons_name)
|
||||
pkeys.append(local_column)
|
||||
return pkeys, constraint_name
|
||||
|
||||
def get_pk_constraint(self, connection, table_name, schema=None, **kw):
|
||||
cols, name = self._get_primary_keys(connection, table_name, schema=schema, **kw)
|
||||
|
||||
return {
|
||||
'constrained_columns':cols,
|
||||
'name':name
|
||||
}
|
||||
return {'constrained_columns': pkeys, 'name': constraint_name}
|
||||
|
||||
@reflection.cache
|
||||
def get_foreign_keys(self, connection, table_name, schema=None, **kw):
|
||||
@@ -1066,7 +1153,7 @@ class OracleDialect(default.DefaultDialect):
|
||||
|
||||
"""
|
||||
|
||||
requested_schema = schema # to check later on
|
||||
requested_schema = schema # to check later on
|
||||
resolve_synonyms = kw.get('oracle_resolve_synonyms', False)
|
||||
dblink = kw.get('dblink', '')
|
||||
info_cache = kw.get('info_cache')
|
||||
@@ -1082,11 +1169,11 @@ class OracleDialect(default.DefaultDialect):
|
||||
|
||||
def fkey_rec():
|
||||
return {
|
||||
'name' : None,
|
||||
'constrained_columns' : [],
|
||||
'referred_schema' : None,
|
||||
'referred_table' : None,
|
||||
'referred_columns' : []
|
||||
'name': None,
|
||||
'constrained_columns': [],
|
||||
'referred_schema': None,
|
||||
'referred_table': None,
|
||||
'referred_columns': []
|
||||
}
|
||||
|
||||
fkeys = util.defaultdict(fkey_rec)
|
||||
@@ -1101,7 +1188,7 @@ class OracleDialect(default.DefaultDialect):
|
||||
util.warn(
|
||||
("Got 'None' querying 'table_name' from "
|
||||
"all_cons_columns%(dblink)s - does the user have "
|
||||
"proper rights to the table?") % {'dblink':dblink})
|
||||
"proper rights to the table?") % {'dblink': dblink})
|
||||
continue
|
||||
|
||||
rec = fkeys[cons_name]
|
||||
@@ -1128,7 +1215,7 @@ class OracleDialect(default.DefaultDialect):
|
||||
local_cols.append(local_column)
|
||||
remote_cols.append(remote_column)
|
||||
|
||||
return fkeys.values()
|
||||
return list(fkeys.values())
|
||||
|
||||
@reflection.cache
|
||||
def get_view_definition(self, connection, view_name, schema=None,
|
||||
@@ -1138,25 +1225,25 @@ class OracleDialect(default.DefaultDialect):
|
||||
self._prepare_reflection_args(connection, view_name, schema,
|
||||
resolve_synonyms, dblink,
|
||||
info_cache=info_cache)
|
||||
s = sql.text("""
|
||||
SELECT text FROM all_views
|
||||
WHERE owner = :schema
|
||||
AND view_name = :view_name
|
||||
""")
|
||||
rp = connection.execute(s,
|
||||
view_name=view_name, schema=schema).scalar()
|
||||
|
||||
params = {'view_name': view_name}
|
||||
text = "SELECT text FROM all_views WHERE view_name=:view_name"
|
||||
|
||||
if schema is not None:
|
||||
text += " AND owner = :schema"
|
||||
params['schema'] = schema
|
||||
|
||||
rp = connection.execute(sql.text(text), **params).scalar()
|
||||
if rp:
|
||||
return rp.decode(self.encoding)
|
||||
if util.py2k:
|
||||
rp = rp.decode(self.encoding)
|
||||
return rp
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
|
||||
class _OuterJoinColumn(sql.ClauseElement):
|
||||
__visit_name__ = 'outer_join_column'
|
||||
|
||||
def __init__(self, column):
|
||||
self.column = column
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user