Added :meth:`.Inspector.get_temp_table_names` and
:meth:`.Inspector.get_temp_view_names`; currently, only the
- SQLite dialect supports these methods. The return of temporary
- table and view names has been **removed** from SQLite's version
- of :meth:`.Inspector.get_table_names` and
+ SQLite and Oracle dialects support these methods. The return of
+ temporary table and view names has been **removed** from SQLite and
+ Oracle's version of :meth:`.Inspector.get_table_names` and
:meth:`.Inspector.get_view_names`; other database backends cannot
support this information (such as MySQL), and the scope of operation
is different in that the tables can be local to a session and
operation, such as an autoincremented primary key, a Python side
default, or a server-side default "eagerly" fetched via RETURNING.
+ .. change::
+ :tags: feature, oracle
+
+ Added support for the Oracle table option ON COMMIT.
+
.. change::
:tags: feature, postgresql
:tickets: 2051
.. _change_3204:
-SQLite has distinct methods for temporary table/view name reporting
--------------------------------------------------------------------
+SQLite/Oracle have distinct methods for temporary table/view name reporting
+---------------------------------------------------------------------------
The :meth:`.Inspector.get_table_names` and :meth:`.Inspector.get_view_names`
-methods in the case of SQLite would also return the names of temporary
+methods in the case of SQLite/Oracle would also return the names of temporary
tables and views, which is not provided by any other dialect (in the case
of MySQL at least it is not even possible). This logic has been moved
out to two new methods :meth:`.Inspector.get_temp_table_names` and
examining the type of column for use in special Python translations or
for migrating schemas to other database backends.
+Oracle Table Options
+-------------------------
+
+The CREATE TABLE phrase supports the following options with Oracle
+in conjunction with the :class:`.Table` construct:
+
+
+* ``ON COMMIT``::
+
+ Table(
+ "some_table", metadata, ...,
+ prefixes=['GLOBAL TEMPORARY'], oracle_on_commit='PRESERVE ROWS')
+
+.. versionadded:: 1.0.0
+
"""
import re
return super(OracleDDLCompiler, self).\
visit_create_index(create, include_schema=True)
+ def post_create_table(self, table):
+ table_opts = []
+ opts = table.dialect_options['oracle']
+
+ if opts['on_commit']:
+ on_commit_options = opts['on_commit'].replace("_", " ").upper()
+ table_opts.append('\n ON COMMIT %s' % on_commit_options)
+
+ return ''.join(table_opts)
+
class OracleIdentifierPreparer(compiler.IdentifierPreparer):
reflection_options = ('oracle_resolve_synonyms', )
construct_arguments = [
- (sa_schema.Table, {"resolve_synonyms": False})
+ (sa_schema.Table, {
+ "resolve_synonyms": False,
+ "on_commit": None
+ })
]
def __init__(self,
"WHERE nvl(tablespace_name, 'no tablespace') NOT IN "
"('SYSTEM', 'SYSAUX') "
"AND OWNER = :owner "
- "AND IOT_NAME IS NULL")
+ "AND IOT_NAME IS NULL "
+ "AND DURATION IS NULL")
+ cursor = connection.execute(s, owner=schema)
+ return [self.normalize_name(row[0]) for row in cursor]
+
+ @reflection.cache
+ def get_temp_table_names(self, connection, **kw):
+ schema = self.denormalize_name(self.default_schema_name)
+ s = sql.text(
+ "SELECT table_name FROM all_tables "
+ "WHERE nvl(tablespace_name, 'no tablespace') NOT IN "
+ "('SYSTEM', 'SYSAUX') "
+ "AND OWNER = :owner "
+ "AND IOT_NAME IS NULL "
+ "AND DURATION IS NOT NULL")
cursor = connection.execute(s, owner=schema)
return [self.normalize_name(row[0]) for row in cursor]
@classmethod
def define_temp_tables(cls, metadata):
- temp_table = Table(
+ # cheat a bit, we should fix this with some dialect-level
+ # temp table fixture
+ if testing.against("oracle"):
+ kw = {
+ 'prefixes': ["GLOBAL TEMPORARY"],
+ 'oracle_on_commit': 'PRESERVE ROWS'
+ }
+ else:
+ kw = {
+ 'prefixes': ["TEMPORARY"],
+ }
+
+ user_tmp = Table(
"user_tmp", metadata,
Column("id", sa.INT, primary_key=True),
Column('name', sa.VARCHAR(50)),
Column('foo', sa.INT),
sa.UniqueConstraint('name', name='user_tmp_uq'),
sa.Index("user_tmp_ix", "foo"),
- prefixes=['TEMPORARY']
+ **kw
)
if testing.requires.view_reflection.enabled and \
testing.requires.temporary_views.enabled:
event.listen(
- temp_table, "after_create",
+ user_tmp, "after_create",
DDL("create temporary view user_tmp_v as "
"select * from user_tmp")
)
@testing.requires.temp_table_names
def test_get_temp_table_names(self):
- insp = inspect(self.metadata.bind)
+ insp = inspect(testing.db)
temp_table_names = insp.get_temp_table_names()
eq_(sorted(temp_table_names), ['user_tmp'])
self._test_get_unique_constraints()
@testing.requires.temp_table_reflection
+ @testing.requires.unique_constraint_reflection
def test_get_temp_table_unique_constraints(self):
insp = inspect(self.metadata.bind)
eq_(
[{'unique': False, 'column_names': ['foo'], 'name': 'user_tmp_ix'}]
)
-
@testing.requires.unique_constraint_reflection
@testing.requires.schemas
def test_get_unique_constraints_with_schema(self):
"CREATE INDEX bar ON foo (x > 5)"
)
+ def test_table_options(self):
+ m = MetaData()
+
+ t = Table(
+ 'foo', m,
+ Column('x', Integer),
+ prefixes=["GLOBAL TEMPORARY"],
+ oracle_on_commit="PRESERVE ROWS"
+ )
+
+ self.assert_compile(
+ schema.CreateTable(t),
+ "CREATE GLOBAL TEMPORARY TABLE "
+ "foo (x INTEGER) ON COMMIT PRESERVE ROWS"
+ )
+
+
class CompatFlagsTest(fixtures.TestBase, AssertsCompiledSQL):
def _dialect(self, server_version, **kw):
def temp_table_names(self):
"""target dialect supports listing of temporary table names"""
- return only_on(['sqlite'])
+ return only_on(['sqlite', 'oracle'])
@property
def temporary_views(self):