summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMariusz Felisiak <felisiak.mariusz@gmail.com>2018-11-26 19:45:05 +0100
committerGitHub <noreply@github.com>2018-11-26 19:45:05 +0100
commitf091ea35150d95fc6732bbf0c27b971dd445509a (patch)
tree254bdd5fee37cacef75eec92614f0e89fa4233ec
parent26c2a6ff883a213b4dcadf4411740aff866153ac (diff)
Refs #29722 -- Added introspection of materialized views for Oracle.
Thanks Tim Graham for the review.
-rw-r--r--django/db/backends/base/features.py3
-rw-r--r--django/db/backends/oracle/creation.py13
-rw-r--r--django/db/backends/oracle/features.py1
-rw-r--r--django/db/backends/oracle/introspection.py16
-rw-r--r--django/db/backends/postgresql/features.py1
-rw-r--r--docs/ref/databases.txt7
-rw-r--r--docs/ref/django-admin.txt6
-rw-r--r--docs/releases/2.2.txt2
-rw-r--r--tests/inspectdb/tests.py10
9 files changed, 43 insertions, 16 deletions
diff --git a/django/db/backends/base/features.py b/django/db/backends/base/features.py
index e07adb970d..56f7d4fb6a 100644
--- a/django/db/backends/base/features.py
+++ b/django/db/backends/base/features.py
@@ -151,6 +151,9 @@ class BaseDatabaseFeatures:
# Can the backend introspect the column order (ASC/DESC) for indexes?
supports_index_column_ordering = True
+ # Does the backend support introspection of materialized views?
+ can_introspect_materialized_views = False
+
# Support for the DISTINCT ON clause
can_distinct_on_fields = False
diff --git a/django/db/backends/oracle/creation.py b/django/db/backends/oracle/creation.py
index 98ea186dcb..741a03ae0e 100644
--- a/django/db/backends/oracle/creation.py
+++ b/django/db/backends/oracle/creation.py
@@ -241,11 +241,14 @@ class DatabaseCreation(BaseDatabaseCreation):
if not success and self._test_settings_get('PASSWORD') is None:
set_password = 'ALTER USER %(user)s IDENTIFIED BY "%(password)s"'
self._execute_statements(cursor, [set_password], parameters, verbosity)
- # Most test-suites can be run without the create-view privilege. But some need it.
- extra = "GRANT CREATE VIEW TO %(user)s"
- success = self._execute_allow_fail_statements(cursor, [extra], parameters, verbosity, 'ORA-01031')
- if not success and verbosity >= 2:
- self.log('Failed to grant CREATE VIEW permission to test user. This may be ok.')
+ # Most test suites can be run without "create view" and
+ # "create materialized view" privileges. But some need it.
+ for object_type in ('VIEW', 'MATERIALIZED VIEW'):
+ extra = 'GRANT CREATE %(object_type)s TO %(user)s'
+ parameters['object_type'] = object_type
+ success = self._execute_allow_fail_statements(cursor, [extra], parameters, verbosity, 'ORA-01031')
+ if not success and verbosity >= 2:
+ self.log('Failed to grant CREATE %s permission to test user. This may be ok.' % object_type)
def _execute_test_db_destruction(self, cursor, parameters, verbosity):
if verbosity >= 2:
diff --git a/django/db/backends/oracle/features.py b/django/db/backends/oracle/features.py
index 7e288e9840..7c72831c25 100644
--- a/django/db/backends/oracle/features.py
+++ b/django/db/backends/oracle/features.py
@@ -21,6 +21,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
truncates_names = True
supports_tablespaces = True
supports_sequence_reset = False
+ can_introspect_materialized_views = True
can_introspect_time_field = False
atomic_transactions = False
supports_combined_alters = False
diff --git a/django/db/backends/oracle/introspection.py b/django/db/backends/oracle/introspection.py
index 51566365bc..29193f0507 100644
--- a/django/db/backends/oracle/introspection.py
+++ b/django/db/backends/oracle/introspection.py
@@ -48,8 +48,20 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
def get_table_list(self, cursor):
"""Return a list of table and view names in the current database."""
- cursor.execute("SELECT TABLE_NAME, 't' FROM USER_TABLES UNION ALL "
- "SELECT VIEW_NAME, 'v' FROM USER_VIEWS")
+ cursor.execute("""
+ SELECT table_name, 't'
+ FROM user_tables
+ WHERE
+ NOT EXISTS (
+ SELECT 1
+ FROM user_mviews
+ WHERE user_mviews.mview_name = user_tables.table_name
+ )
+ UNION ALL
+ SELECT view_name, 'v' FROM user_views
+ UNION ALL
+ SELECT mview_name, 'v' FROM user_mviews
+ """)
return [TableInfo(self.identifier_converter(row[0]), row[1]) for row in cursor.fetchall()]
def get_table_description(self, cursor, table_name):
diff --git a/django/db/backends/postgresql/features.py b/django/db/backends/postgresql/features.py
index 89ff06fdf5..5c8701c396 100644
--- a/django/db/backends/postgresql/features.py
+++ b/django/db/backends/postgresql/features.py
@@ -21,6 +21,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
supports_transactions = True
can_introspect_autofield = True
can_introspect_ip_address_field = True
+ can_introspect_materialized_views = True
can_introspect_small_integer_field = True
can_distinct_on_fields = True
can_rollback_ddl = True
diff --git a/docs/ref/databases.txt b/docs/ref/databases.txt
index 39b3fb9898..98f14629bb 100644
--- a/docs/ref/databases.txt
+++ b/docs/ref/databases.txt
@@ -764,9 +764,10 @@ and a user granted ``RESOURCE WITH ADMIN OPTION`` can grant ``RESOURCE``, such
a user cannot grant the individual privileges (e.g. ``CREATE TABLE``), and thus
``RESOURCE WITH ADMIN OPTION`` is not usually sufficient for running tests.
-Some test suites also create views; to run these, the user also needs
-the ``CREATE VIEW WITH ADMIN OPTION`` privilege. In particular, this is needed
-for Django's own test suite.
+Some test suites also create views or materialized views; to run these, the
+user also needs ``CREATE VIEW WITH ADMIN OPTION`` and
+``CREATE MATERIALIZED VIEW WITH ADMIN OPTION`` privileges. In particular, this
+is needed for Django's own test suite.
All of these privileges are included in the DBA role, which is appropriate
for use on a private developer's database.
diff --git a/docs/ref/django-admin.txt b/docs/ref/django-admin.txt
index 6a3294788a..19f1d046fe 100644
--- a/docs/ref/django-admin.txt
+++ b/docs/ref/django-admin.txt
@@ -399,6 +399,12 @@ it because ``True`` is its default value).
Database-specific notes
~~~~~~~~~~~~~~~~~~~~~~~
+Oracle
+^^^^^^
+
+* Models are created for materialized views if :option:`--include-views` is
+ used.
+
PostgreSQL
^^^^^^^^^^
diff --git a/docs/releases/2.2.txt b/docs/releases/2.2.txt
index 8a15262ff9..7cabba3ad6 100644
--- a/docs/releases/2.2.txt
+++ b/docs/releases/2.2.txt
@@ -182,7 +182,7 @@ Management Commands
* :djadmin:`inspectdb` now creates models for foreign tables on PostgreSQL.
* :option:`inspectdb --include-views` now creates models for materialized views
- on PostgreSQL.
+ on Oracle and PostgreSQL.
* The new :option:`inspectdb --include-partitions` option allows creating
models for partition tables on PostgreSQL. In older versions, models are
diff --git a/tests/inspectdb/tests.py b/tests/inspectdb/tests.py
index 6452002c3e..c69eb8e49b 100644
--- a/tests/inspectdb/tests.py
+++ b/tests/inspectdb/tests.py
@@ -310,16 +310,16 @@ class InspectDBTransactionalTests(TransactionTestCase):
with connection.cursor() as cursor:
cursor.execute('DROP VIEW inspectdb_people_view')
- @skipUnless(connection.vendor == 'postgresql', 'PostgreSQL specific SQL')
+ @skipUnlessDBFeature('can_introspect_materialized_views')
def test_include_materialized_views(self):
- """inspectdb --include-views creates models for database materialized views."""
+ """inspectdb --include-views creates models for materialized views."""
with connection.cursor() as cursor:
cursor.execute(
- 'CREATE MATERIALIZED VIEW inspectdb_people_materialized_view AS '
+ 'CREATE MATERIALIZED VIEW inspectdb_people_materialized AS '
'SELECT id, name FROM inspectdb_people'
)
out = StringIO()
- view_model = 'class InspectdbPeopleMaterializedView(models.Model):'
+ view_model = 'class InspectdbPeopleMaterialized(models.Model):'
view_managed = 'managed = False # Created from a view.'
try:
call_command('inspectdb', table_name_filter=inspectdb_tables_only, stdout=out)
@@ -332,7 +332,7 @@ class InspectDBTransactionalTests(TransactionTestCase):
self.assertIn(view_managed, with_views_output)
finally:
with connection.cursor() as cursor:
- cursor.execute('DROP MATERIALIZED VIEW IF EXISTS inspectdb_people_materialized_view')
+ cursor.execute('DROP MATERIALIZED VIEW inspectdb_people_materialized')
@skipUnless(connection.vendor == 'postgresql', 'PostgreSQL specific SQL')
@skipUnlessDBFeature('supports_table_partitions')