Remove Elixir library

Update SQLAlchemy
This commit is contained in:
Ruud
2014-01-26 16:29:16 +01:00
parent f91081e39c
commit 1120b4ab51
178 changed files with 43610 additions and 35304 deletions
+283 -196
View File
@@ -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