Selaa lähdekoodia

Refs #29722 -- Added introspection of materialized views for Oracle.

Thanks Tim Graham for the review.
Mariusz Felisiak 6 vuotta sitten
vanhempi
commit
f091ea3515

+ 3 - 0
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
 

+ 8 - 5
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:

+ 1 - 0
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

+ 14 - 2
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):

+ 1 - 0
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

+ 4 - 3
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.

+ 6 - 0
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
 ^^^^^^^^^^
 

+ 1 - 1
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

+ 5 - 5
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')