Fixes issue 42042: Adds support for materialized views
authorAugusto Mauch <augusto.mauch@openbravo.com>
Wed, 27 Nov 2019 22:40:08 +0100
changeset 36839 e7f2c0e1b428
parent 36825 9d27d42bd426 (current diff)
parent 36838 d61d2d53638f (diff)
child 36840 ebfdf075a6f7
Fixes issue 42042: Adds support for materialized views

Dbsourcemanager supports now the definition of materialized views.

For more information check out the wiki entry:
http://wiki.openbravo.com/wiki/Projects:Support_Materialized_Views_In_DBSourceManager
--- a/src-db/database/build-create.xml	Wed Nov 27 10:49:02 2019 +0100
+++ b/src-db/database/build-create.xml	Wed Nov 27 22:40:08 2019 +0100
@@ -54,10 +54,19 @@
   </target>
 
 
+  <target name="clean.database.ORACLE">
+    <antcall target="clean.database.ORACLE.param">
+      <param name="driver" value="${bbdd.driver}"/>
+      <param name="url" value="${bbdd.url}"/>
+      <param name="systemUser" value="${bbdd.systemUser}"/>
+      <param name="user" value="${bbdd.user}"/>
+      <param name="systemPassword" value="${bbdd.systemPassword}"/>
+      <param name="sid" value="${bbdd.sid}"/>
+    </antcall>
+  </target>	
 
-
-  <target name="clean.database.ORACLE">
-    <sql driver="${bbdd.driver}" url="${bbdd.url}" userid="${bbdd.systemUser}" password="${bbdd.systemPassword}" onerror="continue" delimiter="/">
+  <target name="clean.database.ORACLE.param">
+    <sql driver="${driver}" url="${url}" userid="${systemUser}" password="${systemPassword}" onerror="continue" delimiter="/">
       <classpath>
         <fileset dir="${base.lib}">
           <include name="**/*.jar">
@@ -69,9 +78,9 @@
         DECLARE
           v_count NUMBER;
         BEGIN
-          SELECT COUNT(*) INTO v_count FROM dba_users WHERE UPPER(username) = UPPER('${bbdd.user}');
+          SELECT COUNT(*) INTO v_count FROM dba_users WHERE UPPER(username) = UPPER('${user}');
           IF (v_count > 0) THEN
-            EXECUTE IMMEDIATE 'DROP USER ${bbdd.user} CASCADE';
+            EXECUTE IMMEDIATE 'DROP USER ${user} CASCADE';
           END IF;
         END;
         /
@@ -79,8 +88,20 @@
     </sql>
   </target>
 
+	
   <target name="clean.database.POSTGRE">
-    <sql driver="${bbdd.driver}" url="${bbdd.url}/postgres" userid="${bbdd.systemUser}" password="${bbdd.systemPassword}" autocommit="true">
+    <antcall target="clean.database.POSTGRE.param">
+      <param name="driver" value="${bbdd.driver}"/>
+      <param name="url" value="${bbdd.url}/postgres"/>
+      <param name="systemUser" value="${bbdd.systemUser}"/>
+      <param name="user" value="${bbdd.user}"/>
+      <param name="systemPassword" value="${bbdd.systemPassword}"/>
+      <param name="sid" value="${bbdd.sid}"/>
+    </antcall>
+  </target>		
+	
+  <target name="clean.database.POSTGRE.param">
+    <sql driver="${driver}" url="${url}" userid="${systemUser}" password="${systemPassword}" autocommit="true">
       <classpath>
         <fileset dir="${base.lib}">
           <include name="**/*.jar">
@@ -88,10 +109,10 @@
         </fileset>
       </classpath>
       <transaction>
-        DROP DATABASE IF EXISTS ${bbdd.sid};
+        DROP DATABASE IF EXISTS ${sid};
       </transaction>
     </sql>
-    <sql driver="${bbdd.driver}" url="${bbdd.url}/postgres" userid="${bbdd.systemUser}" password="${bbdd.systemPassword}" onerror="continue" autocommit="true">
+    <sql driver="${driver}" url="${url}" userid="${systemUser}" password="${systemPassword}" onerror="continue" autocommit="true">
       <classpath>
         <fileset dir="${base.lib}">
           <include name="**/*.jar">
@@ -99,13 +120,25 @@
         </fileset>
       </classpath>
       <transaction>
-        DROP ROLE IF EXISTS ${bbdd.user};
+        DROP ROLE IF EXISTS ${user};
       </transaction>
     </sql>
   </target>
 
   <target name="ORACLE.structure">
-    <sql driver="${bbdd.driver}" url="${bbdd.url}" userid="${bbdd.systemUser}" password="${bbdd.systemPassword}" delimiter="/">
+    <antcall target="ORACLE.structure.param">
+      <param name="driver" value="${bbdd.driver}"/>
+      <param name="url" value="${bbdd.url}"/>
+      <param name="systemUser" value="${bbdd.systemUser}"/>
+      <param name="systemPassword" value="${bbdd.systemPassword}"/>
+      <param name="user" value="${bbdd.user}"/>
+      <param name="password" value="${bbdd.password}"/>
+      <param name="sid" value="${bbdd.sid}"/>
+    </antcall>
+  </target>	
+	
+  <target name="ORACLE.structure.param">
+    <sql driver="${driver}" url="${url}" userid="${systemUser}" password="${systemPassword}" delimiter="/">
       <classpath>
         <fileset dir="${base.lib}">
           <include name="**/*.jar">
@@ -117,7 +150,7 @@
         DECLARE
           v_count NUMBER;
         BEGIN
-          SELECT COUNT(*) INTO v_count FROM DBA_USERS WHERE UPPER(USERNAME) = UPPER('${bbdd.user}');
+          SELECT COUNT(*) INTO v_count FROM DBA_USERS WHERE UPPER(USERNAME) = UPPER('${user}');
           IF (v_count > 0) THEN
             RAISE_APPLICATION_ERROR(-20100, '${bbdd.user} ALREADY EXISTS. SELECT ANOTHER USER OR DROP IT FIRST');
           END IF;
@@ -126,7 +159,7 @@
       </transaction>
 
     </sql>
-    <sql driver="${bbdd.driver}" url="${bbdd.url}" userid="${bbdd.systemUser}" password="${bbdd.systemPassword}" onerror="continue">
+    <sql driver="${driver}" url="${url}" userid="${systemUser}" password="${systemPassword}" onerror="continue">
       <classpath>
         <fileset dir="${base.lib}">
           <include name="**/*.jar">
@@ -138,7 +171,7 @@
         ALTER SYSTEM SET OPEN_CURSORS = 10000 SCOPE=BOTH;
       </transaction>
     </sql>
-    <sql driver="${bbdd.driver}" url="${bbdd.url}" userid="${bbdd.systemUser}" password="${bbdd.systemPassword}">
+    <sql driver="${driver}" url="${url}" userid="${systemUser}" password="${systemPassword}">
       <classpath>
         <fileset dir="${base.lib}">
           <include name="**/*.jar">
@@ -147,26 +180,38 @@
       </classpath>
       <transaction>
         --CREATING USER
-        CREATE USER ${bbdd.user} IDENTIFIED BY ${bbdd.password}
+        CREATE USER ${user} IDENTIFIED BY ${password}
         DEFAULT TABLESPACE USERS
         TEMPORARY TABLESPACE TEMP;
 
         --GRANTING USER
-      	grant create session     	to ${bbdd.user};
-      	grant alter  session     	to ${bbdd.user};
-      	grant create table       	to ${bbdd.user};
-      	grant create procedure   	to ${bbdd.user};
-      	grant create trigger     	to ${bbdd.user};
-      	grant create view        	to ${bbdd.user};
-        grant create sequence    	to ${bbdd.user};
-        grant create materialized view 	to ${bbdd.user};
-      	alter user ${bbdd.user} quota unlimited on users;
+      	grant create session     	to ${user};
+      	grant alter  session     	to ${user};
+      	grant create table       	to ${user};
+      	grant create procedure   	to ${user};
+      	grant create trigger     	to ${user};
+      	grant create view        	to ${user};
+        grant create sequence    	to ${user};
+        grant create materialized view 	to ${user};
+      	alter user ${user} quota unlimited on users;
       </transaction>
     </sql>
   </target>
+	
+  <target name="POSTGRE.structure">
+    <antcall target="POSTGRE.structure.param">
+      <param name="driver" value="${bbdd.driver}"/>
+      <param name="url" value="${bbdd.url}/postgres"/>
+      <param name="systemUser" value="${bbdd.systemUser}"/>
+      <param name="systemPassword" value="${bbdd.systemPassword}"/>
+      <param name="user" value="${bbdd.user}"/>
+      <param name="password" value="${bbdd.password}"/>
+      <param name="sid" value="${bbdd.sid}"/>
+    </antcall>
+  </target>		
 
-  <target name="POSTGRE.structure">
-    <sql driver="${bbdd.driver}" url="${bbdd.url}/postgres" userid="${bbdd.systemUser}" password="${bbdd.systemPassword}" onerror="continue" autocommit="true">
+  <target name="POSTGRE.structure.param">
+    <sql driver="${driver}" url="${url}" userid="${systemUser}" password="${systemPassword}" onerror="continue" autocommit="true">
       <classpath>
         <fileset dir="${base.lib}">
           <include name="**/*.jar">
@@ -175,12 +220,12 @@
       </classpath>
       <transaction>
         --CREATING USER
-        CREATE ROLE ${bbdd.user} LOGIN PASSWORD '${bbdd.password}'
+        CREATE ROLE ${user} LOGIN PASSWORD '${password}'
                CREATEDB CREATEROLE
                VALID UNTIL 'infinity';
       </transaction>
     </sql>
-    <sql driver="${bbdd.driver}" url="${bbdd.url}/postgres" userid="${bbdd.user}" password="${bbdd.password}" autocommit="true">
+    <sql driver="${driver}" url="${url}" userid="${user}" password="${password}" autocommit="true">
       <classpath>
         <fileset dir="${base.lib}">
           <include name="**/*.jar">
@@ -188,7 +233,7 @@
         </fileset>
       </classpath>
       <transaction>
-        CREATE DATABASE ${bbdd.sid}
+        CREATE DATABASE ${sid}
                   WITH ENCODING='UTF8'
                   TEMPLATE=template0;
       </transaction>
Binary file src-db/database/lib/dbsourcemanager.jar has changed
--- a/src-db/database/model/prescript-Oracle.sql	Wed Nov 27 10:49:02 2019 +0100
+++ b/src-db/database/model/prescript-Oracle.sql	Wed Nov 27 22:40:08 2019 +0100
@@ -150,6 +150,9 @@
 for c1 in (select * from user_views order by view_name) loop
      v_md5 := dbms_obfuscation_toolkit.md5(input_string => v_md5||c1.view_name||c1.text);
 end loop;
+for c1 in (select * from user_mviews order by mview_name) loop
+     v_md5 := dbms_obfuscation_toolkit.md5(input_string => v_md5||c1.mview_name||c1.query);
+end loop;
 
 
   select db_checksum
--- a/src-db/database/model/prescript-PostgreSql.sql	Wed Nov 27 10:49:02 2019 +0100
+++ b/src-db/database/model/prescript-PostgreSql.sql	Wed Nov 27 22:40:08 2019 +0100
@@ -1141,28 +1141,28 @@
 /-- END
 
 CREATE OR REPLACE VIEW user_tab_columns AS
- SELECT upper(pg_class.relname::text) AS table_name, upper(pg_attribute.attname::text) AS column_name, 
-        (CASE WHEN upper(pg_type.typname::text)='NUMERIC' 
+ SELECT upper(c.relname::text) AS table_name, upper(a.attname::text) AS column_name, 
+        (CASE WHEN upper(t.typname::text)='NUMERIC' 
              THEN 'NUMBER'
-             ELSE upper(pg_type.typname::text)
+             ELSE upper(t.typname::text)
           END) AS data_type,
-        CASE pg_type.typname
-            WHEN 'varchar'::name THEN pg_attribute.atttypmod - 4
-            WHEN 'bpchar'::name THEN pg_attribute.atttypmod - 4
+        CASE t.typname
+            WHEN 'varchar'::name THEN a.atttypmod - 4
+            WHEN 'bpchar'::name THEN a.atttypmod - 4
             ELSE NULL::integer
         END AS char_col_decl_length,
 
-        CASE pg_type.typname
+        CASE t.typname
             WHEN 'bytea'::name THEN 4000
             WHEN 'text'::name THEN 4000
             WHEN 'oid'::name THEN 4000
-            ELSE CASE PG_ATTRIBUTE.ATTLEN 
-                     WHEN -1 THEN PG_ATTRIBUTE.ATTTYPMOD-4 
-                     ELSE PG_ATTRIBUTE.ATTLEN 
+            ELSE CASE a.ATTLEN 
+                     WHEN -1 THEN a.ATTTYPMOD-4 
+                     ELSE a.ATTLEN 
                  END
         END AS data_length,
 
-        CASE pg_type.typname
+        CASE t.typname
             WHEN 'bytea'::name THEN 4000
             WHEN 'text'::name THEN 4000
             WHEN 'oid'::name THEN 4000
@@ -1173,18 +1173,20 @@
                 END
         END AS data_precision,
         CASE 
-            WHEN upper(pg_type.typname) = 'NUMERIC' and cols.numeric_scale is not null THEN cols.numeric_scale
+            WHEN upper(t.typname) = 'NUMERIC' and cols.numeric_scale is not null THEN cols.numeric_scale
             ELSE 0
         END AS data_scale,
-        CASE pg_attribute.atthasdef
+        CASE a.atthasdef
             WHEN true THEN ( SELECT pg_get_expr(adbin, adrelid)
                FROM pg_attrdef
-              WHERE pg_attrdef.adrelid = pg_class.oid AND pg_attrdef.adnum = pg_attribute.attnum)
+              WHERE pg_attrdef.adrelid = c.oid AND pg_attrdef.adnum = a.attnum)
             ELSE NULL::text
-        END AS data_default, not pg_attribute.attnotnull AS nullable, pg_attribute.attnum AS column_id
-   FROM pg_class, pg_namespace, pg_attribute, pg_type, information_schema.columns cols
-  WHERE pg_attribute.attrelid = pg_class.oid AND pg_attribute.atttypid = pg_type.oid AND pg_class.relnamespace = pg_namespace.oid AND pg_namespace.nspname = current_schema() AND pg_attribute.attnum > 0 
-  AND upper(cols.table_name)=upper(pg_class.relname) AND upper(cols.column_name)=upper(pg_attribute.attname) AND cols.table_schema = current_schema()
+        END AS data_default, not a.attnotnull AS nullable, a.attnum AS column_id, a.*
+   FROM pg_class c JOIN pg_namespace n ON c.relnamespace = n.oid AND n.nspname = current_schema()
+   JOIN pg_attribute a ON a.attrelid = c.oid AND a.attnum > 0
+   JOIN pg_type t ON t.oid = a.atttypid 
+   LEFT JOIN information_schema.columns cols on upper(cols.table_name)=upper(c.relname) AND upper(cols.column_name)=upper(a.attname)
+   WHERE c.relkind in ('r', 'v', 'm')
 /-- END
 
 SELECT * FROM drop_view('v$version')
@@ -1481,6 +1483,34 @@
     end loop;
     
   end loop;
+  
+    --materialized views
+  for i in (
+          SELECT md5(upper(matviewname) ||  md5(upper(pg_get_viewdef(matviewname, true)))) as ck, matviewname
+            FROM pg_matviews 
+           WHERE schemaname = CURRENT_SCHEMA() 
+             AND matviewname !~ '^pg_' 
+        ORDER BY matviewname) loop
+    v_md5 := md5(v_md5||i.ck);
+    
+    -- indexes of materialized views
+    for j in (
+             SELECT md5(upper(pg_attribute.attname::text)||UPPER(PG_CLASS.RELNAME)||(CASE PG_INDEX.indisunique WHEN true THEN 'UNIQUE' ELSE 'NONUNIQUE' END)) as ck
+              FROM PG_INDEX, PG_CLASS, PG_CLASS PG_CLASS1, PG_NAMESPACE, pg_attribute
+              WHERE PG_INDEX.indexrelid = PG_CLASS.OID
+              AND PG_INDEX.indrelid = PG_CLASS1.OID
+              AND PG_CLASS.RELNAMESPACE = PG_NAMESPACE.OID
+              AND PG_CLASS1.RELNAMESPACE = PG_NAMESPACE.OID
+              AND PG_NAMESPACE.NSPNAME = CURRENT_SCHEMA()
+              AND PG_INDEX.INDISPRIMARY ='f'
+               AND pg_attribute.attrelid = pg_index.indrelid
+          AND pg_attribute.attnum = ANY (indkey)
+              AND PG_CLASS1.RELNAME = i.matviewname
+              ORDER BY UPPER(PG_CLASS.RELNAME), upper(pg_attribute.attname::text)) loop
+      v_md5 := md5(v_md5||j.ck);
+    end loop;    
+    
+  end loop;  
 
   select db_checksum
     into aux
--- a/src/org/openbravo/service/system/DatabaseValidator.java	Wed Nov 27 10:49:02 2019 +0100
+++ b/src/org/openbravo/service/system/DatabaseValidator.java	Wed Nov 27 22:40:08 2019 +0100
@@ -83,6 +83,12 @@
 
   @Override
   public SystemValidationResult validate() {
+    boolean checkAD = true;
+    return validate(checkAD);
+  }
+
+  @Override
+  public SystemValidationResult validate(boolean checkAD) {
     final SystemValidationResult result = new SystemValidationResult();
 
     // read the tables
@@ -160,103 +166,106 @@
       }
     }
 
-    // the following cases are checked:
-    // 1) table present in ad, but not in db
-    // 2) table present in db, not in ad
-    // 3) table present on both sides, column match check
+    if (checkAD) {
+      // the following cases are checked:
+      // 1) table present in ad, but not in db
+      // 2) table present in db, not in ad
+      // 3) table present on both sides, column match check
 
-    final Map<String, org.apache.ddlutils.model.Table> dbTablesByName = new HashMap<String, org.apache.ddlutils.model.Table>();
+      final Map<String, org.apache.ddlutils.model.Table> dbTablesByName = new HashMap<String, org.apache.ddlutils.model.Table>();
 
-    final org.apache.ddlutils.model.Table[] dbTables = getDatabase().getTables();
-    for (org.apache.ddlutils.model.Table dbTable : dbTables) {
-      dbTablesByName.put(dbTable.getName().toUpperCase(), dbTable);
-    }
+      final org.apache.ddlutils.model.Table[] dbTables = getDatabase().getTables();
+      for (org.apache.ddlutils.model.Table dbTable : dbTables) {
+        dbTablesByName.put(dbTable.getName().toUpperCase(), dbTable);
+      }
 
-    final org.apache.ddlutils.model.Table[] dbModifiedTables = getDatabase().getModifiedTables();
-    for (org.apache.ddlutils.model.Table dbModifiedTable : dbModifiedTables) {
-      dbTablesByName.put(dbModifiedTable.getName().toUpperCase(), dbModifiedTable);
-    }
-    final Map<String, org.apache.ddlutils.model.Table> tmpDBTablesByName = new HashMap<String, org.apache.ddlutils.model.Table>(
-        dbTablesByName);
+      final org.apache.ddlutils.model.Table[] dbModifiedTables = getDatabase().getModifiedTables();
+      for (org.apache.ddlutils.model.Table dbModifiedTable : dbModifiedTables) {
+        dbTablesByName.put(dbModifiedTable.getName().toUpperCase(), dbModifiedTable);
+      }
+      final Map<String, org.apache.ddlutils.model.Table> tmpDBTablesByName = new HashMap<String, org.apache.ddlutils.model.Table>(
+          dbTablesByName);
 
-    final Map<String, View> dbViews = new HashMap<String, View>();
-    final View[] views = getDatabase().getViews();
-    for (View view : views) {
-      dbViews.put(view.getName().toUpperCase(), view);
-    }
+      final Map<String, View> dbViews = new HashMap<String, View>();
+      final View[] views = getDatabase().getViews();
+      for (View view : views) {
+        dbViews.put(view.getName().toUpperCase(), view);
+      }
 
-    final List<Table> adTables = OBDal.getInstance()
-        .createCriteria(Table.class)
-        .add(Restrictions.eq(Table.PROPERTY_VIEW, false))
-        .add(Restrictions.eq(Table.PROPERTY_DATAORIGINTYPE, ApplicationConstants.TABLEBASEDTABLE))
-        .list();
+      final List<Table> adTables = OBDal.getInstance()
+          .createCriteria(Table.class)
+          .add(Restrictions.eq(Table.PROPERTY_VIEW, false))
+          .add(Restrictions.eq(Table.PROPERTY_DATAORIGINTYPE, ApplicationConstants.TABLEBASEDTABLE))
+          .list();
 
-    final String moduleId = (getValidateModule() == null ? null : getValidateModule().getId());
-    for (Table adTable : adTables) {
-      final org.apache.ddlutils.model.Table dbTable = dbTablesByName
-          .get(adTable.getDBTableName().toUpperCase());
-      final View view = dbViews.get(adTable.getDBTableName().toUpperCase());
+      final String moduleId = (getValidateModule() == null ? null : getValidateModule().getId());
+      for (Table adTable : adTables) {
+        final org.apache.ddlutils.model.Table dbTable = dbTablesByName
+            .get(adTable.getDBTableName().toUpperCase());
+        final View view = dbViews.get(adTable.getDBTableName().toUpperCase());
 
-      if (view == null && dbTable == null) {
-        // in Application Dictionary not in Physical Table
-        if (moduleId == null || (adTable.getDataPackage().getModule() != null
-            && adTable.getDataPackage().getModule().getId().equals(moduleId))) {
-          result.addError(SystemValidationResult.SystemValidationType.NOT_EXIST_IN_DB,
-              "Table " + adTable.getDBTableName() + " defined in the Application Dictionary"
-                  + " but is not present in the database");
+        if (view == null && dbTable == null) {
+          // in Application Dictionary not in Physical Table
+          if (moduleId == null || (adTable.getDataPackage().getModule() != null
+              && adTable.getDataPackage().getModule().getId().equals(moduleId))) {
+            result.addError(SystemValidationResult.SystemValidationType.NOT_EXIST_IN_DB,
+                "Table " + adTable.getDBTableName() + " defined in the Application Dictionary"
+                    + " but is not present in the database");
+          }
+        } else if (view != null) {
+          dbViews.remove(view.getName().toUpperCase());
+        } else {
+          if (moduleId == null || (adTable.getDataPackage().getModule() != null
+              && adTable.getDataPackage().getModule().getId().equals(moduleId))) {
+            checkTableWithoutPrimaryKey(dbTable, result);
+            checkMaxObjectNameLength(dbTable, result);
+          }
+          matchColumns(adTable, dbTable, result);
+          tmpDBTablesByName.remove(dbTable.getName().toUpperCase());
+          checkFieldsInGridView(adTable, result);
         }
-      } else if (view != null) {
-        dbViews.remove(view.getName().toUpperCase());
-      } else {
-        if (moduleId == null || (adTable.getDataPackage().getModule() != null
-            && adTable.getDataPackage().getModule().getId().equals(moduleId))) {
-          checkTableWithoutPrimaryKey(dbTable, result);
-          checkMaxObjectNameLength(dbTable, result);
-        }
-        matchColumns(adTable, dbTable, result);
-        tmpDBTablesByName.remove(dbTable.getName().toUpperCase());
-        checkFieldsInGridView(adTable, result);
       }
-    }
-    for (int i = 0; i < database.getTableCount(); i++) {
-      checkForeignKeys(validateModule, database.getTable(i), result);
-    }
-    for (int i = 0; i < database.getModifiedTableCount(); i++) {
-      checkForeignKeys(validateModule, database.getModifiedTable(i), result);
-    }
+      for (int i = 0; i < database.getTableCount(); i++) {
+        checkForeignKeys(validateModule, database.getTable(i), result);
+      }
+      for (int i = 0; i < database.getModifiedTableCount(); i++) {
+        checkForeignKeys(validateModule, database.getModifiedTable(i), result);
+      }
 
-    // only check this one if the global validate check is done
-    for (org.apache.ddlutils.model.Table dbTable : tmpDBTablesByName.values()) {
-      // ignore errors related to C_TEMP_SELECTION and AD_CONTEXT_INFO
-      if (!dbTable.getName().toUpperCase().startsWith("C_TEMP_SELECTION")
-          && !dbTable.getName().toUpperCase().startsWith("AD_CONTEXT_INFO")) {
-        result.addWarning(SystemValidationResult.SystemValidationType.NOT_EXIST_IN_AD,
-            "Table " + dbTable.getName() + " present in the database "
-                + " but not defined in the Application Dictionary");
-      }
-    }
-
-    if (getValidateModule() == null) {
-      for (View view : dbViews.values()) {
-        // ignore errors related to C_TEMP_SELECTION
-        if (!view.getName().toUpperCase().startsWith("C_TEMP_SELECTION")) {
+      // only check this one if the global validate check is done
+      for (org.apache.ddlutils.model.Table dbTable : tmpDBTablesByName.values()) {
+        // ignore errors related to C_TEMP_SELECTION and AD_CONTEXT_INFO
+        if (!dbTable.getName().toUpperCase().startsWith("C_TEMP_SELECTION")
+            && !dbTable.getName().toUpperCase().startsWith("AD_CONTEXT_INFO")) {
           result.addWarning(SystemValidationResult.SystemValidationType.NOT_EXIST_IN_AD,
-              "View " + view.getName() + " present in the database "
+              "Table " + dbTable.getName() + " present in the database "
                   + " but not defined in the Application Dictionary");
         }
       }
+
+      if (getValidateModule() == null) {
+        for (View view : dbViews.values()) {
+          // ignore errors related to C_TEMP_SELECTION
+          if (!view.getName().toUpperCase().startsWith("C_TEMP_SELECTION")) {
+            result.addWarning(SystemValidationResult.SystemValidationType.NOT_EXIST_IN_AD,
+                "View " + view.getName() + " present in the database "
+                    + " but not defined in the Application Dictionary");
+          }
+        }
+      }
+
+      checkIncorrectClientOrganizationName(result);
+
+      checkDBObjectsName(result);
+
+      checkDataSetName(result);
+
+      checkPasswordColumns(result);
+
+      checkKillableImplementation(result);
+
     }
 
-    checkIncorrectClientOrganizationName(result);
-
-    checkDBObjectsName(result);
-
-    checkDataSetName(result);
-
-    checkPasswordColumns(result);
-
-    checkKillableImplementation(result);
-
     OBDal.getInstance().getSession().clear();
     return result;
   }
--- a/src/org/openbravo/service/system/SystemService.java	Wed Nov 27 10:49:02 2019 +0100
+++ b/src/org/openbravo/service/system/SystemService.java	Wed Nov 27 22:40:08 2019 +0100
@@ -125,11 +125,28 @@
    * @return the validation result
    */
   public SystemValidationResult validateDatabase(Module module, Database database) {
+    boolean validateAD = true;
+    return validateDatabase(module, database, validateAD);
+  }
+
+  /**
+   * Validates the database for a specific module.
+   *
+   * @param module
+   *          the module to validate
+   * @param database
+   *          the database to read the dbschema from
+   * @param validateAD
+   *          a flag that determines if Application Dictionary checks should be done
+   * @return the validation result
+   */
+  public SystemValidationResult validateDatabase(Module module, Database database,
+      boolean validateAD) {
     final DatabaseValidator databaseValidator = new DatabaseValidator();
     databaseValidator.setValidateModule(module);
     databaseValidator.setDatabase(database);
     databaseValidator.setDbsmExecution(true);
-    return databaseValidator.validate();
+    return databaseValidator.validate(validateAD);
   }
 
   /**
--- a/src/org/openbravo/service/system/SystemValidator.java	Wed Nov 27 10:49:02 2019 +0100
+++ b/src/org/openbravo/service/system/SystemValidator.java	Wed Nov 27 22:40:08 2019 +0100
@@ -36,4 +36,11 @@
    * @return the result of the validation, warning and error messages.
    */
   public SystemValidationResult validate();
+
+  /**
+   * @return the result of the validation, warning and error messages.
+   */
+  public default SystemValidationResult validate(boolean checkAD) {
+    return validate();
+  }
 }