diff --git a/web/pgadmin/browser/server_groups/servers/__init__.py b/web/pgadmin/browser/server_groups/servers/__init__.py
index a813f7a7c..28cab833e 100644
--- a/web/pgadmin/browser/server_groups/servers/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/__init__.py
@@ -28,6 +28,7 @@ from pgadmin.model import db, Server, ServerGroup, User
 from pgadmin.utils.driver import get_driver
 from pgadmin.utils.master_password import get_crypt_key
 from pgadmin.utils.exception import CryptKeyMissing
+from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
 from psycopg2 import Error as psycopg2_Error, OperationalError
 
 
@@ -1627,4 +1628,5 @@ class ServerNode(PGChildNodeView):
         )
 
 
+SchemaDiffRegistry('server', ServerNode)
 ServerNode.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/__init__.py
index c4cb71a11..4932a7971 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/__init__.py
@@ -30,6 +30,8 @@ from pgadmin.utils.ajax import make_json_response, \
     make_response as ajax_response, internal_server_error, unauthorized
 from pgadmin.utils.driver import get_driver
 from pgadmin.tools.sqleditor.utils.query_history import QueryHistory
+
+from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
 from pgadmin.model import Server
 
 
@@ -1111,4 +1113,5 @@ class DatabaseView(PGChildNodeView):
         )
 
 
+SchemaDiffRegistry('database', DatabaseView)
 DatabaseView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/__init__.py
index 72c2df5a9..7d0b8960f 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/__init__.py
@@ -23,6 +23,7 @@ from pgadmin.browser.utils import PGChildNodeView
 from pgadmin.utils.ajax import make_json_response, internal_server_error, \
     make_response as ajax_response, gone, bad_request
 from pgadmin.utils.driver import get_driver
+from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
 
 """
     This module is responsible for generating two nodes
@@ -1023,5 +1024,6 @@ It may have been removed by another user.
         return ajax_response(response=SQL.strip("\n"))
 
 
+SchemaDiffRegistry('schema', SchemaView)
 SchemaView.register_node_view(schema_blueprint)
 CatalogView.register_node_view(catalog_blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/collations/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/collations/__init__.py
index dd6064573..fac184fd5 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/collations/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/collations/__init__.py
@@ -25,6 +25,8 @@ from pgadmin.utils.ajax import make_json_response, internal_server_error, \
     make_response as ajax_response, gone
 from pgadmin.utils.compile_template_name import compile_template_path
 from pgadmin.utils.driver import get_driver
+from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
+from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
 
 # If we are in Python3
 if not IS_PY2:
@@ -92,7 +94,7 @@ class CollationModule(SchemaChildModule):
 blueprint = CollationModule(__name__)
 
 
-class CollationView(PGChildNodeView):
+class CollationView(PGChildNodeView, SchemaDiffObjectCompare):
     """
     This class is responsible for generating routes for Collation node
 
@@ -144,6 +146,10 @@ class CollationView(PGChildNodeView):
     * dependent(gid, sid, did, scid):
       - This function will generate dependent list to show it in dependent
         pane for the selected Collation node.
+
+    * compare(**kwargs):
+      - This function will compare the collation nodes from two different
+        schemas.
     """
 
     node_type = blueprint.node_type
@@ -172,7 +178,8 @@ class CollationView(PGChildNodeView):
         'dependency': [{'get': 'dependencies'}],
         'dependent': [{'get': 'dependents'}],
         'get_collations': [{'get': 'get_collation'},
-                           {'get': 'get_collation'}]
+                           {'get': 'get_collation'}],
+        'compare': [{'get': 'compare'}, {'get': 'compare'}]
     })
 
     def check_precondition(f):
@@ -318,23 +325,36 @@ class CollationView(PGChildNodeView):
             JSON of selected collation node
         """
 
+        status, res = self._fetch_properties(scid, coid)
+        if not status:
+            return res
+
+        return ajax_response(
+            response=res,
+            status=200
+        )
+
+    def _fetch_properties(self, scid, coid):
+        """
+        This function fetch the properties for the specified object.
+
+        :param scid: Schema ID
+        :param coid: Collation ID
+        """
+
         SQL = render_template("/".join([self.template_path,
                                         'properties.sql']),
                               scid=scid, coid=coid)
         status, res = self.conn.execute_dict(SQL)
 
         if not status:
-            return internal_server_error(errormsg=res)
+            return False, internal_server_error(errormsg=res)
 
         if len(res['rows']) == 0:
-            return gone(
-                gettext("Could not find the collation object in the database.")
-            )
+            return False, gone(gettext("Could not find the collation "
+                                       "object in the database."))
 
-        return ajax_response(
-            response=res['rows'][0],
-            status=200
-        )
+        return True, res['rows'][0]
 
     @check_precondition
     def get_collation(self, gid, sid, did, scid, coid=None):
@@ -748,5 +768,30 @@ class CollationView(PGChildNodeView):
             status=200
         )
 
+    @check_precondition
+    def fetch_objects_to_compare(self, sid, did, scid):
+        """
+        This function will fetch the list of all the collations for
+        specified schema id.
+
+        :param sid: Server Id
+        :param did: Database Id
+        :param scid: Schema Id
+        :return:
+        """
+        res = dict()
+        SQL = render_template("/".join([self.template_path,
+                                        'nodes.sql']), scid=scid)
+        status, rset = self.conn.execute_2darray(SQL)
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        for row in rset['rows']:
+            status, data = self._fetch_properties(scid, row['oid'])
+            if status:
+                res[row['name']] = data
+
+        return res
+
 
 CollationView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/__init__.py
index 20e477986..6fdcace84 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/__init__.py
@@ -27,6 +27,8 @@ from pgadmin.utils.ajax import make_json_response, internal_server_error, \
     make_response as ajax_response, gone
 from pgadmin.utils.compile_template_name import compile_template_path
 from pgadmin.utils.driver import get_driver
+from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
+from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
 
 # If we are in Python3
 if not IS_PY2:
@@ -79,7 +81,7 @@ class DomainModule(SchemaChildModule):
 blueprint = DomainModule(__name__)
 
 
-class DomainView(PGChildNodeView, DataTypeReader):
+class DomainView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
     """
     class DomainView
 
@@ -138,6 +140,10 @@ class DomainView(PGChildNodeView, DataTypeReader):
 
     * types(gid, sid, did, scid, fnid=None):
       - Returns Data Types.
+
+    * compare(**kwargs):
+      - This function will compare the domain nodes from two different
+        schemas.
     """
 
     node_type = blueprint.node_type
@@ -169,7 +175,8 @@ class DomainView(PGChildNodeView, DataTypeReader):
         'get_collations': [
             {'get': 'get_collations'},
             {'get': 'get_collations'}
-        ]
+        ],
+        'compare': [{'get': 'compare'}, {'get': 'compare'}]
     })
 
     def validate_request(f):
@@ -369,15 +376,31 @@ class DomainView(PGChildNodeView, DataTypeReader):
             scid: Schema Id
             doid: Domain Id
         """
+        status, res = self._fetch_properties(did, scid, doid)
+        if not status:
+            return res
+
+        return ajax_response(
+            response=res,
+            status=200
+        )
 
+    def _fetch_properties(self, did, scid, doid):
+        """
+        This function is used to fecth the properties of specified object.
+        :param did:
+        :param scid:
+        :param doid:
+        :return:
+        """
         SQL = render_template("/".join([self.template_path, 'properties.sql']),
                               scid=scid, doid=doid)
         status, res = self.conn.execute_dict(SQL)
         if not status:
-            return internal_server_error(errormsg=res)
+            return False, internal_server_error(errormsg=res)
 
         if len(res['rows']) == 0:
-            return gone(gettext("""
+            return False, gone(gettext("""
 Could not find the domain in the database.
 It may have been removed by another user or moved to another schema.
 """))
@@ -393,7 +416,7 @@ It may have been removed by another user or moved to another schema.
                               doid=doid)
         status, res = self.conn.execute_dict(SQL)
         if not status:
-            return internal_server_error(errormsg=res)
+            return False, internal_server_error(errormsg=res)
 
         data['constraints'] = res['rows']
 
@@ -406,10 +429,7 @@ It may have been removed by another user or moved to another schema.
         if doid <= self.manager.db_info[did]['datlastsysoid']:
             data['sysdomain'] = True
 
-        return ajax_response(
-            response=data,
-            status=200
-        )
+        return True, data
 
     def _parse_type(self, basetype):
         """
@@ -664,7 +684,7 @@ AND relkind != 'c'))"""
         )
 
     @check_precondition
-    def sql(self, gid, sid, did, scid, doid=None):
+    def sql(self, gid, sid, did, scid, doid=None, return_ajax_response=True):
         """
         Returns the SQL for the Domain object.
 
@@ -674,6 +694,7 @@ AND relkind != 'c'))"""
             did: Database Id
             scid: Schema Id
             doid: Domain Id
+            return_ajax_response:
         """
 
         SQL = render_template("/".join([self.template_path,
@@ -716,6 +737,9 @@ AND relkind != 'c'))"""
 """.format(self.qtIdent(self.conn, data['basensp'], data['name']))
         SQL = sql_header + SQL
 
+        if not return_ajax_response:
+            return SQL.strip('\n')
+
         return ajax_response(response=SQL.strip('\n'))
 
     @check_precondition
@@ -846,5 +870,40 @@ AND relkind != 'c'))"""
             status=200
         )
 
+    @check_precondition
+    def fetch_objects_to_compare(self, sid, did, scid):
+        """
+        This function will fetch the list of all the domains for
+        specified schema id.
+
+        :param sid: Server Id
+        :param did: Database Id
+        :param scid: Schema Id
+        :return:
+        """
+        res = dict()
+        SQL = render_template("/".join([self.template_path,
+                                        'node.sql']), scid=scid)
+        status, rset = self.conn.execute_2darray(SQL)
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        for row in rset['rows']:
+            status, data = self._fetch_properties(did, scid, row['oid'])
+
+            if status:
+                if 'constraints' in data and len(data['constraints']) > 0:
+                    for item in data['constraints']:
+                        # Remove keys that should not be the part
+                        # of comparision.
+                        if 'conoid' in item:
+                            item.pop('conoid')
+                        if 'nspname' in item:
+                            item.pop('nspname')
+
+                res[row['name']] = data
+
+        return res
+
 
 DomainView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/get_constraints.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/get_constraints.sql
index df956bf9a..676c5a6e2 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/get_constraints.sql
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/9.2_plus/get_constraints.sql
@@ -8,7 +8,7 @@ JOIN
 JOIN
     pg_namespace nl ON nl.oid=typnamespace
 LEFT OUTER JOIN
-    pg_description des ON (des.objoid=t.oid AND des.classoid='pg_constraint'::regclass)
+    pg_description des ON (des.objoid=c.oid AND des.classoid='pg_constraint'::regclass)
 WHERE
     contype = 'c' AND contypid =  {{doid}}::oid
 ORDER BY
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/default/get_constraints.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/default/get_constraints.sql
index 897fb2477..b99f855a8 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/default/get_constraints.sql
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/templates/domains/sql/default/get_constraints.sql
@@ -8,7 +8,7 @@ JOIN
 JOIN
     pg_namespace nl ON nl.oid=typnamespace
 LEFT OUTER JOIN
-    pg_description des ON (des.objoid=t.oid AND des.classoid='pg_constraint'::regclass)
+    pg_description des ON (des.objoid=c.oid AND des.classoid='pg_constraint'::regclass)
 WHERE
     contype = 'c'
     AND contypid =  {{doid}}::oid
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/foreign_tables/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/foreign_tables/__init__.py
index 75702a557..1be76c906 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/foreign_tables/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/foreign_tables/__init__.py
@@ -32,6 +32,8 @@ from pgadmin.utils.ajax import make_json_response, internal_server_error, \
     make_response as ajax_response, gone
 from pgadmin.utils.compile_template_name import compile_template_path
 from pgadmin.utils.driver import get_driver
+from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
+from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
 
 # If we are in Python3
 if not IS_PY2:
@@ -93,7 +95,8 @@ class ForeignTableModule(SchemaChildModule):
 blueprint = ForeignTableModule(__name__)
 
 
-class ForeignTableView(PGChildNodeView, DataTypeReader):
+class ForeignTableView(PGChildNodeView, DataTypeReader,
+                       SchemaDiffObjectCompare):
     """
     class ForeignTableView(PGChildNodeView)
 
@@ -174,6 +177,9 @@ class ForeignTableView(PGChildNodeView, DataTypeReader):
     * delete_sql(gid, sid, did, scid, foid):
       - Returns sql for Script
 
+    * compare(**kwargs):
+      - This function will compare the foreign table nodes from two different
+        schemas.
     """
 
     node_type = blueprint.node_type
@@ -213,7 +219,8 @@ class ForeignTableView(PGChildNodeView, DataTypeReader):
         'select_sql': [{'get': 'select_sql'}],
         'insert_sql': [{'get': 'insert_sql'}],
         'update_sql': [{'get': 'update_sql'}],
-        'delete_sql': [{'get': 'delete_sql'}]
+        'delete_sql': [{'get': 'delete_sql'}],
+        'compare': [{'get': 'compare'}, {'get': 'compare'}]
     })
 
     def validate_request(f):
@@ -447,11 +454,9 @@ class ForeignTableView(PGChildNodeView, DataTypeReader):
             scid: Schema Id
             foid: Foreign Table Id
         """
-        data = self._fetch_properties(gid, sid, did, scid, foid)
-        if data is False:
-            return gone(
-                gettext("Could not find the foreign table on the server.")
-            )
+        status, data = self._fetch_properties(gid, sid, did, scid, foid)
+        if not status:
+            return data
 
         return ajax_response(
             response=data,
@@ -814,11 +819,10 @@ class ForeignTableView(PGChildNodeView, DataTypeReader):
             scid: Schema Id
             foid: Foreign Table Id
         """
-        data = self._fetch_properties(gid, sid, did, scid, foid, inherits=True)
-        if data is False:
-            return gone(
-                gettext("Could not find the foreign table on the server.")
-            )
+        status, data = self._fetch_properties(gid, sid, did, scid, foid,
+                                              inherits=True)
+        if not status:
+            return data
 
         col_data = []
         for c in data['columns']:
@@ -891,12 +895,10 @@ class ForeignTableView(PGChildNodeView, DataTypeReader):
             foid: Foreign Table Id
         """
         if foid is not None:
-            old_data = self._fetch_properties(gid, sid, did, scid, foid,
-                                              inherits=True)
-            if old_data is False:
-                return gone(
-                    gettext("Could not find the foreign table on the server.")
-                )
+            status, old_data = self._fetch_properties(gid, sid, did, scid,
+                                                      foid, inherits=True)
+            if not status:
+                return old_data
 
             # Prepare dict of columns with key = column's attnum
             # Will use this in the update template when any column is
@@ -1051,10 +1053,10 @@ class ForeignTableView(PGChildNodeView, DataTypeReader):
                               scid=scid, foid=foid)
         status, res = self.conn.execute_dict(SQL)
         if not status:
-            return internal_server_error(errormsg=res)
+            return False, internal_server_error(errormsg=res)
 
         if len(res['rows']) == 0:
-            return False
+            return False, False
 
         data = res['rows'][0]
 
@@ -1064,7 +1066,7 @@ class ForeignTableView(PGChildNodeView, DataTypeReader):
                                   foid=foid)
             status, aclres = self.conn.execute_dict(SQL)
             if not status:
-                return internal_server_error(errormsg=aclres)
+                return False, internal_server_error(errormsg=aclres)
 
             # Get Formatted Privileges
             data.update(self._format_proacl_from_db(aclres['rows']))
@@ -1082,7 +1084,7 @@ class ForeignTableView(PGChildNodeView, DataTypeReader):
                                         'get_constraints.sql']), foid=foid)
         status, cons = self.conn.execute_dict(SQL)
         if not status:
-            return internal_server_error(errormsg=cons)
+            return False, internal_server_error(errormsg=cons)
 
         if cons and 'rows' in cons:
             data['constraints'] = cons['rows']
@@ -1091,7 +1093,7 @@ class ForeignTableView(PGChildNodeView, DataTypeReader):
                                         'get_columns.sql']), foid=foid)
         status, cols = self.conn.execute_dict(SQL)
         if not status:
-            return internal_server_error(errormsg=cols)
+            return False, internal_server_error(errormsg=cols)
 
         # The Length and the precision of the Datatype should be separated.
         # The Format we getting from database is: numeric(1,1)
@@ -1128,12 +1130,12 @@ class ForeignTableView(PGChildNodeView, DataTypeReader):
                 status, res = self.conn.execute_dict(SQL)
 
                 if not status:
-                    return internal_server_error(errormsg=res)
+                    return False, internal_server_error(errormsg=res)
 
                 if 'inherits' in res['rows'][0]:
                     data['inherits'] = res['rows'][0]['inherits']
 
-        return data
+        return True, data
 
     @staticmethod
     def convert_precision_to_int(typlen):
@@ -1222,11 +1224,9 @@ class ForeignTableView(PGChildNodeView, DataTypeReader):
         Returns:
             SELECT Script sql for the object
         """
-        data = self._fetch_properties(gid, sid, did, scid, foid)
-        if data is False:
-            return gone(
-                gettext("Could not find the foreign table on the server.")
-            )
+        status, data = self._fetch_properties(gid, sid, did, scid, foid)
+        if not status:
+            return data
 
         columns = []
         for c in data['columns']:
@@ -1259,11 +1259,9 @@ class ForeignTableView(PGChildNodeView, DataTypeReader):
         Returns:
             INSERT Script sql for the object
         """
-        data = self._fetch_properties(gid, sid, did, scid, foid)
-        if data is False:
-            return gone(
-                gettext("Could not find the foreign table on the server.")
-            )
+        status, data = self._fetch_properties(gid, sid, did, scid, foid)
+        if not status:
+            return data
 
         columns = []
         values = []
@@ -1301,11 +1299,9 @@ class ForeignTableView(PGChildNodeView, DataTypeReader):
         Returns:
             UPDATE Script sql for the object
         """
-        data = self._fetch_properties(gid, sid, did, scid, foid)
-        if data is False:
-            return gone(
-                gettext("Could not find the foreign table on the server.")
-            )
+        status, data = self._fetch_properties(gid, sid, did, scid, foid)
+        if not status:
+            return data
 
         columns = []
 
@@ -1346,11 +1342,9 @@ class ForeignTableView(PGChildNodeView, DataTypeReader):
         Returns:
             DELETE Script sql for the object
         """
-        data = self._fetch_properties(gid, sid, did, scid, foid)
-        if data is False:
-            return gone(
-                gettext("Could not find the foreign table on the server.")
-            )
+        status, data = self._fetch_properties(gid, sid, did, scid, foid)
+        if not status:
+            return data
 
         sql = u"DELETE FROM {0}\n\tWHERE <condition>;".format(
             self.qtIdent(self.conn, data['basensp'], data['name'])
@@ -1358,5 +1352,37 @@ class ForeignTableView(PGChildNodeView, DataTypeReader):
 
         return ajax_response(response=sql)
 
+    @check_precondition
+    def fetch_objects_to_compare(self, sid, did, scid):
+        """
+        This function will fetch the list of all the foreign tables for
+        specified schema id.
+
+        :param sid: Server Id
+        :param did: Database Id
+        :param scid: Schema Id
+        :return:
+        """
+        res = dict()
+        SQL = render_template("/".join([self.template_path,
+                                        'node.sql']), scid=scid)
+        status, rset = self.conn.execute_2darray(SQL)
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        for row in rset['rows']:
+            status, data = self._fetch_properties(0, sid, did, scid,
+                                                  row['oid'])
+            if status:
+                if 'constraints' in data and data['constraints'] is not None \
+                        and len(data['constraints']) > 0:
+                    for item in data['constraints']:
+                        if 'conoid' in item:
+                            item.pop('conoid')
+
+                res[row['name']] = data
+
+        return res
+
 
 ForeignTableView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_configurations/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_configurations/__init__.py
index 4aa6cc2b4..4e65961de 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_configurations/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_configurations/__init__.py
@@ -24,6 +24,8 @@ from pgadmin.utils import IS_PY2
 from pgadmin.utils.ajax import make_json_response, internal_server_error, \
     make_response as ajax_response, gone
 from pgadmin.utils.driver import get_driver
+from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
+from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
 
 # If we are in Python3
 if not IS_PY2:
@@ -93,7 +95,7 @@ class FtsConfigurationModule(SchemaChildModule):
 blueprint = FtsConfigurationModule(__name__)
 
 
-class FtsConfigurationView(PGChildNodeView):
+class FtsConfigurationView(PGChildNodeView, SchemaDiffObjectCompare):
     """
     class FtsConfigurationView(PGChildNodeView)
 
@@ -167,6 +169,9 @@ class FtsConfigurationView(PGChildNodeView):
     * dependencies(self, gid, sid, did, scid, cfgid):
       - This function get the dependencies and return ajax response for node.
 
+    * compare(**kwargs):
+      - This function will compare the fts configuration nodes from two
+        different schemas.
     """
 
     node_type = blueprint.node_type
@@ -202,6 +207,7 @@ class FtsConfigurationView(PGChildNodeView):
                        {'get': 'copyConfig'}],
         'tokens': [{'get': 'tokens'}, {'get': 'tokens'}],
         'dictionaries': [{}, {'get': 'dictionaries'}],
+        'compare': [{'get': 'compare'}, {'get': 'compare'}]
     })
 
     def _init_(self, **kwargs):
@@ -343,7 +349,22 @@ class FtsConfigurationView(PGChildNodeView):
             scid: Schema Id
             cfgid: fts Configuration id
         """
+        status, res = self._fetch_properties(scid, cfgid)
+        if not status:
+            return res
+
+        return ajax_response(
+            response=res,
+            status=200
+        )
 
+    def _fetch_properties(self, scid, cfgid):
+        """
+        This function is used to fetch property of specified object.
+        :param scid:
+        :param cfgid:
+        :return:
+        """
         sql = render_template(
             "/".join([self.template_path, 'properties.sql']),
             scid=scid,
@@ -352,10 +373,10 @@ class FtsConfigurationView(PGChildNodeView):
         status, res = self.conn.execute_dict(sql)
 
         if not status:
-            return internal_server_error(errormsg=res)
+            return False, internal_server_error(errormsg=res)
 
         if len(res['rows']) == 0:
-            return gone(
+            return False, gone(
                 _(
                     "Could not find the FTS Configuration node in the "
                     "database node.")
@@ -370,14 +391,11 @@ class FtsConfigurationView(PGChildNodeView):
         status, rset = self.conn.execute_dict(sql)
 
         if not status:
-            return internal_server_error(errormsg=rset)
+            return False, internal_server_error(errormsg=rset)
 
         res['rows'][0]['tokens'] = rset['rows']
 
-        return ajax_response(
-            response=res['rows'][0],
-            status=200
-        )
+        return True, res['rows'][0]
 
     @check_precondition
     def create(self, gid, sid, did, scid):
@@ -927,5 +945,30 @@ class FtsConfigurationView(PGChildNodeView):
             status=200
         )
 
+    @check_precondition
+    def fetch_objects_to_compare(self, sid, did, scid):
+        """
+        This function will fetch the list of all the fts configurations for
+        specified schema id.
+
+        :param sid: Server Id
+        :param did: Database Id
+        :param scid: Schema Id
+        :return:
+        """
+        res = dict()
+        SQL = render_template("/".join([self.template_path,
+                                        'nodes.sql']), scid=scid)
+        status, fts_cfg = self.conn.execute_2darray(SQL)
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        for row in fts_cfg['rows']:
+            status, data = self._fetch_properties(scid, row['oid'])
+            if status:
+                res[row['name']] = data
+
+        return res
+
 
 FtsConfigurationView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_dictionaries/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_dictionaries/__init__.py
index f69f3af7f..358882cdb 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_dictionaries/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_dictionaries/__init__.py
@@ -24,6 +24,8 @@ from pgadmin.utils import IS_PY2
 from pgadmin.utils.ajax import make_json_response, internal_server_error, \
     make_response as ajax_response, gone
 from pgadmin.utils.driver import get_driver
+from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
+from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
 
 # If we are in Python3
 if not IS_PY2:
@@ -91,7 +93,7 @@ class FtsDictionaryModule(SchemaChildModule):
 blueprint = FtsDictionaryModule(__name__)
 
 
-class FtsDictionaryView(PGChildNodeView):
+class FtsDictionaryView(PGChildNodeView, SchemaDiffObjectCompare):
     """
     class FtsDictionaryView(PGChildNodeView)
 
@@ -159,6 +161,9 @@ class FtsDictionaryView(PGChildNodeView):
     * dependencies(self, gid, sid, did, scid, dcid):
       - This function get the dependencies and return ajax response for node.
 
+    * compare(**kwargs):
+      - This function will compare the fts dictionaries nodes from two
+        different schemas.
     """
 
     node_type = blueprint.node_type
@@ -189,7 +194,7 @@ class FtsDictionaryView(PGChildNodeView):
         'dependency': [{'get': 'dependencies'}],
         'dependent': [{'get': 'dependents'}],
         'fetch_templates': [{'get': 'fetch_templates'},
-                            {'get': 'fetch_templates'}],
+                            {'get': 'fetch_templates'}]
     })
 
     def _init_(self, **kwargs):
@@ -353,7 +358,23 @@ class FtsDictionaryView(PGChildNodeView):
             scid: Schema Id
             dcid: fts dictionary id
         """
+        status, res = self._fetch_properties(scid, dcid)
+        if not status:
+            return res
+
+        return ajax_response(
+            response=res,
+            status=200
+        )
+
+    def _fetch_properties(self, scid, dcid):
+        """
+        This function is used to fetch the properties of specified object.
 
+        :param scid:
+        :param dcid:
+        :return:
+        """
         sql = render_template(
             "/".join([self.template_path, 'properties.sql']),
             scid=scid,
@@ -362,10 +383,10 @@ class FtsDictionaryView(PGChildNodeView):
         status, res = self.conn.execute_dict(sql)
 
         if not status:
-            return internal_server_error(errormsg=res)
+            return False, internal_server_error(errormsg=res)
 
         if len(res['rows']) == 0:
-            return gone(_(
+            return False, gone(_(
                 "Could not find the FTS Dictionary node in the database node."
             ))
 
@@ -382,10 +403,7 @@ class FtsDictionaryView(PGChildNodeView):
                 res['rows'][0]['options']
             )
 
-        return ajax_response(
-            response=res['rows'][0],
-            status=200
-        )
+        return True, res['rows'][0]
 
     @check_precondition
     def create(self, gid, sid, did, scid):
@@ -854,5 +872,30 @@ class FtsDictionaryView(PGChildNodeView):
             status=200
         )
 
+    @check_precondition
+    def fetch_objects_to_compare(self, sid, did, scid):
+        """
+        This function will fetch the list of all the fts dictionaries for
+        specified schema id.
+
+        :param sid: Server Id
+        :param did: Database Id
+        :param scid: Schema Id
+        :return:
+        """
+        res = dict()
+        SQL = render_template("/".join([self.template_path,
+                                        'nodes.sql']), scid=scid)
+        status, rset = self.conn.execute_2darray(SQL)
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        for row in rset['rows']:
+            status, data = self._fetch_properties(scid, row['oid'])
+            if status:
+                res[row['name']] = data
+
+        return res
+
 
 FtsDictionaryView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_parsers/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_parsers/__init__.py
index 384ae62e8..09a445723 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_parsers/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_parsers/__init__.py
@@ -24,6 +24,8 @@ from pgadmin.utils import IS_PY2
 from pgadmin.utils.ajax import make_json_response, internal_server_error, \
     make_response as ajax_response, gone
 from pgadmin.utils.driver import get_driver
+from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
+from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
 
 # If we are in Python3
 if not IS_PY2:
@@ -84,7 +86,7 @@ class FtsParserModule(SchemaChildModule):
 blueprint = FtsParserModule(__name__)
 
 
-class FtsParserView(PGChildNodeView):
+class FtsParserView(PGChildNodeView, SchemaDiffObjectCompare):
     """
     class FtsParserView(PGChildNodeView)
 
@@ -161,6 +163,9 @@ class FtsParserView(PGChildNodeView):
       - This function get the dependencies and return ajax response for
         FTS Parser node.
 
+    * compare(**kwargs):
+      - This function will compare the fts parser nodes from two
+        different schemas.
     """
 
     node_type = blueprint.node_type
@@ -198,7 +203,7 @@ class FtsParserView(PGChildNodeView):
         'lextype_functions': [{'get': 'lextype_functions'},
                               {'get': 'lextype_functions'}],
         'headline_functions': [{'get': 'headline_functions'},
-                               {'get': 'headline_functions'}],
+                               {'get': 'headline_functions'}]
     })
 
     def _init_(self, **kwargs):
@@ -303,6 +308,32 @@ class FtsParserView(PGChildNodeView):
 
     @check_precondition
     def properties(self, gid, sid, did, scid, pid):
+        """
+
+        :param gid:
+        :param sid:
+        :param did:
+        :param scid:
+        :param pid:
+        :return:
+        """
+        status, res = self._fetch_properties(scid, pid)
+        if not status:
+            return res
+
+        return ajax_response(
+            response=res,
+            status=200
+        )
+
+    def _fetch_properties(self, scid, pid):
+        """
+        This function is used to fetch the properties of specified object.
+
+        :param scid:
+        :param pid:
+        :return:
+        """
         sql = render_template(
             "/".join([self.template_path, 'properties.sql']),
             scid=scid,
@@ -311,16 +342,13 @@ class FtsParserView(PGChildNodeView):
         status, res = self.conn.execute_dict(sql)
 
         if not status:
-            return internal_server_error(errormsg=res)
+            return False, internal_server_error(errormsg=res)
 
         if len(res['rows']) == 0:
-            return gone(
+            return False, gone(
                 _("Could not find the FTS Parser node in the database node."))
 
-        return ajax_response(
-            response=res['rows'][0],
-            status=200
-        )
+        return True, res['rows'][0]
 
     @check_precondition
     def create(self, gid, sid, did, scid):
@@ -862,5 +890,30 @@ class FtsParserView(PGChildNodeView):
             status=200
         )
 
+    @check_precondition
+    def fetch_objects_to_compare(self, sid, did, scid):
+        """
+        This function will fetch the list of all the fts parsers for
+        specified schema id.
+
+        :param sid: Server Id
+        :param did: Database Id
+        :param scid: Schema Id
+        :return:
+        """
+        res = dict()
+        SQL = render_template("/".join([self.template_path,
+                                        'nodes.sql']), scid=scid)
+        status, rset = self.conn.execute_2darray(SQL)
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        for row in rset['rows']:
+            status, data = self._fetch_properties(scid, row['oid'])
+            if status:
+                res[row['name']] = data
+
+        return res
+
 
 FtsParserView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/__init__.py
index 8e952d912..6b7627db0 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/__init__.py
@@ -24,6 +24,8 @@ from pgadmin.utils import IS_PY2
 from pgadmin.utils.ajax import make_json_response, internal_server_error, \
     make_response as ajax_response, gone
 from pgadmin.utils.driver import get_driver
+from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
+from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
 
 # If we are in Python3
 if not IS_PY2:
@@ -90,7 +92,7 @@ class FtsTemplateModule(SchemaChildModule):
 blueprint = FtsTemplateModule(__name__)
 
 
-class FtsTemplateView(PGChildNodeView):
+class FtsTemplateView(PGChildNodeView, SchemaDiffObjectCompare):
     """
     class FtsTemplateView(PGChildNodeView)
 
@@ -154,6 +156,9 @@ class FtsTemplateView(PGChildNodeView):
       - This function get the dependencies and return ajax response for the
       FTS Template node.
 
+    * compare(**kwargs):
+      - This function will compare the fts template nodes from two
+        different schemas.
     """
 
     node_type = blueprint.node_type
@@ -184,7 +189,7 @@ class FtsTemplateView(PGChildNodeView):
         'dependency': [{'get': 'dependencies'}],
         'dependent': [{'get': 'dependents'}],
         'get_lexize': [{'get': 'get_lexize'}, {'get': 'get_lexize'}],
-        'get_init': [{'get': 'get_init'}, {'get': 'get_init'}],
+        'get_init': [{'get': 'get_init'}, {'get': 'get_init'}]
     })
 
     def _init_(self, **kwargs):
@@ -281,25 +286,47 @@ class FtsTemplateView(PGChildNodeView):
 
     @check_precondition
     def properties(self, gid, sid, did, scid, tid):
+        """
+
+        :param gid:
+        :param sid:
+        :param did:
+        :param scid:
+        :param tid:
+        :return:
+        """
+        status, res = self._fetch_properties(scid, tid)
+        if not status:
+            return res
+
+        return ajax_response(
+            response=res,
+            status=200
+        )
+
+    def _fetch_properties(self, scid, tid):
+        """
+        This function is used to fetch the properties of specified object.
+
+        :param scid:
+        :param pid:
+        :return:
+        """
         sql = render_template(
             "/".join([self.template_path, 'properties.sql']),
             scid=scid,
             tid=tid
         )
         status, res = self.conn.execute_dict(sql)
-
         if not status:
-            return internal_server_error(errormsg=res)
+            return False, internal_server_error(errormsg=res)
 
         if len(res['rows']) == 0:
-            return gone(
+            return False, gone(
                 gettext("Could not find the requested FTS template.")
             )
 
-        return ajax_response(
-            response=res['rows'][0],
-            status=200
-        )
+        return True, res['rows'][0]
 
     @check_precondition
     def create(self, gid, sid, did, scid):
@@ -734,5 +761,30 @@ class FtsTemplateView(PGChildNodeView):
             status=200
         )
 
+    @check_precondition
+    def fetch_objects_to_compare(self, sid, did, scid):
+        """
+        This function will fetch the list of all the fts templates for
+        specified schema id.
+
+        :param sid: Server Id
+        :param did: Database Id
+        :param scid: Schema Id
+        :return:
+        """
+        res = dict()
+        SQL = render_template("/".join([self.template_path,
+                                        'nodes.sql']), scid=scid)
+        status, rset = self.conn.execute_2darray(SQL)
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        for row in rset['rows']:
+            status, data = self._fetch_properties(scid, row['oid'])
+            if status:
+                res[row['name']] = data
+
+        return res
+
 
 FtsTemplateView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py
index a66e2215d..ef2dda4f1 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py
@@ -21,7 +21,7 @@ from flask import render_template, make_response, request, jsonify, \
     current_app
 from flask_babelex import gettext
 from pgadmin.browser.server_groups.servers.databases.schemas.utils import \
-    SchemaChildModule, DataTypeReader
+    SchemaChildModule, DataTypeReader, get_schema
 from pgadmin.browser.server_groups.servers.databases.utils import \
     parse_sec_labels_from_db, parse_variables_from_db
 from pgadmin.browser.server_groups.servers.utils import parse_priv_from_db, \
@@ -30,8 +30,10 @@ from pgadmin.browser.utils import PGChildNodeView
 from pgadmin.utils.ajax import make_json_response, internal_server_error, \
     make_response as ajax_response, gone
 from pgadmin.utils.driver import get_driver
-
 from config import PG_DEFAULT_DRIVER
+from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
+from pgadmin.tools.schema_diff.model import SchemaDiffModel
+from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
 
 
 class FunctionModule(SchemaChildModule):
@@ -115,7 +117,7 @@ class FunctionModule(SchemaChildModule):
 blueprint = FunctionModule(__name__)
 
 
-class FunctionView(PGChildNodeView, DataTypeReader):
+class FunctionView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
     """
     class FunctionView(PGChildNodeView)
 
@@ -177,6 +179,10 @@ class FunctionView(PGChildNodeView, DataTypeReader):
 
     * exec_sql(gid, sid, did, scid, fnid):
       - Returns sql for Script
+
+    * compare(**kwargs):
+      - This function will compare the function nodes from two
+        different schemas.
     """
 
     node_type = blueprint.node_type
@@ -213,6 +219,9 @@ class FunctionView(PGChildNodeView, DataTypeReader):
                                   {'get': 'get_support_functions'}]
     })
 
+    keys_to_ignore = ['oid', 'proowner', 'typnsp', 'xmin', 'prokind',
+                      'proisagg', 'pronamespace', 'proargdefaults']
+
     @property
     def required_args(self):
         """
@@ -789,7 +798,7 @@ class FunctionView(PGChildNodeView, DataTypeReader):
         )
 
     @check_precondition
-    def delete(self, gid, sid, did, scid, fnid=None):
+    def delete(self, gid, sid, did, scid, fnid=None, only_sql=False):
         """
         Drop the Function.
 
@@ -840,6 +849,8 @@ class FunctionView(PGChildNodeView, DataTypeReader):
                                       func_args=res['rows'][0]['func_args'],
                                       nspname=res['rows'][0]['nspname'],
                                       cascade=cascade)
+                if only_sql:
+                    return SQL
                 status, res = self.conn.execute_scalar(SQL)
                 if not status:
                     return internal_server_error(errormsg=res)
@@ -914,7 +925,8 @@ class FunctionView(PGChildNodeView, DataTypeReader):
             )
 
     @check_precondition
-    def sql(self, gid, sid, did, scid, fnid=None):
+    def sql(self, gid, sid, did, scid, fnid=None, diff_schema=None,
+            json_resp=True):
         """
         Returns the SQL for the Function object.
 
@@ -988,6 +1000,8 @@ class FunctionView(PGChildNodeView, DataTypeReader):
             if not status:
                 return internal_server_error(errormsg=res)
 
+            if diff_schema:
+                res['rows'][0]['nspname'] = diff_schema
             name_with_default_args = self.qtIdent(
                 self.conn,
                 res['rows'][0]['nspname'],
@@ -1039,6 +1053,10 @@ class FunctionView(PGChildNodeView, DataTypeReader):
             if not status:
                 return internal_server_error(errormsg=res)
 
+            if diff_schema:
+                res['rows'][0]['nspname'] = diff_schema
+                resp_data['pronamespace'] = diff_schema
+
             name_with_default_args = self.qtIdent(
                 self.conn,
                 res['rows'][0]['nspname'],
@@ -1070,6 +1088,9 @@ class FunctionView(PGChildNodeView, DataTypeReader):
                resp_data['proname']),
            resp_data['proargtypenames'].lstrip('(').rstrip(')'))
 
+        if not json_resp:
+            return re.sub('\n{2,}', '\n\n', func_def)
+
         SQL = sql_header + func_def
         SQL = re.sub('\n{2,}', '\n\n', SQL)
 
@@ -1596,7 +1617,66 @@ class FunctionView(PGChildNodeView, DataTypeReader):
             status=200
         )
 
+    def get_sql_from_diff(self, gid, sid, did, scid, oid, data=None,
+                          diff_schema=None, drop_sql=False):
+        sql = ''
+        if data:
+            if diff_schema:
+                data['schema'] = diff_schema
+            status, sql = self._get_sql(gid, sid, did, scid, data, oid)
+        else:
+            if drop_sql:
+                sql = self.delete(gid=gid, sid=sid, did=did,
+                                  scid=scid, fnid=oid, only_sql=True)
+            elif diff_schema:
+                sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, fnid=oid,
+                               diff_schema=diff_schema, json_resp=False)
+            else:
+                sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, fnid=oid,
+                               json_resp=False)
+        return sql
+
+    @check_precondition
+    def fetch_objects_to_compare(self, sid, did, scid, oid=None):
+        """
+        This function will fetch the list of all the functions for
+        specified schema id.
+
+        :param sid: Server Id
+        :param did: Database Id
+        :param scid: Schema Id
+        :return:
+        """
+        res = dict()
+        server_type = self.manager.server_type
+        server_version = self.manager.sversion
+
+        if server_type == 'pg' and self.blueprint.min_ver is not None and \
+                server_version < self.blueprint.min_ver:
+            return res
+        if server_type == 'ppas' and self.blueprint.min_ppasver is not None \
+                and server_version < self.blueprint.min_ppasver:
+            return res
+
+        if not oid:
+            SQL = render_template("/".join([self.sql_template_path,
+                                            'node.sql']), scid=scid)
+            status, rset = self.conn.execute_2darray(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            for row in rset['rows']:
+                data = self._fetch_properties(0, sid, did, scid, row['oid'])
+                if isinstance(data, dict):
+                    res[row['name']] = data
+        else:
+            data = self._fetch_properties(0, sid, did, scid, oid)
+            res = data
+
+        return res
+
 
+SchemaDiffRegistry('function', FunctionView)
 FunctionView.register_node_view(blueprint)
 
 
@@ -1697,6 +1777,7 @@ class ProcedureView(FunctionView):
                 'prosrc']
 
 
+SchemaDiffRegistry('procedure', ProcedureView)
 ProcedureView.register_node_view(procedure_blueprint)
 
 
@@ -1795,4 +1876,5 @@ class TriggerFunctionView(FunctionView):
                 'prosrc']
 
 
+SchemaDiffRegistry('trigger_function', TriggerFunctionView)
 TriggerFunctionView.register_node_view(trigger_function_blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/packages/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/packages/__init__.py
index 70f99e91e..4c0a5a382 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/packages/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/packages/__init__.py
@@ -27,6 +27,8 @@ from pgadmin.utils.ajax import make_json_response, \
     make_response as ajax_response, internal_server_error, \
     precondition_required, gone
 from pgadmin.utils.driver import get_driver
+from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
+from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
 
 # If we are in Python3
 if not IS_PY2:
@@ -83,7 +85,7 @@ class PackageModule(SchemaChildModule):
 blueprint = PackageModule(__name__)
 
 
-class PackageView(PGChildNodeView):
+class PackageView(PGChildNodeView, SchemaDiffObjectCompare):
     node_type = blueprint.node_type
 
     parent_ids = [
@@ -111,6 +113,8 @@ class PackageView(PGChildNodeView):
         'dependent': [{'get': 'dependents'}]
     })
 
+    keys_to_ignore = ['oid', 'schema', 'xmin']
+
     def check_precondition(action=None):
         """
         This function will behave as a decorator which will checks
@@ -297,16 +301,32 @@ class PackageView(PGChildNodeView):
 
         Returns:
 
+        """
+        status, res = self._fetch_properties(scid, pkgid)
+        if not status:
+            return res
+
+        return ajax_response(
+            response=res,
+            status=200
+        )
+
+    def _fetch_properties(self, scid, pkgid):
+        """
+        This function is used to fetch the properties of specified object.
+        :param scid:
+        :param pkgid:
+        :return:
         """
         SQL = render_template("/".join([self.template_path, 'properties.sql']),
                               scid=scid, pkgid=pkgid)
         status, res = self.conn.execute_dict(SQL)
 
         if not status:
-            return internal_server_error(errormsg=res)
+            return False, internal_server_error(errormsg=res)
 
         if len(res['rows']) == 0:
-            return gone(
+            return False, gone(
                 errormsg=_("Could not find the package in the database.")
             )
 
@@ -321,16 +341,13 @@ class PackageView(PGChildNodeView):
         status, rset1 = self.conn.execute_dict(SQL)
 
         if not status:
-            return internal_server_error(errormsg=rset1)
+            return False, internal_server_error(errormsg=rset1)
 
         for row in rset1['rows']:
             priv = parse_priv_from_db(row)
             res['rows'][0].setdefault(row['deftype'], []).append(priv)
 
-        return ajax_response(
-            response=res['rows'][0],
-            status=200
-        )
+        return True, res['rows'][0]
 
     @check_precondition(action="create")
     def create(self, gid, sid, did, scid):
@@ -396,7 +413,7 @@ class PackageView(PGChildNodeView):
         )
 
     @check_precondition(action='delete')
-    def delete(self, gid, sid, did, scid, pkgid=None):
+    def delete(self, gid, sid, did, scid, pkgid=None, only_sql=False):
         """
         This function will drop the object
 
@@ -453,6 +470,9 @@ class PackageView(PGChildNodeView):
                                       data=res['rows'][0],
                                       cascade=cascade)
 
+                if only_sql:
+                    return SQL
+
                 status, res = self.conn.execute_scalar(SQL)
                 if not status:
                     return internal_server_error(errormsg=res)
@@ -552,7 +572,8 @@ class PackageView(PGChildNodeView):
             status=200
         )
 
-    def getSQL(self, gid, sid, did, data, scid, pkgid=None, sqltab=False):
+    def getSQL(self, gid, sid, did, data, scid, pkgid=None, sqltab=False,
+               diff_schema=None):
         """
         This function will generate sql from model data.
 
@@ -621,6 +642,9 @@ class PackageView(PGChildNodeView):
                 if arg not in data:
                     data[arg] = old_data[arg]
 
+            if diff_schema:
+                data['schema'] = diff_schema
+
             SQL = render_template("/".join([self.template_path, 'update.sql']),
                                   data=data, o_data=old_data, conn=self.conn)
             return SQL, data['name'] if 'name' in data else old_data['name']
@@ -635,7 +659,8 @@ class PackageView(PGChildNodeView):
             return SQL, data['name']
 
     @check_precondition(action="sql")
-    def sql(self, gid, sid, did, scid, pkgid):
+    def sql(self, gid, sid, did, scid, pkgid, diff_schema=None,
+            json_resp=True):
         """
         This function will generate sql for sql panel
 
@@ -645,6 +670,8 @@ class PackageView(PGChildNodeView):
             did: Database ID
             scid: Schema ID
             pkgid: Package ID
+            diff_schema:  Schema diff target schema name
+            json_resp: json response or plain text response
         """
         try:
             SQL = render_template(
@@ -676,13 +703,18 @@ class PackageView(PGChildNodeView):
                 res['rows'][0].setdefault(row['deftype'], []).append(priv)
 
             result = res['rows'][0]
-            sql, name = self.getSQL(gid, sid, did, result, scid, pkgid, True)
+            sql, name = self.getSQL(gid, sid, did, result, scid, pkgid, True,
+                                    diff_schema)
             # Most probably this is due to error
             if not isinstance(sql, (str, unicode)):
                 return sql
 
             sql = sql.strip('\n').strip(' ')
 
+            # Return sql for schema diff
+            if not json_resp:
+                return sql
+
             sql_header = u"-- Package: {}\n\n-- ".format(
                 self.qtIdent(self.conn, self.schema, result['name'])
             )
@@ -756,5 +788,54 @@ class PackageView(PGChildNodeView):
 
         return sql[start:end].strip("\n")
 
+    @check_precondition(action="fetch_objects_to_compare")
+    def fetch_objects_to_compare(self, sid, did, scid):
+        """
+        This function will fetch the list of all the packages for
+        specified schema id.
+
+        :param sid: Server Id
+        :param did: Database Id
+        :param scid: Schema Id
+        :return:
+        """
+        res = dict()
+        if self.manager.server_type != 'ppas':
+            return res
+
+        SQL = render_template("/".join([self.template_path,
+                                        'nodes.sql']), scid=scid)
+        status, rset = self.conn.execute_2darray(SQL)
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        for row in rset['rows']:
+            status, data = self._fetch_properties(scid, row['oid'])
+            if status:
+                res[row['name']] = data
+
+        return res
+
+    def get_sql_from_diff(self, gid, sid, did, scid, oid, data=None,
+                          diff_schema=None, drop_sql=False):
+        sql = ''
+        if data:
+            if diff_schema:
+                data['schema'] = diff_schema
+            status, sql = self.getSQL(gid, sid, did, data, scid, oid)
+        else:
+            if drop_sql:
+                sql = self.delete(gid=gid, sid=sid, did=did,
+                                  scid=scid, pkgid=oid, only_sql=True)
+
+            elif diff_schema:
+                sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, pkgid=oid,
+                               diff_schema=diff_schema, json_resp=False)
+            else:
+                sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, pkgid=oid,
+                               json_resp=False)
+        return sql
+
 
+SchemaDiffRegistry('package', PackageView)
 PackageView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/packages/edbfuncs/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/packages/edbfuncs/__init__.py
index 4809be85b..f97994468 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/packages/edbfuncs/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/packages/edbfuncs/__init__.py
@@ -161,6 +161,8 @@ class EdbFuncView(PGChildNodeView, DataTypeReader):
     * dependencies(gid, sid, did, scid, pkgid, edbfnid):
       - Returns the dependencies for the Functions object.
 
+    * compare(**kwargs):
+      - This function will compare the nodes from two different schemas.
     """
 
     node_type = blueprint.node_type
@@ -184,7 +186,8 @@ class EdbFuncView(PGChildNodeView, DataTypeReader):
         'nodes': [{'get': 'nodes'}, {'get': 'nodes'}],
         'sql': [{'get': 'sql'}],
         'dependency': [{'get': 'dependencies'}],
-        'dependent': [{'get': 'dependents'}]
+        'dependent': [{'get': 'dependents'}],
+        'compare': [{'get': 'compare'}, {'get': 'compare'}]
     })
 
     def check_precondition(f):
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/packages/edbvars/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/packages/edbvars/__init__.py
index ddce19a65..e82660dde 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/packages/edbvars/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/packages/edbvars/__init__.py
@@ -137,6 +137,8 @@ class EdbVarView(PGChildNodeView, DataTypeReader):
     * sql(gid, sid, did, scid, pkgid, varid):
       - Returns the SQL for the Functions object.
 
+    * compare(**kwargs):
+      - This function will compare the nodes from two different schemas.
     """
 
     node_type = blueprint.node_type
@@ -158,7 +160,8 @@ class EdbVarView(PGChildNodeView, DataTypeReader):
             {'get': 'list'}
         ],
         'nodes': [{'get': 'nodes'}, {'get': 'nodes'}],
-        'sql': [{'get': 'sql'}]
+        'sql': [{'get': 'sql'}],
+        'compare': [{'get': 'compare'}, {'get': 'compare'}]
     })
 
     def check_precondition(f):
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/sequences/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/sequences/__init__.py
index eff3d9e85..3dbe7422e 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/sequences/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/sequences/__init__.py
@@ -24,6 +24,9 @@ from pgadmin.utils.ajax import make_json_response, internal_server_error, \
 from pgadmin.utils.driver import get_driver
 from config import PG_DEFAULT_DRIVER
 from pgadmin.utils import IS_PY2
+from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
+from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
+
 # If we are in Python3
 if not IS_PY2:
     unicode = str
@@ -88,7 +91,7 @@ class SequenceModule(SchemaChildModule):
 blueprint = SequenceModule(__name__)
 
 
-class SequenceView(PGChildNodeView):
+class SequenceView(PGChildNodeView, SchemaDiffObjectCompare):
     node_type = blueprint.node_type
 
     parent_ids = [
@@ -273,6 +276,23 @@ class SequenceView(PGChildNodeView):
         Returns:
 
         """
+        status, res = self._fetch_properties(scid, seid)
+        if not status:
+            return res
+
+        return ajax_response(
+            response=res,
+            status=200
+        )
+
+    def _fetch_properties(self, scid, seid):
+        """
+        This function is used to fetch the properties of the specified object.
+        :param scid:
+        :param seid:
+        :return:
+        """
+
         SQL = render_template(
             "/".join([self.template_path, 'properties.sql']),
             scid=scid, seid=seid
@@ -280,10 +300,11 @@ class SequenceView(PGChildNodeView):
         status, res = self.conn.execute_dict(SQL)
 
         if not status:
-            return internal_server_error(errormsg=res)
+            return False, internal_server_error(errormsg=res)
 
         if len(res['rows']) == 0:
-            return gone(_("Could not find the sequence in the database."))
+            return False, gone(
+                _("Could not find the sequence in the database."))
 
         for row in res['rows']:
             SQL = render_template(
@@ -292,7 +313,7 @@ class SequenceView(PGChildNodeView):
             )
             status, rset1 = self.conn.execute_dict(SQL)
             if not status:
-                return internal_server_error(errormsg=rset1)
+                return False, internal_server_error(errormsg=rset1)
 
             row['current_value'] = rset1['rows'][0]['last_value']
             row['minimum'] = rset1['rows'][0]['min_value']
@@ -319,7 +340,7 @@ class SequenceView(PGChildNodeView):
         )
         status, dataclres = self.conn.execute_dict(SQL)
         if not status:
-            return internal_server_error(errormsg=res)
+            return False, internal_server_error(errormsg=res)
 
         for row in dataclres['rows']:
             priv = parse_priv_from_db(row)
@@ -328,10 +349,7 @@ class SequenceView(PGChildNodeView):
             else:
                 res['rows'][0][row['deftype']] = [priv]
 
-        return ajax_response(
-            response=res['rows'][0],
-            status=200
-        )
+        return True, res['rows'][0]
 
     @check_precondition(action="create")
     def create(self, gid, sid, did, scid):
@@ -869,5 +887,30 @@ class SequenceView(PGChildNodeView):
             status=200
         )
 
+    @check_precondition(action="fetch_objects_to_compare")
+    def fetch_objects_to_compare(self, sid, did, scid):
+        """
+        This function will fetch the list of all the sequences for
+        specified schema id.
+
+        :param sid: Server Id
+        :param did: Database Id
+        :param scid: Schema Id
+        :return:
+        """
+        res = dict()
+        SQL = render_template("/".join([self.template_path,
+                                        'nodes.sql']), scid=scid)
+        status, rset = self.conn.execute_2darray(SQL)
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        for row in rset['rows']:
+            status, data = self._fetch_properties(scid, row['oid'])
+            if status:
+                res[row['name']] = data
+
+        return res
+
 
 SequenceView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/synonyms/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/synonyms/__init__.py
index 7f3c680d7..145ccf69b 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/synonyms/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/synonyms/__init__.py
@@ -24,6 +24,8 @@ from pgadmin.utils.ajax import precondition_required
 from pgadmin.utils.driver import get_driver
 from config import PG_DEFAULT_DRIVER
 from pgadmin.utils import IS_PY2
+from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
+from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
 
 # If we are in Python3
 if not IS_PY2:
@@ -91,7 +93,7 @@ class SynonymModule(SchemaChildModule):
 blueprint = SynonymModule(__name__)
 
 
-class SynonymView(PGChildNodeView):
+class SynonymView(PGChildNodeView, SchemaDiffObjectCompare):
     """
     This class is responsible for generating routes for Synonym node
 
@@ -143,6 +145,10 @@ class SynonymView(PGChildNodeView):
     * dependent(gid, sid, did, scid):
       - This function will generate dependent list to show it in dependent
         pane for the selected Synonym node.
+
+    * compare(**kwargs):
+      - This function will compare the synonyms nodes from two
+        different schemas.
     """
 
     node_type = blueprint.node_type
@@ -385,26 +391,36 @@ class SynonymView(PGChildNodeView):
         Returns:
             JSON of selected synonym node
         """
+        status, res = self._fetch_properties(scid, syid)
+        if not status:
+            return res
 
+        return ajax_response(
+            response=res,
+            status=200
+        )
+
+    def _fetch_properties(self, scid, syid):
+        """
+        This function is used to fetch the properties of the specified object
+        :param scid:
+        :param syid:
+        :return:
+        """
         try:
             SQL = render_template("/".join([self.template_path,
                                             'properties.sql']),
                                   scid=scid, syid=syid)
             status, res = self.conn.execute_dict(SQL)
-
             if not status:
-                return internal_server_error(errormsg=res)
+                return False, internal_server_error(errormsg=res)
 
-            if len(res['rows']) > 0:
-                return ajax_response(
-                    response=res['rows'][0],
-                    status=200
-                )
-            else:
-                return gone(
+            if len(res['rows']) == 0:
+                return False, gone(
                     gettext('The specified synonym could not be found.')
                 )
 
+            return True, res['rows'][0]
         except Exception as e:
             return internal_server_error(errormsg=str(e))
 
@@ -707,5 +723,33 @@ class SynonymView(PGChildNodeView):
             status=200
         )
 
+    @check_precondition
+    def fetch_objects_to_compare(self, sid, did, scid):
+        """
+        This function will fetch the list of all the synonyms for
+        specified schema id.
+
+        :param sid: Server Id
+        :param did: Database Id
+        :param scid: Schema Id
+        :return:
+        """
+        res = dict()
+        if self.manager.server_type != 'ppas':
+            return res
+
+        SQL = render_template("/".join([self.template_path,
+                                        'properties.sql']), scid=scid)
+        status, rset = self.conn.execute_2darray(SQL)
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        for row in rset['rows']:
+            status, data = self._fetch_properties(scid, row['name'])
+            if status:
+                res[row['name']] = data
+
+        return res
+
 
 SynonymView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/__init__.py
index 3fef6e025..14e13ed2d 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/__init__.py
@@ -11,9 +11,11 @@
 
 import simplejson as json
 import re
+import copy
+import random
 
 import pgadmin.browser.server_groups.servers.databases as database
-from flask import render_template, request, jsonify, url_for
+from flask import render_template, request, jsonify, url_for, current_app
 from flask_babelex import gettext
 from pgadmin.browser.server_groups.servers.databases.schemas.utils \
     import SchemaChildModule, DataTypeReader, VacuumSettings
@@ -22,8 +24,15 @@ from pgadmin.utils.ajax import make_json_response, internal_server_error, \
     make_response as ajax_response, gone
 from .utils import BaseTableView
 from pgadmin.utils.preferences import Preferences
+from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
+from pgadmin.tools.schema_diff.directory_compare import compare_dictionaries,\
+    directory_diff
+from pgadmin.tools.schema_diff.model import SchemaDiffModel
+from pgadmin.utils.driver import get_driver
+from config import PG_DEFAULT_DRIVER
 from pgadmin.browser.server_groups.servers.databases.schemas.tables.\
     constraints.foreign_key import utils as fkey_utils
+from .schema_diff_utils import SchemaDiffTableCompare
 from pgadmin.browser.server_groups.servers.databases.schemas.tables.\
     columns import utils as column_utils
 from pgadmin.browser.server_groups.servers.databases.schemas.tables.\
@@ -132,7 +141,8 @@ class TableModule(SchemaChildModule):
 blueprint = TableModule(__name__)
 
 
-class TableView(BaseTableView, DataTypeReader, VacuumSettings):
+class TableView(BaseTableView, DataTypeReader, VacuumSettings,
+                SchemaDiffTableCompare):
     """
     This class is responsible for generating routes for Table node
 
@@ -229,6 +239,10 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings):
 
     * delete_sql(gid, sid, did, scid, foid):
       - Returns sql for Script
+
+    * compare(**kwargs):
+      - This function will compare the table nodes from two
+        different schemas.
 """
 
     node_type = blueprint.node_type
@@ -277,7 +291,8 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings):
         'insert_sql': [{'get': 'insert_sql'}],
         'update_sql': [{'get': 'update_sql'}],
         'delete_sql': [{'get': 'delete_sql'}],
-        'count_rows': [{'get': 'count_rows'}]
+        'count_rows': [{'get': 'count_rows'}],
+        'compare': [{'get': 'compare'}, {'get': 'compare'}]
     })
 
     @BaseTableView.check_precondition
@@ -464,9 +479,9 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings):
           - setting
         values
         """
-        res = self.get_vacuum_table_settings(self.conn)
+        res = self.get_vacuum_table_settings(self.conn, sid)
         return ajax_response(
-            response=res['rows'],
+            response=res,
             status=200
         )
 
@@ -480,9 +495,9 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings):
           - setting
         values
         """
-        res = self.get_vacuum_toast_settings(self.conn)
+        res = self.get_vacuum_toast_settings(self.conn, sid)
         return ajax_response(
-            response=res['rows'],
+            response=res,
             status=200
         )
 
@@ -582,7 +597,22 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings):
         Returns:
             JSON of selected table node
         """
+        status, res = self._fetch_properties(did, scid, tid)
+        if not status:
+            return res
 
+        return super(TableView, self).properties(
+            gid, sid, did, scid, tid, res
+        )
+
+    def _fetch_properties(self, did, scid, tid):
+        """
+        This function is used to fetch the properties of the specified object
+        :param did:
+        :param scid:
+        :param tid:
+        :return:
+        """
         SQL = render_template(
             "/".join([self.table_template_path, 'properties.sql']),
             did=did, scid=scid, tid=tid,
@@ -590,10 +620,11 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings):
         )
         status, res = self.conn.execute_dict(SQL)
         if not status:
-            return internal_server_error(errormsg=res)
+            return False, internal_server_error(errormsg=res)
 
         if len(res['rows']) == 0:
-            return gone(gettext("The specified table could not be found."))
+            return False, gone(
+                gettext("The specified table could not be found."))
 
         # We will check the threshold set by user before executing
         # the query because that can cause performance issues
@@ -620,7 +651,7 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings):
             status, count = self.conn.execute_scalar(SQL)
 
             if not status:
-                return internal_server_error(errormsg=count)
+                return False, internal_server_error(errormsg=count)
 
             res['rows'][0]['rows_cnt'] = count
 
@@ -628,9 +659,7 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings):
         elif not estimated_row_count:
             res['rows'][0]['rows_cnt'] = estimated_row_count
 
-        return super(TableView, self).properties(
-            gid, sid, did, scid, tid, res
-        )
+        return True, res
 
     @BaseTableView.check_precondition
     def types(self, gid, sid, did, scid, tid=None, clid=None):
@@ -1168,6 +1197,72 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings):
         """
         return BaseTableView.reset_statistics(self, scid, tid)
 
+    @BaseTableView.check_precondition
+    def get_sql_from_table_diff(self, **kwargs):
+        """
+        This function will create sql on the basis the difference of 2 tables
+        """
+        data = dict()
+        res = None
+        sid = kwargs['sid']
+        did = kwargs['did']
+        scid = kwargs['scid']
+        tid = kwargs['tid']
+        diff_data = kwargs['diff_data'] if 'diff_data' in kwargs else None
+        json_resp = kwargs['json_resp'] if 'json_resp' in kwargs else True
+        diff_schema = kwargs['diff_schema'] if 'diff_schema' in kwargs else\
+            None
+        schema_diff_table = kwargs['schema_diff_table'] if\
+            'schema_diff_table' in kwargs else None
+
+        if diff_data:
+            return self._fetch_sql(did, scid, tid, diff_data, json_resp)
+        else:
+            main_sql = []
+
+            SQL = render_template(
+                "/".join([self.table_template_path, 'properties.sql']),
+                did=did, scid=scid, tid=tid,
+                datlastsysoid=self.datlastsysoid
+            )
+            status, res = self.conn.execute_dict(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            if len(res['rows']) == 0:
+                return gone(gettext("The specified table could not be found."
+                                    ))
+
+            if status:
+                data = res['rows'][0]
+                # data = super(TableView, self).properties(
+                #     0, sid, did, scid, tid, res, False
+                # )
+
+            if diff_schema:
+                data['schema'] = diff_schema
+
+            if schema_diff_table:
+                data['orig_name'] = data['name']
+                data['name'] = 'schema_diff_temp_{0}'.format(
+                    random.randint(1, 9999999))
+
+                sql, partition_sql = BaseTableView.get_reverse_engineered_sql(
+                    self, did, scid, tid, main_sql, data, json_resp,
+                    diff_partition_sql=True)
+            else:
+                sql, partition_sql = BaseTableView.get_reverse_engineered_sql(
+                    self, did, scid, tid, main_sql, data, json_resp)
+
+            if schema_diff_table:
+                # If partition tables have different partitions
+                sql += render_template(
+                    "/".join([self.table_template_path, 'schema_diff.sql']),
+                    conn=self.conn, data=data, partition_sql=partition_sql
+                )
+
+            return sql
+
     @BaseTableView.check_precondition
     def msql(self, gid, sid, did, scid, tid=None):
         """
@@ -1181,7 +1276,7 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings):
            tid: Table ID
         """
         data = dict()
-        res = None
+        SQL = ''
         for k, v in request.args.items():
             try:
                 # comments should be taken as is because if user enters a
@@ -1193,6 +1288,11 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings):
             except (ValueError, TypeError, KeyError):
                 data[k] = v
 
+        return self._fetch_sql(did, scid, tid, data)
+
+    def _fetch_sql(self, did, scid, tid, data, json_resp=True):
+        res = None
+
         if tid is not None:
             SQL = render_template(
                 "/".join([self.table_template_path, 'properties.sql']),
@@ -1201,13 +1301,18 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings):
             )
             status, res = self.conn.execute_dict(SQL)
             if not status:
-                return internal_server_error(errormsg=res)
+                return internal_server_error(errormsg=SQL)
 
         SQL, name = self.get_sql(did, scid, tid, data, res)
         SQL = re.sub('\n{2,}', '\n\n', SQL)
         SQL = SQL.strip('\n')
+
+        if not json_resp:
+            return SQL
+
         if SQL == '':
             SQL = "--modified SQL"
+
         return make_json_response(
             data=SQL,
             status=200
@@ -1419,7 +1524,7 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings):
         return ajax_response(response=sql)
 
     @BaseTableView.check_precondition
-    def delete_sql(self, gid, sid, did, scid, tid):
+    def delete_sql(self, gid, sid, did, scid, tid, json_resp=True):
         """
         DELETE script sql for the object
 
@@ -1448,6 +1553,9 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings):
             self.qtIdent(self.conn, data['schema'], data['name'])
         )
 
+        if not json_resp:
+            return sql
+
         return ajax_response(response=sql)
 
     @BaseTableView.check_precondition
@@ -1502,5 +1610,60 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings):
             data={'total_rows': count}
         )
 
+    def get_delete_sql(self, res):
+        self.cmd = 'delete'
+        sql = super(TableView, self).get_delete_sql(res)
+        self.cmd = None
+        return sql
+
+    @BaseTableView.check_precondition
+    def fetch_tables(self, sid, did, scid, tid=None, keys_to_remove=None):
+        """
+        This function will fetch the list of all the tables
+        and will be used by schema diff.
+
+        :param sid: Server Id
+        :param did: Database Id
+        :param scid: Schema Id
+        :param tid: Table Id
+        :param keys_to_remove: Table columns to be removed from the dataset
+        :return: Table dataset
+        """
+        if tid:
+            status, data = self._fetch_properties(did, scid, tid)
+
+            if not status:
+                current_app.logger.error(data)
+                return False
+
+            data = super(TableView, self).properties(
+                0, sid, did, scid, tid, data, False
+            )
+            self.remove_keys_for_comparision(data, keys_to_remove)
+            return data
+
+        else:
+            res = dict()
+            SQL = render_template("/".join([self.table_template_path,
+                                            'nodes.sql']), scid=scid)
+            status, tables = self.conn.execute_2darray(SQL)
+            if not status:
+                current_app.logger.error(tables)
+                return False
+
+            for row in tables['rows']:
+                status, data = self._fetch_properties(did, scid, row['oid'])
+
+                if status:
+                    data = super(TableView, self).properties(
+                        0, sid, did, scid, row['oid'], data, False
+                    )
+
+                    self.remove_keys_for_comparision(data, keys_to_remove)
+                    res[row['name']] = data
+
+            return res
+
 
+SchemaDiffRegistry('table', TableView)
 TableView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/columns/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/columns/__init__.py
index c0c40e417..3346af8d8 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/columns/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/columns/__init__.py
@@ -29,6 +29,7 @@ from pgadmin.utils.driver import get_driver
 from config import PG_DEFAULT_DRIVER
 from pgadmin.utils import IS_PY2
 from pgadmin.utils.ajax import ColParamsJSONDecoder
+
 # If we are in Python3
 if not IS_PY2:
     unicode = str
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/compound_triggers/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/compound_triggers/__init__.py
index 6119ff138..83d87bd5a 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/compound_triggers/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/compound_triggers/__init__.py
@@ -26,6 +26,10 @@ from pgadmin.browser.server_groups.servers.databases.schemas.utils \
 from pgadmin.utils.driver import get_driver
 from config import PG_DEFAULT_DRIVER
 from pgadmin.utils import IS_PY2
+from pgadmin.utils.compile_template_name import compile_template_path
+from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
+from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
+
 # If we are in Python3
 if not IS_PY2:
     unicode = str
@@ -155,7 +159,7 @@ class CompoundTriggerModule(CollectionNodeModule):
 blueprint = CompoundTriggerModule(__name__)
 
 
-class CompoundTriggerView(PGChildNodeView):
+class CompoundTriggerView(PGChildNodeView, SchemaDiffObjectCompare):
     """
     This class is responsible for generating routes for Compound Trigger node
 
@@ -245,6 +249,10 @@ class CompoundTriggerView(PGChildNodeView):
         'enable': [{'put': 'enable_disable_trigger'}]
     })
 
+    # Schema Diff: Keys to ignore while comparing
+    keys_to_ignore = ['oid', 'xmin', 'nspname', 'tfunction',
+                      'tgrelid', 'tgfoid']
+
     def check_precondition(f):
         """
         This function will behave as a decorator which will checks
@@ -267,6 +275,12 @@ class CompoundTriggerView(PGChildNodeView):
             ]['datlastsysoid'] if self.manager.db_info is not None and \
                 kwargs['did'] in self.manager.db_info else 0
 
+            self.table_template_path = compile_template_path(
+                'tables/sql',
+                self.manager.server_type,
+                self.manager.version
+            )
+
             # we will set template path for sql scripts
             self.template_path = 'compound_triggers/sql/{0}/#{1}#'.format(
                 self.manager.server_type, self.manager.version)
@@ -417,6 +431,18 @@ class CompoundTriggerView(PGChildNodeView):
             JSON of selected compound trigger node
         """
 
+        data = self._fetch_properties(tid, trid)
+
+        if not status:
+            return data
+
+        return ajax_response(
+            response=data,
+            status=200
+        )
+
+    def _fetch_properties(self, tid, trid):
+
         SQL = render_template("/".join([self.template_path,
                                         'properties.sql']),
                               tid=tid, trid=trid,
@@ -440,10 +466,7 @@ class CompoundTriggerView(PGChildNodeView):
 
         data = trigger_definition(data)
 
-        return ajax_response(
-            response=data,
-            status=200
-        )
+        return True, data
 
     @check_precondition
     def create(self, gid, sid, did, scid, tid):
@@ -519,7 +542,7 @@ class CompoundTriggerView(PGChildNodeView):
             return internal_server_error(errormsg=str(e))
 
     @check_precondition
-    def delete(self, gid, sid, did, scid, tid, trid=None):
+    def delete(self, gid, sid, did, scid, tid, trid=None, only_sql=False):
         """
         This function will updates existing the compound trigger object
 
@@ -579,6 +602,9 @@ class CompoundTriggerView(PGChildNodeView):
                                       conn=self.conn,
                                       cascade=cascade
                                       )
+                if only_sql:
+                    return SQL
+
                 status, res = self.conn.execute_scalar(SQL)
                 if not status:
                     return internal_server_error(errormsg=res)
@@ -846,5 +872,109 @@ class CompoundTriggerView(PGChildNodeView):
             status=200
         )
 
+    @check_precondition
+    def get_sql_from_diff(self, gid, sid, did, scid, tid, oid,
+                          data=None, diff_schema=None, drop_sql=False):
+        if data:
+            sql, name = self.get_sql(scid, tid, oid, data)
+            if not isinstance(sql, (str, unicode)):
+                return sql
+            sql = sql.strip('\n').strip(' ')
+        else:
+            if drop_sql:
+                SQL = self.delete(gid=gid, sid=sid, did=did,
+                                  scid=scid, tid=tid,
+                                  trid=oid, only_sql=True)
+            else:
+                SQL = render_template("/".join([self.template_path,
+                                                'properties.sql']),
+                                      tid=tid, trid=oid,
+                                      datlastsysoid=self.datlastsysoid)
+
+                status, res = self.conn.execute_dict(SQL)
+                if not status:
+                    return internal_server_error(errormsg=res)
+                if len(res['rows']) == 0:
+                    return gone(gettext("""Could not find the compound
+                     trigger in the table."""))
+
+                data = dict(res['rows'][0])
+                # Adding parent into data dict,
+                # will be using it while creating sql
+                data['schema'] = self.schema
+                data['table'] = self.table
+
+                if len(data['tgattr']) >= 1:
+                    columns = ', '.join(data['tgattr'].split(' '))
+                    data['columns'] = self._column_details(tid, columns)
+
+                data = self._trigger_definition(data)
+
+                if diff_schema:
+                    data['schema'] = diff_schema
+
+                SQL, name = self.get_sql(scid, tid, None, data)
+
+                sql_header = u"-- Compound Trigger: {0}\n\n-- ".format(
+                    data['name'])
+
+                sql_header += render_template("/".join([self.template_path,
+                                                        'delete.sql']),
+                                              data=data, conn=self.conn)
+
+                SQL = sql_header + '\n\n' + SQL.strip('\n')
+
+                # If compound trigger is disbaled then add sql
+                # code for the same
+                if not data['is_enable_trigger']:
+                    SQL += '\n\n'
+                    SQL += render_template("/".join([
+                        self.template_path,
+                        'enable_disable_trigger.sql']),
+                        data=data, conn=self.conn)
+
+        return SQL
+
+    @check_precondition
+    def fetch_objects_to_compare(self, sid, did, scid, tid, oid=None,
+                                 ignore_keys=False):
+        """
+        This function will fetch the list of all the triggers for
+        specified schema id.
+
+        :param sid: Server Id
+        :param did: Database Id
+        :param scid: Schema Id
+        :param tid: Table Id
+        :return:
+        """
+        res = dict()
+
+        if oid:
+            status, data = self._fetch_properties(tid, oid)
+            if not status:
+                current_app.logger.error(data)
+                return False
+            res = data
+        else:
+            SQL = render_template("/".join([self.template_path,
+                                            'nodes.sql']), tid=tid)
+            status, triggers = self.conn.execute_2darray(SQL)
+            if not status:
+                current_app.logger.error(triggers)
+                return False
+
+            for row in triggers['rows']:
+                status, data = self._fetch_properties(tid, row['oid'])
+                if status:
+                    if ignore_keys:
+                        for key in self.keys_to_ignore:
+                            if key in data:
+                                del data[key]
+                    res[row['name']] = data
+
+        return res
+
 
+SchemaDiffRegistry('compound_trigger', CompoundTriggerView, 'table')
 CompoundTriggerView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/utils.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/utils.py
index 47baee9b3..04237d645 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/utils.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/utils.py
@@ -152,7 +152,8 @@ def get_index_constraint_sql(conn, did, tid, data, template_path=None):
 
                     modified_sql, name = get_sql(conn, c, did, tid, ctype,
                                                  c['oid'])
-                    sql.append(modified_sql.strip('\n'))
+                    if modified_sql:
+                        sql.append(modified_sql.strip('\n'))
 
             if 'added' in constraint:
                 for c in constraint['added']:
@@ -183,6 +184,7 @@ def get_sql(conn, data, did, tid, ctype, cid=None, template_path=None):
     :return:
     """
     name = data['name'] if 'name' in data else None
+    sql = None
     if cid is not None:
         sql = render_template("/".join([template_path, 'properties.sql']),
                               did=did, tid=tid, cid=cid,
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/__init__.py
index 7f19e953a..6cde60843 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/__init__.py
@@ -13,7 +13,7 @@ import simplejson as json
 from functools import wraps
 
 import pgadmin.browser.server_groups.servers.databases as database
-from flask import render_template, request, jsonify
+from flask import render_template, request, jsonify, current_app
 from flask_babelex import gettext
 from pgadmin.browser.collection import CollectionNodeModule
 from pgadmin.browser.server_groups.servers.databases.schemas.tables.\
@@ -25,8 +25,14 @@ from pgadmin.utils.compile_template_name import compile_template_path
 from pgadmin.utils.driver import get_driver
 from config import PG_DEFAULT_DRIVER
 from pgadmin.utils import IS_PY2
+from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
+from pgadmin.tools.schema_diff.directory_compare import compare_dictionaries,\
+    directory_diff
+from pgadmin.tools.schema_diff.model import SchemaDiffModel
+from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
 from pgadmin.browser.server_groups.servers.databases.schemas. \
     tables.indexes import utils as index_utils
+
 # If we are in Python3
 if not IS_PY2:
     unicode = str
@@ -135,7 +141,7 @@ class IndexesModule(CollectionNodeModule):
 blueprint = IndexesModule(__name__)
 
 
-class IndexesView(PGChildNodeView):
+class IndexesView(PGChildNodeView, SchemaDiffObjectCompare):
     """
     This class is responsible for generating routes for Index node
 
@@ -227,6 +233,11 @@ class IndexesView(PGChildNodeView):
                          {'get': 'get_op_class'}]
     })
 
+    # Schema Diff: Keys to ignore while comparing
+    keys_to_ignore = ['oid', 'relowner', 'schema',
+                      'indrelid', 'nspname'
+                      ]
+
     def check_precondition(f):
         """
         This function will behave as a decorator which will checks
@@ -248,6 +259,12 @@ class IndexesView(PGChildNodeView):
             ]['datlastsysoid'] if self.manager.db_info is not None and \
                 kwargs['did'] in self.manager.db_info else 0
 
+            self.table_template_path = compile_template_path(
+                'tables/sql',
+                self.manager.server_type,
+                self.manager.version
+            )
+
             # we will set template path for sql scripts
             self.template_path = compile_template_path(
                 'indexes/sql/',
@@ -485,19 +502,35 @@ class IndexesView(PGChildNodeView):
         Returns:
             JSON of selected schema node
         """
+        status, data = self._fetch_properties(did, tid, idx)
+        if not status:
+            return data
 
+        return ajax_response(
+            response=data,
+            status=200
+        )
+
+    def _fetch_properties(self, did, tid, idx):
+        """
+        This function is used to fetch the properties of specified object.
+        :param did:
+        :param tid:
+        :param idx:
+        :return:
+        """
         SQL = render_template(
             "/".join([self.template_path, 'properties.sql']),
             did=did, tid=tid, idx=idx, datlastsysoid=self.datlastsysoid
         )
 
         status, res = self.conn.execute_dict(SQL)
-
         if not status:
-            return internal_server_error(errormsg=res)
+            return False, internal_server_error(errormsg=res)
 
         if len(res['rows']) == 0:
-            return gone(gettext("""Could not find the index in the table."""))
+            return False, gone(
+                gettext("""Could not find the index in the table."""))
 
         # Making copy of output for future use
         data = dict(res['rows'][0])
@@ -509,10 +542,7 @@ class IndexesView(PGChildNodeView):
         if self.manager.version >= 110000:
             data = index_utils.get_include_details(self.conn, idx, data)
 
-        return ajax_response(
-            response=data,
-            status=200
-        )
+        return True, data
 
     @check_precondition
     def create(self, gid, sid, did, scid, tid):
@@ -620,7 +650,8 @@ class IndexesView(PGChildNodeView):
             return internal_server_error(errormsg=str(e))
 
     @check_precondition
-    def delete(self, gid, sid, did, scid, tid, idx=None):
+    def delete(self, gid, sid, did, scid, tid, idx=None,
+               only_sql=False):
         """
         This function will updates existing the schema object
 
@@ -676,6 +707,9 @@ class IndexesView(PGChildNodeView):
                     "/".join([self.template_path, 'delete.sql']),
                     data=data, conn=self.conn, cascade=cascade
                 )
+
+                if only_sql:
+                    return SQL
                 status, res = self.conn.execute_scalar(SQL)
                 if not status:
                     return internal_server_error(errormsg=res)
@@ -792,6 +826,32 @@ class IndexesView(PGChildNodeView):
 
         return ajax_response(response=SQL)
 
+    @check_precondition
+    def get_sql_from_index_diff(self, sid, did, scid, tid, idx, data=None,
+                                diff_schema=None, drop_req=False):
+
+        tmp_idx = idx
+        schema = ''
+        if data:
+            schema = self.schema
+        elif diff_schema:
+            schema = diff_schema
+
+        sql = index_utils.get_reverse_engineered_sql(
+            self.conn, schema,
+            self.table, did, tid, idx,
+            self.datlastsysoid,
+            template_path=None, with_header=False)
+
+        drop_sql = ''
+        if drop_req:
+            drop_sql = '\n' + render_template(
+                "/".join([self.template_path, 'delete.sql']),
+                data=data, conn=self.conn
+            )
+
+        return drop_sql + '\n\n' + sql
+
     @check_precondition
     def dependents(self, gid, sid, did, scid, tid, idx):
         """
@@ -914,5 +974,129 @@ class IndexesView(PGChildNodeView):
             status=200
         )
 
+    @check_precondition
+    def fetch_objects_to_compare(self, sid, did, scid, tid, oid=None,
+                                 ignore_keys=False):
+        """
+        This function will fetch the list of all the indexes for
+        specified schema id.
+
+        :param sid: Server Id
+        :param did: Database Id
+        :param scid: Schema Id
+        :return:
+        """
+
+        res = dict()
+
+        if not oid:
+            SQL = render_template("/".join([self.template_path,
+                                            'nodes.sql']), tid=tid)
+            status, indexes = self.conn.execute_2darray(SQL)
+            if not status:
+                current_app.logger.error(indexes)
+                return False
+
+            for row in indexes['rows']:
+                status, data = self._fetch_properties(did, tid,
+                                                      row['oid'])
+                if status:
+                    if ignore_keys:
+                        for key in self.keys_to_ignore:
+                            if key in data:
+                                del data[key]
+                    res[row['name']] = data
+        else:
+            status, data = self._fetch_properties(did, tid,
+                                                  oid)
+            if not status:
+                current_app.logger.error(data)
+                return False
+            res = data
+
+        return res
+
+    def ddl_compare(self, **kwargs):
+        """
+        This function will compare index properties and
+         return the difference of SQL
+        """
+
+        src_sid = kwargs.get('source_sid')
+        src_did = kwargs.get('source_did')
+        src_scid = kwargs.get('source_scid')
+        src_tid = kwargs.get('source_tid')
+        src_oid = kwargs.get('source_oid')
+        tar_sid = kwargs.get('target_sid')
+        tar_did = kwargs.get('target_did')
+        tar_scid = kwargs.get('target_scid')
+        tar_tid = kwargs.get('target_tid')
+        tar_oid = kwargs.get('target_oid')
+        comp_status = kwargs.get('comp_status')
+
+        source = ''
+        target = ''
+        diff = ''
+
+        status, target_schema = self.get_schema(tar_sid,
+                                                tar_did,
+                                                tar_scid
+                                                )
+        if not status:
+            return internal_server_error(errormsg=target_schema)
+
+        if comp_status == SchemaDiffModel.COMPARISON_STATUS['source_only']:
+            diff = self.get_sql_from_index_diff(sid=src_sid,
+                                                did=src_did, scid=src_scid,
+                                                tid=src_tid, idx=src_oid,
+                                                diff_schema=target_schema)
+
+        elif comp_status == SchemaDiffModel.COMPARISON_STATUS['target_only']:
+            diff = self.delete(gid=1, sid=tar_sid, did=tar_did,
+                               scid=tar_scid, tid=tar_tid,
+                               idx=tar_oid, only_sql=True)
+
+        else:
+            source = self.fetch_objects_to_compare(sid=src_sid, did=src_did,
+                                                   scid=src_scid, tid=src_tid,
+                                                   oid=src_oid)
+            target = self.fetch_objects_to_compare(sid=tar_sid, did=tar_did,
+                                                   scid=tar_scid, tid=tar_tid,
+                                                   oid=tar_oid)
+
+            if not (source or target):
+                return None
+
+            diff_dict = directory_diff(
+                source, target, ignore_keys=self.keys_to_ignore,
+                difference={}
+            )
+
+            required_create_keys = ['columns']
+            create_req = False
+
+            for key in required_create_keys:
+                if key in diff_dict:
+                    create_req = True
+
+            if create_req:
+                diff = self.get_sql_from_index_diff(sid=src_sid,
+                                                    did=src_did,
+                                                    scid=src_scid,
+                                                    tid=src_tid,
+                                                    idx=src_oid,
+                                                    diff_schema=target_schema,
+                                                    drop_req=True)
+            else:
+                diff = self.get_sql_from_index_diff(sid=tar_sid,
+                                                    did=tar_did,
+                                                    scid=tar_scid,
+                                                    tid=tar_tid,
+                                                    idx=tar_oid,
+                                                    data=diff_dict)
+
+        return diff
+
 
+SchemaDiffRegistry('index', IndexesView, 'table')
 IndexesView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/utils.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/utils.py
index 44534ac6e..eb9001f0a 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/utils.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/utils.py
@@ -26,7 +26,7 @@ def get_template_path(f):
     def wrap(*args, **kwargs):
         # Here args[0] will hold the connection object
         conn_obj = args[0]
-        if 'template_path' not in kwargs:
+        if 'template_path' not in kwargs or kwargs['template_path'] is None:
             kwargs['template_path'] = \
                 'indexes/sql/#{0}#'.format(conn_obj.manager.version)
 
@@ -229,7 +229,7 @@ def get_sql(conn, data, did, tid, idx, datlastsysoid,
 @get_template_path
 def get_reverse_engineered_sql(conn, schema, table, did, tid, idx,
                                datlastsysoid,
-                               template_path=None):
+                               template_path=None, with_header=True):
     """
     This function will return reverse engineered sql for specified trigger.
 
@@ -240,6 +240,8 @@ def get_reverse_engineered_sql(conn, schema, table, did, tid, idx,
     :param idx: Index ID
     :param datlastsysoid:
     :param template_path: Optional template path
+    :param with_header: Optional parameter to decide whether the SQL will be
+     returned with header or not
     :return:
     """
     SQL = render_template("/".join([template_path, 'properties.sql']),
@@ -267,11 +269,12 @@ def get_reverse_engineered_sql(conn, schema, table, did, tid, idx,
 
     SQL, name = get_sql(conn, data, did, tid, None, datlastsysoid)
 
-    sql_header = u"-- Index: {0}\n\n-- ".format(data['name'])
+    if with_header:
+        sql_header = u"-- Index: {0}\n\n-- ".format(data['name'])
 
-    sql_header += render_template("/".join([template_path, 'delete.sql']),
-                                  data=data, conn=conn)
+        sql_header += render_template("/".join([template_path, 'delete.sql']),
+                                      data=data, conn=conn)
 
-    SQL = sql_header + '\n\n' + SQL
+        SQL = sql_header + '\n\n' + SQL
 
     return SQL
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/partitions/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/partitions/__init__.py
index aa6694a39..4438c89df 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/partitions/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/partitions/__init__.py
@@ -24,6 +24,11 @@ from pgadmin.browser.collection import CollectionNodeModule
 from pgadmin.utils.ajax import make_json_response, precondition_required
 from config import PG_DEFAULT_DRIVER
 from pgadmin.browser.utils import PGChildModule
+from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
+from pgadmin.tools.schema_diff.directory_compare import compare_dictionaries,\
+    directory_diff
+from pgadmin.tools.schema_diff.model import SchemaDiffModel
+from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
 
 
 def backend_supported(module, manager, **kwargs):
@@ -152,7 +157,8 @@ class PartitionsModule(CollectionNodeModule):
 blueprint = PartitionsModule(__name__)
 
 
-class PartitionsView(BaseTableView, DataTypeReader, VacuumSettings):
+class PartitionsView(BaseTableView, DataTypeReader, VacuumSettings,
+                     SchemaDiffObjectCompare):
     """
     This class is responsible for generating routes for Partition node
 
@@ -200,6 +206,10 @@ class PartitionsView(BaseTableView, DataTypeReader, VacuumSettings):
 
     })
 
+    # Schema Diff: Keys to ignore while comparing
+    keys_to_ignore = ['oid', 'schema', 'vacuum_table',
+                      'vacuum_toast', 'edit_types']
+
     def children(self, **kwargs):
         """Build a list of treeview nodes from the child nodes."""
 
@@ -367,6 +377,63 @@ class PartitionsView(BaseTableView, DataTypeReader, VacuumSettings):
         return super(PartitionsView, self).properties(
             gid, sid, did, scid, ptid, res)
 
+    @BaseTableView.check_precondition
+    def fetch_objects_to_compare(self, sid, did, scid, tid, ptid=None):
+        """
+        This function will fetch the list of all the tables for
+        specified schema id.
+
+        :param sid: Server Id
+        :param did: Database Id
+        :param scid: Schema Id
+        :param tid: Table Id
+        :param ptif: Partition table Id
+        :return:
+        """
+        res = {}
+
+        if ptid:
+            SQL = render_template("/".join([self.partition_template_path,
+                                            'properties.sql']),
+                                  did=did, scid=scid, tid=tid,
+                                  ptid=ptid, datlastsysoid=self.datlastsysoid)
+            status, result = self.conn.execute_dict(SQL)
+            if not status:
+                current_app.logger.error(result)
+                return False
+
+            res = super(PartitionsView, self).properties(
+                0, sid, did, scid, ptid, result)
+
+        else:
+            SQL = render_template(
+                "/".join([self.partition_template_path, 'nodes.sql']),
+                scid=scid, tid=tid
+            )
+            status, partitions = self.conn.execute_2darray(SQL)
+            if not status:
+                current_app.logger.error(partitions)
+                return False
+
+            for row in partitions['rows']:
+                SQL = render_template("/".join([self.partition_template_path,
+                                                'properties.sql']),
+                                      did=did, scid=scid, tid=tid,
+                                      ptid=row['oid'],
+                                      datlastsysoid=self.datlastsysoid)
+                status, result = self.conn.execute_dict(SQL)
+
+                if not status:
+                    current_app.logger.error(result)
+                    return False
+
+                data = super(PartitionsView, self).properties(
+                    0, sid, did, scid, row['oid'], result, False
+                )
+                res[row['name']] = data
+
+            return res
+
     @BaseTableView.check_precondition
     def sql(self, gid, sid, did, scid, tid, ptid):
         """
@@ -400,6 +467,62 @@ class PartitionsView(BaseTableView, DataTypeReader, VacuumSettings):
         return BaseTableView.get_reverse_engineered_sql(self, did, scid, ptid,
                                                         main_sql, data)
 
+    @BaseTableView.check_precondition
+    def get_sql_from_diff(self, **kwargs):
+        """
+        This function will create sql on the basis the difference of 2 tables
+        """
+        data = dict()
+        res = None
+        sid = kwargs['sid']
+        did = kwargs['did']
+        scid = kwargs['scid']
+        tid = kwargs['tid']
+        ptid = kwargs['ptid']
+        diff_data = kwargs['diff_data'] if 'diff_data' in kwargs else None
+        json_resp = kwargs['json_resp'] if 'json_resp' in kwargs else True
+        diff_schema = kwargs['diff_schema'] if 'diff_schema' in kwargs else\
+            None
+
+        if diff_data:
+            SQL = render_template("/".join([self.partition_template_path,
+                                            'properties.sql']),
+                                  did=did, scid=scid, tid=tid,
+                                  ptid=ptid, datlastsysoid=self.datlastsysoid)
+            status, res = self.conn.execute_dict(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            SQL, name = self.get_sql(did, scid, ptid, diff_data, res)
+            SQL = re.sub('\n{2,}', '\n\n', SQL)
+            SQL = SQL.strip('\n')
+            return SQL
+        else:
+            main_sql = []
+
+            SQL = render_template("/".join([self.partition_template_path,
+                                            'properties.sql']),
+                                  did=did, scid=scid, tid=tid,
+                                  ptid=ptid, datlastsysoid=self.datlastsysoid)
+            status, res = self.conn.execute_dict(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            if len(res['rows']) == 0:
+                return gone(gettext(
+                    "The specified partitioned table could not be found."))
+
+            data = res['rows'][0]
+
+            if diff_schema:
+                data['schema'] = diff_schema
+                data['parent_schema'] = diff_schema
+
+            return BaseTableView.get_reverse_engineered_sql(self, did,
+                                                            scid, ptid,
+                                                            main_sql, data,
+                                                            False)
+
     @BaseTableView.check_precondition
     def detach(self, gid, sid, did, scid, tid, ptid):
         """
@@ -601,7 +724,7 @@ class PartitionsView(BaseTableView, DataTypeReader, VacuumSettings):
             return internal_server_error(errormsg=str(e))
 
     @BaseTableView.check_precondition
-    def delete(self, gid, sid, did, scid, tid, ptid=None):
+    def delete(self, gid, sid, did, scid, tid, ptid=None, only_sql=False):
         """
         This function will delete the table object
 
@@ -656,5 +779,61 @@ class PartitionsView(BaseTableView, DataTypeReader, VacuumSettings):
         except Exception as e:
             return internal_server_error(errormsg=str(e))
 
+    def ddl_compare(self, **kwargs):
+        """
+        This function will compare index properties and
+        return the difference of SQL
+        """
+
+        src_sid = kwargs.get('source_sid')
+        src_did = kwargs.get('source_did')
+        src_scid = kwargs.get('source_scid')
+        src_tid = kwargs.get('source_tid')
+        src_oid = kwargs.get('source_oid')
+        tar_sid = kwargs.get('target_sid')
+        tar_did = kwargs.get('target_did')
+        tar_scid = kwargs.get('target_scid')
+        tar_tid = kwargs.get('target_tid')
+        tar_oid = kwargs.get('target_oid')
+        comp_status = kwargs.get('comp_status')
+
+        source = ''
+        target = ''
+        diff = ''
+
+        status, target_schema = self.get_schema_for_schema_diff(tar_sid,
+                                                                tar_did,
+                                                                tar_scid
+                                                                )
+        if not status:
+            return internal_server_error(errormsg=target_schema)
+
+        if comp_status == SchemaDiffModel.COMPARISON_STATUS['source_only']:
+            diff = self.get_sql_from_diff(sid=src_sid,
+                                          did=src_did, scid=src_scid,
+                                          tid=src_tid, ptid=src_oid,
+                                          diff_schema=target_schema)
+
+        elif comp_status == SchemaDiffModel.COMPARISON_STATUS['target_only']:
+            SQL = render_template("/".join([self.partition_template_path,
+                                            'properties.sql']),
+                                  did=did, scid=scid, tid=tid,
+                                  ptid=ptid, datlastsysoid=self.datlastsysoid)
+            status, res = self.conn.execute_dict(SQL)
+
+            SQL = render_template(
+                "/".join([self.table_template_path, 'properties.sql']),
+                did=tar_did, scid=tar_scid, tid=tar_oid,
+                datlastsysoid=self.datlastsysoid
+            )
+            status, res = self.conn.execute_dict(SQL)
+            if status:
+                self.cmd = 'delete'
+                diff = super(PartitionsView, self).get_delete_sql(res)
+                self.cmd = None
+
+        return diff
+
 
+SchemaDiffRegistry('partition', PartitionsView, 'table')
 PartitionsView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/rules/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/rules/__init__.py
index 070875e8f..479edf78e 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/rules/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/rules/__init__.py
@@ -13,7 +13,8 @@ import simplejson as json
 from functools import wraps
 
 import pgadmin.browser.server_groups.servers.databases.schemas as schemas
-from flask import render_template, make_response, request, jsonify
+from flask import render_template, make_response, request, jsonify,\
+    current_app
 from flask_babelex import gettext
 from pgadmin.browser.collection import CollectionNodeModule
 from pgadmin.browser.server_groups.servers.databases.schemas.utils import \
@@ -23,7 +24,11 @@ from pgadmin.utils.ajax import make_json_response, internal_server_error, \
     make_response as ajax_response, gone
 from pgadmin.utils.driver import get_driver
 from config import PG_DEFAULT_DRIVER
+from pgadmin.utils.compile_template_name import compile_template_path
 from pgadmin.utils import IS_PY2
+from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
+from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
+
 # If we are in Python3
 if not IS_PY2:
     unicode = str
@@ -134,7 +139,7 @@ class RuleModule(CollectionNodeModule):
 blueprint = RuleModule(__name__)
 
 
-class RuleView(PGChildNodeView):
+class RuleView(PGChildNodeView, SchemaDiffObjectCompare):
     """
     This is a class for rule node which inherits the
     properties and methods from PGChildNodeView class and define
@@ -178,6 +183,9 @@ class RuleView(PGChildNodeView):
         'configs': [{'get': 'configs'}]
     })
 
+    # Schema Diff: Keys to ignore while comparing
+    keys_to_ignore = ['oid', 'schema', 'definition']
+
     def check_precondition(f):
         """
         This function will behave as a decorator which will check the
@@ -197,6 +205,12 @@ class RuleView(PGChildNodeView):
             ]['datlastsysoid'] if self.manager.db_info is not None and \
                 kwargs['did'] in self.manager.db_info else 0
             self.template_path = 'rules/sql'
+            self.table_template_path = compile_template_path(
+                'tables/sql',
+                self.manager.server_type,
+                self.manager.version
+            )
+
             return f(*args, **kwargs)
 
         return wrap
@@ -278,6 +292,21 @@ class RuleView(PGChildNodeView):
         """
         Fetch the properties of an individual rule and render in properties tab
 
+        """
+        status, data = self._fetch_properties(rid)
+        if not status:
+            return data
+
+        return ajax_response(
+            response=data,
+            status=200
+        )
+
+    def _fetch_properties(self, rid):
+        """
+        This function is used to fetch the properties of the specified object
+        :param rid:
+        :return:
         """
         SQL = render_template("/".join(
             [self.template_path, 'properties.sql']
@@ -285,15 +314,13 @@ class RuleView(PGChildNodeView):
         status, res = self.conn.execute_dict(SQL)
 
         if not status:
-            return internal_server_error(errormsg=res)
+            return False, internal_server_error(errormsg=res)
 
         if len(res['rows']) == 0:
-            return gone(gettext("""Could not find the rule in the table."""))
+            return False, gone(
+                gettext("""Could not find the rule in the table."""))
 
-        return ajax_response(
-            response=parse_rule_definition(res),
-            status=200
-        )
+        return True, parse_rule_definition(res)
 
     @check_precondition
     def create(self, gid, sid, did, scid, tid):
@@ -369,7 +396,7 @@ class RuleView(PGChildNodeView):
             return internal_server_error(errormsg=str(e))
 
     @check_precondition
-    def delete(self, gid, sid, did, scid, tid, rid=None):
+    def delete(self, gid, sid, did, scid, tid, rid=None, only_sql=False):
         """
         This function will drop a rule object
         """
@@ -412,6 +439,8 @@ class RuleView(PGChildNodeView):
                     nspname=rset['nspname'],
                     cascade=cascade
                 )
+                if only_sql:
+                    return SQL
                 status, res = self.conn.execute_scalar(SQL)
                 if not status:
                     return internal_server_error(errormsg=res)
@@ -489,6 +518,44 @@ class RuleView(PGChildNodeView):
                 [self.template_path, 'create.sql']), data=data)
         return SQL, data['name'] if 'name' in data else old_data['name']
 
+    @check_precondition
+    def get_sql_from_diff(self, gid, sid, did, scid, tid, oid, data=None,
+                          diff_schema=None, drop_sql=False):
+
+        if drop_sql:
+            SQL = self.delete(gid=gid, sid=sid, did=did,
+                              scid=scid, tid=tid,
+                              rid=oid, only_sql=True)
+        else:
+            SQL = render_template("/".join(
+                [self.template_path, 'properties.sql']), rid=oid)
+            status, res = self.conn.execute_dict(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+            if len(res['rows']) == 0:
+                return gone(
+                    gettext("""Could not find the rule in the table.""")
+                )
+            res_data = parse_rule_definition(res)
+
+            SQL = ''
+
+            if data:
+                old_data = res_data
+                SQL = render_template(
+                    "/".join([self.template_path, 'update.sql']),
+                    data=data, o_data=old_data
+                )
+            else:
+                if diff_schema:
+                    res_data['schema'] = diff_schema
+
+                SQL = render_template("/".join(
+                    [self.template_path, 'create.sql']),
+                    data=res_data, display_comments=True)
+
+        return SQL
+
     @check_precondition
     def dependents(self, gid, sid, did, scid, tid, rid):
         """
@@ -527,5 +594,47 @@ class RuleView(PGChildNodeView):
             status=200
         )
 
+    @check_precondition
+    def fetch_objects_to_compare(self, sid, did, scid, tid, oid=None,
+                                 ignore_keys=False):
+        """
+        This function will fetch the list of all the rules for
+        specified schema id.
+
+        :param sid: Server Id
+        :param did: Database Id
+        :param scid: Schema Id
+        :param tid: Table Id
+        :return:
+        """
+
+        res = {}
+        if oid:
+            status, data = self._fetch_properties(oid)
+            if not status:
+                current_app.logger.error(data)
+                return False
+
+            res = data
+        else:
+            SQL = render_template("/".join([self.template_path,
+                                            'nodes.sql']),
+                                  tid=tid)
+            status, rules = self.conn.execute_2darray(SQL)
+            if not status:
+                current_app.logger.error(rules)
+                return False
+
+            for row in rules['rows']:
+                status, data = self._fetch_properties(row['oid'])
+                if status:
+                    if ignore_keys:
+                        for key in self.keys_to_ignore:
+                            if key in data:
+                                del data[key]
+                    res[row['name']] = data
+        return res
+
 
+SchemaDiffRegistry('rule', RuleView, 'table')
 RuleView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/schema_diff_utils.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/schema_diff_utils.py
new file mode 100644
index 000000000..7a9cff6fa
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/schema_diff_utils.py
@@ -0,0 +1,507 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2019, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+""" Implements Utility class for Table and Partitioned Table. """
+
+import copy
+
+from flask import render_template
+from pgadmin.utils.driver import get_driver
+from config import PG_DEFAULT_DRIVER
+from pgadmin.tools.schema_diff.directory_compare import compare_dictionaries,\
+    directory_diff
+from pgadmin.tools.schema_diff.model import SchemaDiffModel
+from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
+from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
+
+
+class SchemaDiffTableCompare(SchemaDiffObjectCompare):
+
+    keys_to_ignore = ['oid', 'schema', 'vacuum_table',
+                      'vacuum_toast', 'edit_types', 'attnum', 'col_type',
+                      'references', 'reltuples', 'rows_cnt']
+
+    keys_to_ignore_ddl_comp = ['oid',
+                               'schema',
+                               'columns',
+                               'edit_types',
+                               'primary_key',
+                               'exclude_constraint',
+                               'check_constraint',
+                               'foreign_key',
+                               'reltuples',
+                               'rows_cnt'
+                               ]
+
+    keys_to_remove = {
+        'columns': ['relname', 'nspname', 'parent_tbl', 'attrelid', 'adrelid'],
+        'primary_key': ['oid'],
+        'unique_constraint': ['oid'],
+        'check_constraint': ['oid', 'nspname'],
+        'foreign_key': ['oid', 'fknsp', 'confrelid'],
+        'exclude_constraint': ['oid'],
+        'partitions': ['oid'],
+    }
+
+    keys_to_remove_ddl_comp = {
+        'columns': ['relname', 'nspname', 'parent_tbl', 'attrelid', 'adrelid'],
+        'check_constraint': ['nspname'],
+        'foreign_key': ['fknsp', 'confrelid']
+    }
+
+    def compare(self, **kwargs):
+        """
+        This function is used to compare all the table objects
+        from two different schemas.
+
+        :return: Comparison Dictionary
+        """
+        src_sid = kwargs.get('source_sid')
+        src_did = kwargs.get('source_did')
+        src_scid = kwargs.get('source_scid')
+        tar_sid = kwargs.get('target_sid')
+        tar_did = kwargs.get('target_did')
+        tar_scid = kwargs.get('target_scid')
+        sub_modules = ['index', 'rule', 'trigger']
+
+        source_tables = self.fetch_tables(sid=src_sid, did=src_did,
+                                          scid=src_scid)
+
+        target_tables = self.fetch_tables(sid=tar_sid, did=tar_did,
+                                          scid=tar_scid)
+
+        if self.manager.version >= 120000:
+            sub_modules.append('compound_trigger')
+
+        # If both the dict have no items then return None.
+        if not (source_tables or target_tables) or (
+                len(source_tables) <= 0 and len(target_tables) <= 0):
+            return None
+
+        src_server_type, tar_server_type = self.get_server_type(src_sid,
+                                                                tar_sid)
+        for module in sub_modules:
+
+            module_view = SchemaDiffRegistry.get_node_view(
+                module)
+
+            # Get sub module data for source tables
+            if module_view.blueprint.server_type is None or \
+                    src_server_type in module_view.blueprint.server_type:
+                for key, val in source_tables.items():
+                    source = module_view.fetch_objects_to_compare(
+                        sid=src_sid,
+                        did=src_did,
+                        scid=src_scid,
+                        tid=val['oid'],
+                        oid=None,
+                        ignore_keys=True
+                    )
+                    source_tables[key][module] = source
+
+            # Get sub module data for target tables
+            if module_view.blueprint.server_type is None or \
+                    tar_server_type in module_view.blueprint.server_type:
+                for key, val in target_tables.items():
+                    target = module_view.fetch_objects_to_compare(
+                        sid=tar_sid,
+                        did=tar_did,
+                        scid=tar_scid,
+                        tid=val['oid'],
+                        oid=None,
+                        ignore_keys=True
+                    )
+                    target_tables[key][module] = target
+
+        return compare_dictionaries(source_tables, target_tables,
+                                    self.node_type,
+                                    self.blueprint.COLLECTION_LABEL,
+                                    self.keys_to_ignore)
+
+    @staticmethod
+    def get_server_type(src_id, tar_id):
+        """Get server types of source and target servers."""
+        driver = get_driver(PG_DEFAULT_DRIVER)
+        src_manager = driver.connection_manager(src_id)
+        tar_manager = driver.connection_manager(tar_id)
+
+        return src_manager.server_type, tar_manager.server_type
+
+    def ddl_compare(self, **kwargs):
+        """
+        This function will compare properties of 2 tables and
+        return the source DDL, target DDL and Difference of them.
+        """
+
+        src_sid = kwargs.get('source_sid')
+        src_did = kwargs.get('source_did')
+        src_scid = kwargs.get('source_scid')
+        src_oid = kwargs.get('source_oid')
+        tar_sid = kwargs.get('target_sid')
+        tar_did = kwargs.get('target_did')
+        tar_scid = kwargs.get('target_scid')
+        tar_oid = kwargs.get('target_oid')
+        comp_status = kwargs.get('comp_status')
+        generate_script = False
+
+        if 'generate_script' in kwargs and kwargs['generate_script']:
+            generate_script = True
+
+        source = ''
+        target = ''
+        diff = ''
+        ignore_sub_modules = ['column', 'constraints']
+
+        src_server_type, tar_server_type = self.get_server_type(src_sid,
+                                                                tar_sid)
+
+        status, target_schema = self.get_schema(tar_sid,
+                                                tar_did,
+                                                tar_scid
+                                                )
+
+        if not status:
+            return internal_server_error(errormsg=target_schema)
+
+        if comp_status == SchemaDiffModel.COMPARISON_STATUS['source_only']:
+            if not generate_script:
+                source = self.get_sql_from_table_diff(sid=src_sid,
+                                                      did=src_did,
+                                                      scid=src_scid,
+                                                      tid=src_oid,
+                                                      json_resp=False)
+            diff = self.get_sql_from_table_diff(sid=src_sid, did=src_did,
+                                                scid=src_scid, tid=src_oid,
+                                                diff_schema=target_schema,
+                                                json_resp=False)
+
+        elif comp_status == SchemaDiffModel.COMPARISON_STATUS['target_only']:
+            if not generate_script:
+                target = self.get_sql_from_table_diff(sid=tar_sid,
+                                                      did=tar_did,
+                                                      scid=tar_scid,
+                                                      tid=tar_oid,
+                                                      json_resp=False)
+            SQL = render_template(
+                "/".join([self.table_template_path, 'properties.sql']),
+                did=tar_did, scid=tar_scid, tid=tar_oid,
+                datlastsysoid=self.datlastsysoid
+            )
+            status, res = self.conn.execute_dict(SQL)
+
+            if status:
+                diff = self.get_delete_sql(res)
+
+        elif comp_status == SchemaDiffModel.COMPARISON_STATUS['different']:
+            source = self.fetch_tables(
+                sid=src_sid, did=src_did,
+                scid=src_scid, tid=src_oid,
+                keys_to_remove=self.keys_to_remove_ddl_comp
+            )
+            target = self.fetch_tables(
+                sid=tar_sid, did=tar_did,
+                scid=tar_scid, tid=tar_oid,
+                keys_to_remove=self.keys_to_remove_ddl_comp
+            )
+
+            if self.manager.version < 100000:
+                ignore_sub_modules.append('partition')
+
+            if self.manager.version < 120000:
+                ignore_sub_modules.append('compound_trigger')
+
+            # In case of error return None
+            if not (source or target):
+                return None
+
+            diff_dict = directory_diff(
+                source, target, ignore_keys=self.keys_to_ignore_ddl_comp,
+                difference={}
+            )
+
+            # Column comparison
+            col_diff = self.table_col_ddl_comp(source, target)
+            diff_dict.update(col_diff)
+
+            # Constraint comparison
+            pk_diff = self.constraint_ddl_comp(source, target)
+            diff_dict.update(pk_diff)
+
+            diff_dict['relacl'] = self.parce_acl(source, target)
+
+            if not generate_script:
+                source = self.get_sql_from_table_diff(sid=src_sid,
+                                                      did=src_did,
+                                                      scid=src_scid,
+                                                      tid=src_oid,
+                                                      json_resp=False)
+                target = self.get_sql_from_table_diff(sid=tar_sid,
+                                                      did=tar_did,
+                                                      scid=tar_scid,
+                                                      tid=tar_oid,
+                                                      json_resp=False)
+            diff = self.get_sql_from_table_diff(sid=tar_sid, did=tar_did,
+                                                scid=tar_scid, tid=tar_oid,
+                                                diff_data=diff_dict,
+                                                json_resp=False)
+
+            for module in self.blueprint.submodules:
+                if module.NODE_TYPE not in ignore_sub_modules:
+                    module_view = SchemaDiffRegistry.get_node_view(
+                        module.NODE_TYPE)
+
+                    if module_view.blueprint.server_type and (
+                            src_server_type not in
+                            module_view.blueprint.server_type and
+                            tar_server_type not in
+                            module_view.blueprint.server_type
+                    ):
+                        continue
+
+                    if module_view.blueprint.server_type and (
+                            (src_server_type in
+                             module_view.blueprint.server_type and
+                             tar_server_type not in
+                             module_view.blueprint.server_type) or (
+                            src_server_type not in
+                            module_view.blueprint.server_type and
+                            tar_server_type in
+                            module_view.blueprint.server_type)
+                    ):
+                        continue
+
+                    result = module_view.compare(
+                        source_sid=src_sid, source_did=src_did,
+                        source_scid=src_scid, source_tid=src_oid,
+                        target_sid=tar_sid, target_did=tar_did,
+                        target_scid=tar_scid, target_tid=tar_oid
+                    )
+                    if result and module.NODE_TYPE != 'partition':
+                        child_diff = ''
+                        for res in result:
+                            if res['status'] == \
+                                    SchemaDiffModel.COMPARISON_STATUS[
+                                        'different']:
+                                source_oid = res['source_oid']
+                                target_oid = res['target_oid']
+                            else:
+                                source_oid = res['oid']
+                                target_oid = res['oid']
+
+                            if res['status'] != \
+                                    SchemaDiffModel.COMPARISON_STATUS[
+                                        'identical']:
+                                child_diff = module_view.ddl_compare(
+                                    source_sid=src_sid, source_did=src_did,
+                                    source_scid=src_scid,
+                                    source_oid=source_oid,
+                                    source_tid=src_oid, target_sid=tar_sid,
+                                    target_did=tar_did, target_scid=tar_scid,
+                                    target_tid=tar_oid, target_oid=target_oid,
+                                    comp_status=res['status']
+
+                                )
+                                if child_diff:
+                                    diff += child_diff
+                    elif result:
+                        # For partition module
+                        identical = False
+                        source_only = False
+                        target_only = False
+                        different = False
+                        for res in result:
+                            if res['status'] == \
+                                    SchemaDiffModel.COMPARISON_STATUS[
+                                        'identical']:
+                                identical = True
+                            elif res['status'] == \
+                                    SchemaDiffModel.COMPARISON_STATUS[
+                                        'source_only']:
+                                source_only = True
+                            elif res['status'] == \
+                                    SchemaDiffModel.COMPARISON_STATUS[
+                                        'target_only']:
+                                target_only = True
+                            else:
+                                different = True
+
+                        if identical:
+                            pass
+                        elif (source_only or target_only) and not different:
+                            for res in result:
+                                source_oid = res['oid']
+                                target_oid = res['oid']
+
+                                child_diff = module_view.ddl_compare(
+                                    source_sid=src_sid, source_did=src_did,
+                                    source_scid=src_scid,
+                                    source_oid=source_oid,
+                                    source_tid=src_oid, target_sid=tar_sid,
+                                    target_did=tar_did, target_scid=tar_scid,
+                                    target_tid=tar_oid, target_oid=target_oid,
+                                    comp_status=res['status']
+
+                                )
+                                if ddl_compare:
+                                    diff += child_diff
+                        else:
+                            diff = self.get_sql_from_table_diff(
+                                sid=src_sid,
+                                did=src_did,
+                                scid=src_scid,
+                                tid=src_oid,
+                                diff_schema=target_schema,
+                                json_resp=False,
+                                schema_diff_table=True
+                            )
+        else:
+            source = self.get_sql_from_table_diff(sid=src_sid, did=src_did,
+                                                  scid=src_scid, tid=src_oid,
+                                                  json_resp=False)
+            target = self.get_sql_from_table_diff(sid=tar_sid, did=tar_did,
+                                                  scid=tar_scid, tid=tar_oid,
+                                                  json_resp=False)
+
+        return {'source_ddl': source,
+                'target_ddl': target,
+                'diff_ddl': diff
+                }
+
+    @staticmethod
+    def table_col_ddl_comp(source, target):
+        """
+        Table Column comparison
+        :param source: Source columns
+        :param target: Target columns
+        :return: Difference of the columns
+        """
+        source_cols = source['columns']
+        target_cols = copy.deepcopy(target['columns'])
+        added = []
+        updated = []
+        different = {'columns': {}}
+
+        for source in source_cols:
+            if 'name' in source:
+                if type(target_cols) is list and len(
+                        target_cols) > 0:
+                    tmp = None
+                    for item in target_cols:
+                        if item['name'] == source['name']:
+                            tmp = copy.deepcopy(item)
+                    if tmp and source != tmp:
+                        tmp_updated = copy.deepcopy(source)
+                        # Preserve the column number
+                        tmp_updated['attnum'] = tmp['attnum']
+                        if item['typname'] not in tmp_updated['edit_types']:
+                            tmp_updated['col_type_conversion'] = False
+                        updated.append(tmp_updated)
+                        target_cols.remove(tmp)
+                    elif tmp and source == tmp:
+                        target_cols.remove(tmp)
+                    elif tmp is None:
+                        added.append(source)
+                else:
+                    added.append(source)
+            different['columns']['added'] = added
+            different['columns']['changed'] = updated
+
+        if target_cols and len(target_cols) > 0:
+            different['columns']['deleted'] = target_cols
+
+        return different
+
+    @staticmethod
+    def constraint_ddl_comp(source_table, target_table):
+        """
+        Table Constraint DDL comparison
+        :param source: Source Table
+        :param target: Target Table
+        :return: Difference of constraints
+        """
+        different = {}
+        non_editable_keys = {}
+
+        non_editable_keys = {'primary_key': ['col_count',
+                                             'condeferrable',
+                                             'condeffered',
+                                             'columns'],
+                             'check_constraint': ['consrc'],
+                             'exclude_constraint': ['amname',
+                                                    'indconstraint',
+                                                    'columns']
+                             }
+
+        for constraint in ['primary_key', 'check_constraint',
+                           'exclude_constraint']:
+            source_cols = source_table[constraint] if \
+                constraint in source_table else []
+            target_cols = copy.deepcopy(target_table[constraint]) if\
+                constraint in target_table else []
+            added = []
+            updated = []
+            deleted = []
+
+            different[constraint] = {}
+            for source in source_cols:
+                if 'name' in source:
+                    if type(target_cols) is list and len(
+                            target_cols) > 0:
+                        tmp_src = copy.deepcopy(source)
+                        tmp_src.pop('oid')
+                        tmp_tar = None
+                        tmp = None
+                        for item in target_cols:
+                            if item['name'] == source['name']:
+                                tmp_tar = copy.deepcopy(item)
+                                tmp = copy.deepcopy(item)
+                                tmp_tar.pop('oid')
+                        if tmp_tar and tmp_src != tmp_tar:
+                            tmp_updated = copy.deepcopy(source)
+                            for key in non_editable_keys[constraint]:
+                                if key in tmp_updated and \
+                                        tmp_updated[key] != tmp_tar[key]:
+                                    added.append(source)
+                                    deleted.append(tmp_updated)
+                                    tmp_updated = None
+                                    break
+                            if tmp_updated:
+                                tmp_updated['oid'] = tmp_tar['oid']
+                                updated.append(tmp_updated)
+                            target_cols.remove(tmp)
+                        elif tmp_tar and tmp_src == tmp_tar:
+                            target_cols.remove(tmp)
+                        elif tmp_tar is None:
+                            added.append(source)
+                    else:
+                        added.append(source)
+                different[constraint]['added'] = added
+                different[constraint]['changed'] = updated
+                different[constraint]['deleted'] = deleted
+
+            if target_cols and len(target_cols) > 0:
+                different[constraint]['deleted'] = target_cols
+
+        return different
+
+    def remove_keys_for_comparision(self, data, keys=None):
+        """
+        This function is used to remove specific keys from data
+        """
+
+        keys_to_remove = keys if keys else self.keys_to_remove
+
+        for p_key, p_val in keys_to_remove.items():
+            if p_key in data and data[p_key] is not None \
+                    and len(data[p_key]) > 0:
+                for item in data[p_key]:
+                    # Remove keys that should not be the part of comparision.
+                    for key in p_val:
+                        if key in item:
+                            item.pop(key)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/10_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/10_plus/create.sql
index 36eb7ff8e..c189a7488 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/10_plus/create.sql
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/10_plus/create.sql
@@ -21,7 +21,7 @@ CACHE {{data.seqcache|int}} {% endif %}
 {% endif %}{% endif %};
 
 {###  Add comments ###}
-{% if data and data.description %}
+{% if data and data.description and data.description != None %}
 COMMENT ON COLUMN {{conn|qtIdent(data.schema, data.table, data.name)}}
     IS {{data.description|qtLiteral}};
 
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/10_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/10_plus/update.sql
index 4b943defb..4e8b982fd 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/10_plus/update.sql
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/10_plus/update.sql
@@ -10,8 +10,14 @@ ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
 {% endif %}
 {###  Alter column type and collation ###}
 {% if (data.cltype and data.cltype != o_data.cltype) or (data.attlen is defined and data.attlen != o_data.attlen) or (data.attprecision is defined and data.attprecision != o_data.attprecision) or (data.collspcname and data.collspcname != o_data.collspcname)%}
-ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
-    ALTER COLUMN {% if data.name %}{{conn|qtTypeIdent(data.name)}}{% else %}{{conn|qtTypeIdent(o_data.name)}}{% endif %} TYPE {{ GET_TYPE.UPDATE_TYPE_SQL(conn, data, o_data) }}{% if data.collspcname and data.collspcname != o_data.collspcname %}
+{% if data.col_type_conversion is defined and data.col_type_conversion == False %}
+-- WARNING:
+-- The SQL statement below would normally be used to alter the datatype for the {{o_data.name}} column, however,
+-- the current datatype cannot be cast to the target datatype so this conversion cannot be made automatically.
+
+{% endif %}
+{% if data.col_type_conversion is defined and data.col_type_conversion == False %} -- {% endif %}ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
+{% if data.col_type_conversion is defined and data.col_type_conversion == False %} -- {% endif %}    ALTER COLUMN {% if data.name %}{{conn|qtTypeIdent(data.name)}}{% else %}{{conn|qtTypeIdent(o_data.name)}}{% endif %} TYPE {{ GET_TYPE.UPDATE_TYPE_SQL(conn, data, o_data) }}{% if data.collspcname and data.collspcname != o_data.collspcname %}
  COLLATE {{data.collspcname}}{% elif o_data.collspcname %} COLLATE {{o_data.collspcname}}{% endif %};
 {% endif %}
 {###  Alter column default value ###}
@@ -95,7 +101,7 @@ COMMENT ON COLUMN {{conn|qtIdent(data.schema, data.table, o_data.name)}}
 
 {% endif %}
 {### Update column variables ###}
-{% if 'attoptions' in data and data.attoptions|length > 0 %}
+{% if 'attoptions' in data and data.attoptions and data.attoptions|length > 0 %}
 {% set variables = data.attoptions %}
 {% if 'deleted' in variables and variables.deleted|length > 0 %}
 ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/12_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/12_plus/create.sql
index 71de43658..19e26f2c2 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/12_plus/create.sql
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/12_plus/create.sql
@@ -21,7 +21,7 @@ CACHE {{data.seqcache|int}} {% endif %}
 {% endif %}{% endif %}{% if data.colconstype == 'g' and data.genexpr and data.genexpr != '' %} GENERATED ALWAYS AS ({{data.genexpr}}) STORED{% endif %};
 
 {###  Add comments ###}
-{% if data and data.description %}
+{% if data and data.description and data.description != None %}
 COMMENT ON COLUMN {{conn|qtIdent(data.schema, data.table, data.name)}}
     IS {{data.description|qtLiteral}};
 
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/9.2_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/9.2_plus/update.sql
index d27734401..dfb7555c1 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/9.2_plus/update.sql
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/9.2_plus/update.sql
@@ -6,6 +6,12 @@
 {% if data.name and data.name != o_data.name %}
 ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
     RENAME {{conn|qtIdent(o_data.name)}} TO {{conn|qtIdent(data.name)}};
+{% endif %}
+{% if data.col_type_conversion is defined and data.col_type_conversion == False %}
+-- WARNING:
+-- The SQL statement below would normally be used to alter the datatype for the {{o_data.name}} column, however,
+-- the current datatype cannot be cast to the target datatype so this conversion cannot be made automatically.
+
 {% endif %}
 {###  Alter column type and collation ###}
 {% if (data.cltype and data.cltype != o_data.cltype) or (data.attlen is defined and data.attlen != o_data.attlen) or (data.attprecision is defined and data.attprecision != o_data.attprecision) or (data.collspcname and data.collspcname != o_data.collspcname)%}
@@ -45,7 +51,7 @@ PLAIN{% elif data.attstorage == 'm'%}MAIN{% elif data.attstorage == 'e'%}
 EXTERNAL{% elif data.attstorage == 'x'%}EXTENDED{% endif %};
 
 {% endif %}
-{% if data.description is defined %}
+{% if data.description is defined and data.description != None %}
 {% if data.name %}
 COMMENT ON COLUMN {{conn|qtIdent(data.schema, data.table, data.name)}}
 {% else %}
@@ -55,7 +61,7 @@ COMMENT ON COLUMN {{conn|qtIdent(data.schema, data.table, o_data.name)}}
 
 {% endif %}
 {### Update column variables ###}
-{% if 'attoptions' in data and data.attoptions|length > 0 %}
+{% if 'attoptions' in data and data.attoptions != None and data.attoptions|length > 0 %}
 {% set variables = data.attoptions %}
 {% if 'deleted' in variables and variables.deleted|length > 0 %}
 ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/default/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/default/create.sql
index affd88906..ed7f5f1c6 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/default/create.sql
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/default/create.sql
@@ -12,7 +12,7 @@ ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
 
 {% endif %}
 {###  Add comments ###}
-{% if data and data.description %}
+{% if data and data.description and data.description != None %}
 COMMENT ON COLUMN {{conn|qtIdent(data.schema, data.table, data.name)}}
     IS {{data.description|qtLiteral}};
 
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/default/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/default/update.sql
index ac0afe8d1..3c6ae0a91 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/default/update.sql
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/columns/sql/default/update.sql
@@ -9,9 +9,15 @@ ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
 
 {% endif %}
 {###  Alter column type and collation ###}
-{% if (data.cltype and data.cltype != o_data.cltype) or (data.attlen is defined and data.attlen != o_data.attlen) or (data.attprecision is defined and data.attprecision != o_data.attprecision)  or (data.collspcname and data.collspcname != o_data.collspcname) %}
-ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
-    ALTER COLUMN {% if data.name %}{{conn|qtTypeIdent(data.name)}}{% else %}{{conn|qtTypeIdent(o_data.name)}}{% endif %} TYPE {{ GET_TYPE.UPDATE_TYPE_SQL(conn, data, o_data) }}{% if data.collspcname and data.collspcname != o_data.collspcname %}
+{% if (data.cltype and data.cltype != o_data.cltype) or (data.attlen is defined and data.attlen != o_data.attlen) or (data.attprecision is defined and data.attprecision != o_data.attprecision) or (data.collspcname and data.collspcname != o_data.collspcname)%}
+{% if data.col_type_conversion is defined and data.col_type_conversion == False %}
+-- WARNING:
+-- The SQL statement below would normally be used to alter the datatype for the XXX column, however,
+-- the current datatype cannot be cast to the target datatype so this conversion cannot be made automatically.
+
+{% endif %}
+{% if data.col_type_conversion is defined and data.col_type_conversion == False %} -- {% endif %}ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
+{% if data.col_type_conversion is defined and data.col_type_conversion == False %} -- {% endif %}    ALTER COLUMN {% if data.name %}{{conn|qtTypeIdent(data.name)}}{% else %}{{conn|qtTypeIdent(o_data.name)}}{% endif %} TYPE {{ GET_TYPE.UPDATE_TYPE_SQL(conn, data, o_data) }}{% if data.collspcname and data.collspcname != o_data.collspcname %}
  COLLATE {{data.collspcname}}{% elif o_data.collspcname %} COLLATE {{o_data.collspcname}}{% endif %};
 {% endif %}
 {###  Alter column default value ###}
@@ -46,7 +52,7 @@ PLAIN{% elif data.attstorage == 'm'%}MAIN{% elif data.attstorage == 'e'%}
 EXTERNAL{% elif data.attstorage == 'x'%}EXTENDED{% endif %};
 
 {% endif %}
-{% if data.description is defined %}
+{% if data.description is defined and data.description != None %}
 {% if data.name %}
 COMMENT ON COLUMN {{conn|qtIdent(data.schema, data.table, data.name)}}
 {% else %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partitions/sql/pg/10_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partitions/sql/pg/10_plus/create.sql
index 6db5452b5..01f9bfbab 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partitions/sql/pg/10_plus/create.sql
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partitions/sql/pg/10_plus/create.sql
@@ -3,6 +3,7 @@
 {#====== MAIN TABLE TEMPLATE STARTS HERE ======#}
 {#===========================================#}
 {### CREATE TABLE STATEMENT FOR partitions ###}
+
 CREATE {% if data.relpersistence %}UNLOGGED {% endif %}TABLE {{conn|qtIdent(data.schema, data.name)}}{% if data.relispartition is defined and data.relispartition %} PARTITION OF {{conn|qtIdent(data.parent_schema, data.partitioned_table_name)}}{% endif %}
 
 {# Macro to render for constraints #}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/tables/sql/10_plus/schema_diff.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/tables/sql/10_plus/schema_diff.sql
new file mode 100644
index 000000000..ebd4ae6e5
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/tables/sql/10_plus/schema_diff.sql
@@ -0,0 +1,14 @@
+
+
+INSERT INTO {{conn|qtIdent(data.schema, data.name)}}(
+{% if data.columns and data.columns|length > 0 %}
+{% for c in data.columns %}{{c.name}}{% if not loop.last %},{% endif %}{% endfor %}{% endif %})
+SELECT {% if data.columns and data.columns|length > 0 %}{% for c in data.columns %}{{c.name}}{% if not loop.last %},{% endif %}{% endfor %}{% endif %}
+ FROM {{conn|qtIdent(data.schema, data.orig_name)}};
+
+DROP TABLE {{conn|qtIdent(data.schema, data.orig_name)}};
+
+{{partition_sql}}
+
+ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
+    RENAME TO {{conn|qtIdent(data.orig_name)}};
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/__init__.py
index d6f6867e0..97dd00f07 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/__init__.py
@@ -13,7 +13,7 @@ import simplejson as json
 from functools import wraps
 
 import pgadmin.browser.server_groups.servers.databases as database
-from flask import render_template, request, jsonify
+from flask import render_template, request, jsonify, current_app
 from flask_babelex import gettext
 from pgadmin.browser.collection import CollectionNodeModule
 from pgadmin.browser.utils import PGChildNodeView
@@ -25,7 +25,11 @@ from pgadmin.browser.server_groups.servers.databases.schemas.utils \
     import trigger_definition
 from pgadmin.utils.driver import get_driver
 from config import PG_DEFAULT_DRIVER
+from pgadmin.utils.compile_template_name import compile_template_path
 from pgadmin.utils import IS_PY2
+from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
+from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
+
 # If we are in Python3
 if not IS_PY2:
     unicode = str
@@ -151,7 +155,7 @@ class TriggerModule(CollectionNodeModule):
 blueprint = TriggerModule(__name__)
 
 
-class TriggerView(PGChildNodeView):
+class TriggerView(PGChildNodeView, SchemaDiffObjectCompare):
     """
     This class is responsible for generating routes for Trigger node
 
@@ -244,6 +248,10 @@ class TriggerView(PGChildNodeView):
         'enable': [{'put': 'enable_disable_trigger'}]
     })
 
+    # Schema Diff: Keys to ignore while comparing
+    keys_to_ignore = ['oid', 'xmin', 'nspname', 'tfunction',
+                      'tgrelid', 'tgfoid', 'prosrc']
+
     def check_precondition(f):
         """
         This function will behave as a decorator which will checks
@@ -267,6 +275,11 @@ class TriggerView(PGChildNodeView):
                 kwargs['did'] in self.manager.db_info else 0
 
             # we will set template path for sql scripts
+            self.table_template_path = compile_template_path(
+                'tables/sql',
+                self.manager.server_type,
+                self.manager.version
+            )
             self.template_path = 'triggers/sql/{0}/#{1}#'.format(
                 self.manager.server_type, self.manager.version)
             # Store server type
@@ -450,7 +463,22 @@ class TriggerView(PGChildNodeView):
         Returns:
             JSON of selected trigger node
         """
+        status, data = self._fetch_properties(tid, trid)
+        if not status:
+            return data
+
+        return ajax_response(
+            response=data,
+            status=200
+        )
 
+    def _fetch_properties(self, tid, trid):
+        """
+        This function is used to fetch the properties of the specified object
+        :param tid:
+        :param trid:
+        :return:
+        """
         SQL = render_template("/".join([self.template_path,
                                         'properties.sql']),
                               tid=tid, trid=trid,
@@ -459,10 +487,10 @@ class TriggerView(PGChildNodeView):
         status, res = self.conn.execute_dict(SQL)
 
         if not status:
-            return internal_server_error(errormsg=res)
+            return False, internal_server_error(errormsg=res)
 
         if len(res['rows']) == 0:
-            return gone(
+            return False, gone(
                 gettext("""Could not find the trigger in the table."""))
 
         # Making copy of output for future use
@@ -472,10 +500,7 @@ class TriggerView(PGChildNodeView):
 
         data = trigger_definition(data)
 
-        return ajax_response(
-            response=data,
-            status=200
-        )
+        return True, data
 
     @check_precondition
     def create(self, gid, sid, did, scid, tid):
@@ -552,7 +577,7 @@ class TriggerView(PGChildNodeView):
             return internal_server_error(errormsg=str(e))
 
     @check_precondition
-    def delete(self, gid, sid, did, scid, tid, trid=None):
+    def delete(self, gid, sid, did, scid, tid, trid=None, only_sql=False):
         """
         This function will updates existing the trigger object
 
@@ -610,6 +635,8 @@ class TriggerView(PGChildNodeView):
                                       conn=self.conn,
                                       cascade=cascade
                                       )
+                if only_sql:
+                    return SQL
                 status, res = self.conn.execute_scalar(SQL)
                 if not status:
                     return internal_server_error(errormsg=res)
@@ -761,6 +788,35 @@ class TriggerView(PGChildNodeView):
 
         return ajax_response(response=SQL)
 
+    @check_precondition
+    def get_sql_from_diff(self, gid, sid, did, scid, tid, oid,
+                          data=None, diff_schema=None, drop_sql=False):
+        if data:
+            SQL, name = trigger_utils.get_sql(self.conn, data, tid, oid,
+                                              self.datlastsysoid,
+                                              self.blueprint.show_system_objects)
+
+            if not isinstance(SQL, (str, unicode)):
+                return SQL
+            SQL = SQL.strip('\n').strip(' ')
+        else:
+            if drop_sql:
+                SQL = self.delete(gid=gid, sid=sid, did=did,
+                                  scid=scid, tid=tid, trid=oid,
+                                  only_sql=True)
+            else:
+                schema = self.schema
+                if diff_schema:
+                    schema = diff_schema
+                SQL = trigger_utils.get_reverse_engineered_sql(
+                    self.conn, schema,
+                    self.table, tid, oid,
+                    self.datlastsysoid,
+                    self.blueprint.show_system_objects,
+                    template_path=None, with_header=False)
+
+        return SQL
+
     @check_precondition
     def enable_disable_trigger(self, gid, sid, did, scid, tid, trid):
         """
@@ -875,5 +931,46 @@ class TriggerView(PGChildNodeView):
             status=200
         )
 
+    @check_precondition
+    def fetch_objects_to_compare(self, sid, did, scid, tid, oid=None,
+                                 ignore_keys=False):
+        """
+        This function will fetch the list of all the triggers for
+        specified schema id.
+
+        :param sid: Server Id
+        :param did: Database Id
+        :param scid: Schema Id
+        :param tid: Table Id
+        :return:
+        """
+        res = dict()
+
+        if oid:
+            status, data = self._fetch_properties(tid, oid)
+            if not status:
+                current_app.logger.error(data)
+                return False
+            res = data
+        else:
+            SQL = render_template("/".join([self.template_path,
+                                            'nodes.sql']), tid=tid)
+            status, triggers = self.conn.execute_2darray(SQL)
+            if not status:
+                current_app.logger.error(triggers)
+                return False
+
+            for row in triggers['rows']:
+                status, data = self._fetch_properties(tid, row['oid'])
+                if status:
+                    if ignore_keys:
+                        for key in self.keys_to_ignore:
+                            if key in data:
+                                del data[key]
+                    res[row['name']] = data
+
+        return res
+
 
+SchemaDiffRegistry('trigger', TriggerView, 'table')
 TriggerView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/utils.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/utils.py
index 166d2a14c..221f48d52 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/utils.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/utils.py
@@ -30,7 +30,7 @@ def get_template_path(f):
     def wrap(*args, **kwargs):
         # Here args[0] will hold the connection object
         conn_obj = args[0]
-        if 'template_path' not in kwargs:
+        if 'template_path' not in kwargs or kwargs['template_path'] is None:
             kwargs['template_path'] = 'triggers/sql/{0}/#{1}#'.format(
                 conn_obj.manager.server_type, conn_obj.manager.version)
 
@@ -201,7 +201,7 @@ def get_sql(conn, data, tid, trid, datlastsysoid,
 @get_template_path
 def get_reverse_engineered_sql(conn, schema, table, tid, trid,
                                datlastsysoid, show_system_objects,
-                               template_path=None):
+                               template_path=None, with_header=True):
     """
     This function will return reverse engineered sql for specified trigger.
 
@@ -213,6 +213,8 @@ def get_reverse_engineered_sql(conn, schema, table, tid, trid,
     :param datlastsysoid:
     :param show_system_objects: Show System Object value True or False
     :param template_path: Optional template path
+    :param with_header: Optional parameter to decide whether the SQL will be
+     returned with header or not
     :return:
     """
     SQL = render_template("/".join([template_path, 'properties.sql']),
@@ -240,12 +242,15 @@ def get_reverse_engineered_sql(conn, schema, table, tid, trid,
     SQL, name = get_sql(conn, data, tid, None, datlastsysoid,
                         show_system_objects)
 
-    sql_header = u"-- Trigger: {0}\n\n-- ".format(data['name'])
+    if with_header:
+        sql_header = u"-- Trigger: {0}\n\n-- ".format(data['name'])
 
-    sql_header += render_template("/".join([template_path, 'delete.sql']),
-                                  data=data, conn=conn)
+        sql_header += render_template("/".join([template_path, 'delete.sql']),
+                                      data=data, conn=conn)
 
-    SQL = sql_header + '\n\n' + SQL.strip('\n')
+        SQL = sql_header + '\n\n' + SQL.strip('\n')
+    else:
+        SQL = SQL.strip('\n')
 
     # If trigger is disabled then add sql code for the same
     if data['is_enable_trigger'] != 'O':
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/utils.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/utils.py
index 1599d35e2..3247d2fc7 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/utils.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/utils.py
@@ -10,6 +10,7 @@
 """ Implements Utility class for Table and Partitioned Table. """
 
 import re
+import copy
 from functools import wraps
 import simplejson as json
 from flask import render_template, jsonify, request
@@ -179,8 +180,10 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
                 data[row['deftype']] = [priv]
 
         # We will add Auto vacuum defaults with out result for grid
-        data['vacuum_table'] = self.parse_vacuum_data(self.conn, data, 'table')
-        data['vacuum_toast'] = self.parse_vacuum_data(self.conn, data, 'toast')
+        data['vacuum_table'] = copy.deepcopy(
+            self.parse_vacuum_data(self.conn, data, 'table'))
+        data['vacuum_toast'] = copy.deepcopy(
+            self.parse_vacuum_data(self.conn, data, 'toast'))
 
         # Fetch columns for the table logic
         #
@@ -405,7 +408,8 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
             status=200
         )
 
-    def get_reverse_engineered_sql(self, did, scid, tid, main_sql, data):
+    def get_reverse_engineered_sql(self, did, scid, tid, main_sql, data,
+                                   json_resp=True, diff_partition_sql=False):
         """
         This function will creates reverse engineered sql for
         the table object
@@ -416,6 +420,9 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
            tid: Table ID
            main_sql: List contains all the reversed engineered sql
            data: Table's Data
+           json_resp: Json response or plain SQL
+           diff_partition_sql: In Schema diff, the Partition sql should be
+           return separately to perform further task
         """
         """
         #####################################
@@ -427,6 +434,7 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
         schema = data['schema']
         table = data['name']
         is_partitioned = 'is_partitioned' in data and data['is_partitioned']
+        sql_header = ''
 
         data = self._formatter(did, scid, tid, data)
 
@@ -444,18 +452,20 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
                     c['cltype'], c['hasSqrBracket'] = \
                         column_utils.type_formatter(c['cltype'])
 
-        sql_header = u"-- Table: {0}\n\n-- ".format(
-            self.qtIdent(self.conn, data['schema'], data['name']))
+        if json_resp:
+            sql_header = u"-- Table: {0}\n\n-- ".format(
+                self.qtIdent(self.conn, data['schema'], data['name']))
 
-        sql_header += render_template("/".join([self.table_template_path,
-                                                'delete.sql']),
-                                      data=data, conn=self.conn)
+            sql_header += render_template("/".join([self.table_template_path,
+                                                    'delete.sql']),
+                                          data=data, conn=self.conn)
 
-        sql_header = sql_header.strip('\n')
-        sql_header += '\n'
+            sql_header = sql_header.strip('\n')
+            sql_header += '\n'
 
-        # Add into main sql
-        main_sql.append(sql_header)
+            # Add into main sql
+            main_sql.append(sql_header)
+        partition_main_sql = ""
 
         # Parse privilege data
         if 'relacl' in data:
@@ -493,12 +503,14 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
         for row in rset['rows']:
             index_sql = index_utils.get_reverse_engineered_sql(
                 self.conn, schema, table, did, tid, row['oid'],
-                self.datlastsysoid)
+                self.datlastsysoid,
+                template_path=None, with_header=json_resp)
             index_sql = u"\n" + index_sql
 
             # Add into main sql
             index_sql = re.sub('\n{2,}', '\n\n', index_sql)
-            main_sql.append(index_sql)
+
+            main_sql.append(index_sql.strip('\n'))
 
         """
         ########################################
@@ -514,7 +526,8 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
         for row in rset['rows']:
             trigger_sql = trigger_utils.get_reverse_engineered_sql(
                 self.conn, schema, table, tid, row['oid'],
-                self.datlastsysoid, self.blueprint.show_system_objects)
+                self.datlastsysoid, self.blueprint.show_system_objects,
+                template_path=None, with_header=json_resp)
             trigger_sql = u"\n" + trigger_sql
 
             # Add into main sql
@@ -571,10 +584,13 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
             if not status:
                 return internal_server_error(errormsg=res)
 
+            display_comments = True
+            if not json_resp:
+                display_comments = False
             res_data = parse_rule_definition(res)
             rules_sql += render_template("/".join(
                 [self.rules_template_path, 'create.sql']),
-                data=res_data, display_comments=True)
+                data=res_data, display_comments=display_comments)
 
             # Add into main sql
             rules_sql = re.sub('\n{2,}', '\n\n', rules_sql)
@@ -594,13 +610,17 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
                 return internal_server_error(errormsg=rset)
 
             if len(rset['rows']):
-                sql_header = u"\n-- Partitions SQL"
+                if json_resp:
+                    sql_header = u"\n-- Partitions SQL"
                 partition_sql = ''
                 for row in rset['rows']:
                     part_data = dict()
-                    part_data['partitioned_table_name'] = table
-                    part_data['parent_schema'] = schema
-                    part_data['schema'] = row['schema_name']
+                    part_data['partitioned_table_name'] = data['name']
+                    part_data['parent_schema'] = data['schema']
+                    if not json_resp:
+                        part_data['schema'] = data['schema']
+                    else:
+                        part_data['schema'] = row['schema_name']
                     part_data['relispartition'] = True
                     part_data['name'] = row['name']
                     part_data['partition_value'] = row['partition_value']
@@ -612,13 +632,18 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
                         data=part_data, conn=self.conn)
 
                 # Add into main sql
-                partition_sql = re.sub('\n{2,}', '\n\n', partition_sql)
-                main_sql.append(
-                    sql_header + '\n\n' + partition_sql.strip('\n')
-                )
+                partition_sql = re.sub('\n{2,}', '\n\n', partition_sql
+                                       ).strip('\n')
+                partition_main_sql = partition_sql.strip('\n')
+                if not diff_partition_sql:
+                    main_sql.append(
+                        sql_header + '\n\n' + partition_main_sql
+                    )
 
         sql = '\n'.join(main_sql)
 
+        if not json_resp:
+            return sql, partition_main_sql
         return ajax_response(response=sql.strip('\n'))
 
     def reset_statistics(self, scid, tid):
@@ -907,7 +932,8 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
                             conn=self.conn).strip('\n') + '\n\n'
 
                 # If partition(s) is/are added
-                if 'added' in partitions:
+                if 'added' in partitions and 'partition_scheme' in old_data\
+                        and old_data['partition_scheme'] != '':
                     temp_data = dict()
                     temp_data['schema'] = data['schema']
                     temp_data['name'] = data['name']
@@ -1133,7 +1159,8 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
         except Exception as e:
             return internal_server_error(errormsg=str(e))
 
-    def properties(self, gid, sid, did, scid, tid, res):
+    def properties(self, gid, sid, did, scid, tid, res,
+                   return_ajax_response=True):
         """
         This function will show the properties of the selected table node.
 
@@ -1145,6 +1172,7 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
             scid: Schema ID
             tid: Table ID
             res: Table/Partition table properties
+            return_ajax_response: If True then return the ajax response
 
         Returns:
             JSON of selected table node
@@ -1242,6 +1270,9 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
 
             data['partitions'] = partitions
 
+        if not return_ajax_response:
+            return data
+
         return ajax_response(
             response=data,
             status=200
@@ -1359,18 +1390,7 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
             }
         )
 
-    def delete(self, gid, sid, did, scid, tid, res):
-        """
-        This function will delete the table object
-
-         Args:
-           gid: Server Group ID
-           sid: Server ID
-           did: Database ID
-           scid: Schema ID
-           tid: Table ID
-        """
-
+    def get_delete_sql(self, res):
         # Below will decide if it's simple drop or drop with cascade call
         if self.cmd == 'delete':
             # This is a cascade operation
@@ -1380,11 +1400,26 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
 
         data = res['rows'][0]
 
-        SQL = render_template(
+        return render_template(
             "/".join([self.table_template_path, 'delete.sql']),
             data=data, cascade=cascade,
             conn=self.conn
         )
+
+    def delete(self, gid, sid, did, scid, tid, res):
+        """
+        This function will delete the table object
+
+         Args:
+           gid: Server Group ID
+           sid: Server ID
+           did: Database ID
+           scid: Schema ID
+           tid: Table ID
+        """
+
+        SQL = self.get_delete_sql(res)
+
         status, res = self.conn.execute_scalar(SQL)
         if not status:
             return status, res
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/__init__.py
index b50e6d7d7..b173a4058 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/__init__.py
@@ -26,6 +26,8 @@ from pgadmin.utils import IS_PY2
 from pgadmin.utils.ajax import make_json_response, internal_server_error, \
     make_response as ajax_response, gone
 from pgadmin.utils.driver import get_driver
+from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
+from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
 
 # If we are in Python3
 if not IS_PY2:
@@ -94,7 +96,7 @@ class TypeModule(SchemaChildModule):
 blueprint = TypeModule(__name__)
 
 
-class TypeView(PGChildNodeView, DataTypeReader):
+class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
     """
     This class is responsible for generating routes for Type node
 
@@ -173,6 +175,10 @@ class TypeView(PGChildNodeView, DataTypeReader):
     * get_external_functions_list(gid, sid, did, scid, tid):
       - This function will return list of external functions
         in ajax response
+
+    * compare(**kwargs):
+      - This function will compare the type nodes from two
+        different schemas.
     """
 
     node_type = blueprint.node_type
@@ -559,6 +565,22 @@ class TypeView(PGChildNodeView, DataTypeReader):
         Returns:
             JSON of selected type node
         """
+        status, res = self._fetch_properties(scid, tid)
+        if not status:
+            return res
+
+        return ajax_response(
+            response=res,
+            status=200
+        )
+
+    def _fetch_properties(self, scid, tid):
+        """
+        This function is used to fecth the properties of the specified object.
+        :param scid:
+        :param tid:
+        :return:
+        """
 
         SQL = render_template(
             "/".join([self.template_path,
@@ -569,10 +591,10 @@ class TypeView(PGChildNodeView, DataTypeReader):
         )
         status, res = self.conn.execute_dict(SQL)
         if not status:
-            return internal_server_error(errormsg=res)
+            return False, internal_server_error(errormsg=res)
 
         if len(res['rows']) == 0:
-            return gone(
+            return False, gone(
                 gettext("""Could not find the type in the database."""))
 
         # Making copy of output for future use
@@ -583,7 +605,7 @@ class TypeView(PGChildNodeView, DataTypeReader):
                               scid=scid, tid=tid)
         status, acl = self.conn.execute_dict(SQL)
         if not status:
-            return internal_server_error(errormsg=acl)
+            return False, internal_server_error(errormsg=acl)
 
         # We will set get privileges from acl sql so we don't need
         # it from properties sql
@@ -599,10 +621,7 @@ class TypeView(PGChildNodeView, DataTypeReader):
         # Calling function to check and additional properties if available
         copy_dict.update(self.additional_properties(copy_dict, tid))
 
-        return ajax_response(
-            response=copy_dict,
-            status=200
-        )
+        return True, copy_dict
 
     @check_precondition
     def get_collations(self, gid, sid, did, scid, tid=None):
@@ -1428,5 +1447,31 @@ class TypeView(PGChildNodeView, DataTypeReader):
             status=200
         )
 
+    @check_precondition
+    def fetch_objects_to_compare(self, sid, did, scid):
+        """
+        This function will fetch the list of all the types for
+        specified schema id.
+
+        :param sid: Server Id
+        :param did: Database Id
+        :param scid: Schema Id
+        :return:
+        """
+        res = dict()
+        SQL = render_template("/".join([self.template_path,
+                                        'nodes.sql']),
+                              scid=scid, datlastsysoid=self.datlastsysoid)
+        status, rset = self.conn.execute_2darray(SQL)
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        for row in rset['rows']:
+            status, data = self._fetch_properties(scid, row['oid'])
+            if status:
+                res[row['name']] = data
+
+        return res
+
 
 TypeView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/utils.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/utils.py
index 13da66e35..ee87d9694 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/utils.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/utils.py
@@ -15,6 +15,8 @@ from flask import render_template
 
 from pgadmin.browser.collection import CollectionNodeModule
 from pgadmin.utils.ajax import internal_server_error
+from pgadmin.utils.driver import get_driver
+from config import PG_DEFAULT_DRIVER
 
 
 class SchemaChildModule(CollectionNodeModule):
@@ -485,44 +487,50 @@ class VacuumSettings:
         * type - table/toast vacuum type
 
     """
+    vacuum_settings = dict()
 
     def __init__(self):
         pass
 
-    def get_vacuum_table_settings(self, conn):
+    def fetch_default_vacuum_settings(self, conn, sid, setting_type):
         """
-        Fetch the default values for autovacuum
-        fields, return an array of
-          - label
-          - name
-          - setting
-        values
+        This function is used to fetch and cached the default vacuum settings
+        for specified server id.
+        :param conn: Connection Object
+        :param sid:  Server ID
+        :param setting_type: Type (table or toast)
+        :return:
         """
+        if sid in VacuumSettings.vacuum_settings:
+            if setting_type in VacuumSettings.vacuum_settings[sid]:
+                return VacuumSettings.vacuum_settings[sid][setting_type]
+        else:
+            VacuumSettings.vacuum_settings[sid] = dict()
 
         # returns an array of name & label values
         vacuum_fields = render_template("vacuum_settings/vacuum_fields.json")
-
         vacuum_fields = json.loads(vacuum_fields)
 
         # returns an array of setting & name values
         vacuum_fields_keys = "'" + "','".join(
-            vacuum_fields['table'].keys()) + "'"
+            vacuum_fields[setting_type].keys()) + "'"
         SQL = render_template('vacuum_settings/sql/vacuum_defaults.sql',
                               columns=vacuum_fields_keys)
-        status, res = conn.execute_dict(SQL)
 
+        status, res = conn.execute_dict(SQL)
         if not status:
             return internal_server_error(errormsg=res)
 
         for row in res['rows']:
             row_name = row['name']
-            row['name'] = vacuum_fields['table'][row_name][0]
-            row['label'] = vacuum_fields['table'][row_name][1]
-            row['column_type'] = vacuum_fields['table'][row_name][2]
+            row['name'] = vacuum_fields[setting_type][row_name][0]
+            row['label'] = vacuum_fields[setting_type][row_name][1]
+            row['column_type'] = vacuum_fields[setting_type][row_name][2]
 
-        return res
+        VacuumSettings.vacuum_settings[sid][setting_type] = res['rows']
+        return VacuumSettings.vacuum_settings[sid][setting_type]
 
-    def get_vacuum_toast_settings(self, conn):
+    def get_vacuum_table_settings(self, conn, sid):
         """
         Fetch the default values for autovacuum
         fields, return an array of
@@ -531,29 +539,18 @@ class VacuumSettings:
           - setting
         values
         """
+        return self.fetch_default_vacuum_settings(conn, sid, 'table')
 
-        # returns an array of name & label values
-        vacuum_fields = render_template("vacuum_settings/vacuum_fields.json")
-
-        vacuum_fields = json.loads(vacuum_fields)
-
-        # returns an array of setting & name values
-        vacuum_fields_keys = "'" + "','".join(
-            vacuum_fields['toast'].keys()) + "'"
-        SQL = render_template('vacuum_settings/sql/vacuum_defaults.sql',
-                              columns=vacuum_fields_keys)
-        status, res = conn.execute_dict(SQL)
-
-        if not status:
-            return internal_server_error(errormsg=res)
-
-        for row in res['rows']:
-            row_name = row['name']
-            row['name'] = vacuum_fields['toast'][row_name][0]
-            row['label'] = vacuum_fields['toast'][row_name][1]
-            row['column_type'] = vacuum_fields['table'][row_name][2]
-
-        return res
+    def get_vacuum_toast_settings(self, conn, sid):
+        """
+        Fetch the default values for autovacuum
+        fields, return an array of
+          - label
+          - name
+          - setting
+        values
+        """
+        return self.fetch_default_vacuum_settings(conn, sid, 'toast')
 
     def parse_vacuum_data(self, conn, result, type):
         """
@@ -567,47 +564,46 @@ class VacuumSettings:
         * type - table/toast vacuum type
         """
 
-        # returns an array of name & label values
-        vacuum_fields = render_template("vacuum_settings/vacuum_fields.json")
+        vacuum_settings_tmp = self.fetch_default_vacuum_settings(
+            conn, self.manager.sid, type)
 
-        vacuum_fields = json.loads(vacuum_fields)
+        for row in vacuum_settings_tmp:
+            row_name = row['name']
+            if type is 'toast':
+                row_name = 'toast_{0}'.format(row['name'])
+            if row_name in result and result[row_name] is not None:
+                if row['column_type'] == 'number':
+                    value = float(result[row_name])
+                else:
+                    value = int(result[row_name])
+                row['value'] = value
+            else:
+                if 'value' in row:
+                    row.pop('value')
 
-        # returns an array of setting & name values
-        vacuum_fields_keys = "'" + "','".join(
-            vacuum_fields[type].keys()) + "'"
-        SQL = render_template('vacuum_settings/sql/vacuum_defaults.sql',
-                              columns=vacuum_fields_keys)
-        status, res = conn.execute_dict(SQL)
+        return vacuum_settings_tmp
 
-        if not status:
-            return internal_server_error(errormsg=res)
 
-        if type is 'table':
-            for row in res['rows']:
-                row_name = row['name']
-                row['name'] = vacuum_fields[type][row_name][0]
-                row['label'] = vacuum_fields[type][row_name][1]
-                row['column_type'] = vacuum_fields[type][row_name][2]
-                if result[row['name']] is not None:
-                    if row['column_type'] == 'number':
-                        value = float(result[row['name']])
-                    else:
-                        value = int(result[row['name']])
-                    row['value'] = row['setting'] = value
-
-        elif type is 'toast':
-            for row in res['rows']:
-                row_old_name = row['name']
-                row_name = 'toast_{0}'.format(
-                    vacuum_fields[type][row_old_name][0])
-                row['name'] = vacuum_fields[type][row_old_name][0]
-                row['label'] = vacuum_fields[type][row_old_name][1]
-                row['column_type'] = vacuum_fields[type][row_old_name][2]
-                if result[row_name] and result[row_name] is not None:
-                    if row['column_type'] == 'number':
-                        value = float(result[row_name])
-                    else:
-                        value = int(result[row_name])
-                    row['value'] = row['setting'] = value
+def get_schema(sid, did, scid):
+    """
+    This function will return the schema name.
+    """
+
+    driver = get_driver(PG_DEFAULT_DRIVER)
+    manager = driver.connection_manager(sid)
+    conn = manager.connection(did=did)
+
+    ver = manager.version
+    server_type = manager.server_type
+
+    # Fetch schema name
+    status, schema_name = conn.execute_scalar(
+        render_template("/".join(['schemas',
+                                  '{0}/#{1}#'.format(server_type,
+                                                     ver),
+                                  'sql/get_name.sql']),
+                        conn=conn, scid=scid
+                        )
+    )
 
-        return res['rows']
+    return status, schema_name
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/__init__.py
index 4bc357c83..387ee9660 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/__init__.py
@@ -9,6 +9,7 @@
 
 """Implements View and Materialized View Node"""
 
+import copy
 from functools import wraps
 
 import simplejson as json
@@ -18,13 +19,16 @@ from flask_babelex import gettext
 import pgadmin.browser.server_groups.servers.databases as databases
 from config import PG_DEFAULT_DRIVER
 from pgadmin.browser.server_groups.servers.databases.schemas.utils import \
-    SchemaChildModule, parse_rule_definition, VacuumSettings
+    SchemaChildModule, parse_rule_definition, VacuumSettings, get_schema
 from pgadmin.browser.server_groups.servers.utils import parse_priv_from_db, \
     parse_priv_to_db
 from pgadmin.browser.utils import PGChildNodeView
 from pgadmin.utils.ajax import make_json_response, internal_server_error, \
     make_response as ajax_response, gone
 from pgadmin.utils.driver import get_driver
+from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
+from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
+
 
 """
     This module is responsible for generating two nodes
@@ -197,7 +201,7 @@ def check_precondition(f):
     return wrap
 
 
-class ViewNode(PGChildNodeView, VacuumSettings):
+class ViewNode(PGChildNodeView, VacuumSettings, SchemaDiffObjectCompare):
     """
     This class is responsible for generating routes for view node.
 
@@ -250,6 +254,10 @@ class ViewNode(PGChildNodeView, VacuumSettings):
     * dependent(gid, sid, did, scid):
       - This function will generate dependent list to show it in dependent
         pane for the selected view node.
+
+    * compare(**kwargs):
+      - This function will compare the view nodes from two
+        different schemas.
     """
     node_type = view_blueprint.node_type
 
@@ -290,6 +298,8 @@ class ViewNode(PGChildNodeView, VacuumSettings):
             {'get': 'get_toast_table_vacuum'}]
     })
 
+    keys_to_ignore = ['oid', 'schema', 'xmin']
+
     def __init__(self, *args, **kwargs):
         """
         Initialize the variables used by methods of ViewNode.
@@ -400,21 +410,37 @@ class ViewNode(PGChildNodeView, VacuumSettings):
         Fetches the properties of an individual view
         and render in the properties tab
         """
+        status, res = self._fetch_properties(scid, vid)
+        if not status:
+            return res
+
+        return ajax_response(
+            response=res,
+            status=200
+        )
+
+    def _fetch_properties(self, scid, vid):
+        """
+        This function is used to fetch the properties of the specified object
+        :param scid:
+        :param vid:
+        :return:
+        """
         SQL = render_template("/".join(
             [self.template_path, 'sql/properties.sql']
         ), vid=vid, datlastsysoid=self.datlastsysoid)
         status, res = self.conn.execute_dict(SQL)
         if not status:
-            return internal_server_error(errormsg=res)
+            return False, internal_server_error(errormsg=res)
 
         if len(res['rows']) == 0:
-            return gone(gettext("""Could not find the view."""))
+            return False, gone(gettext("""Could not find the view."""))
 
         SQL = render_template("/".join(
             [self.template_path, 'sql/acl.sql']), vid=vid)
         status, dataclres = self.conn.execute_dict(SQL)
         if not status:
-            return internal_server_error(errormsg=res)
+            return False, internal_server_error(errormsg=res)
 
         for row in dataclres['rows']:
             priv = parse_priv_from_db(row)
@@ -428,10 +454,7 @@ class ViewNode(PGChildNodeView, VacuumSettings):
         # merging formated result with main result again
         result.update(frmtd_reslt)
 
-        return ajax_response(
-            response=result,
-            status=200
-        )
+        return True, result
 
     @staticmethod
     def formatter(result):
@@ -556,7 +579,7 @@ class ViewNode(PGChildNodeView, VacuumSettings):
             return internal_server_error(errormsg=str(e))
 
     @check_precondition
-    def delete(self, gid, sid, did, scid, vid=None):
+    def delete(self, gid, sid, did, scid, vid=None, only_sql=False):
         """
         This function will drop a view object
         """
@@ -604,6 +627,10 @@ class ViewNode(PGChildNodeView, VacuumSettings):
                     nspname=res_data['rows'][0]['schema'],
                     name=res_data['rows'][0]['name'], cascade=cascade
                 )
+
+                if only_sql:
+                    return SQL
+
                 status, res = self.conn.execute_scalar(SQL)
                 if not status:
                     return internal_server_error(errormsg=res)
@@ -840,7 +867,7 @@ class ViewNode(PGChildNodeView, VacuumSettings):
 
         return columns
 
-    def get_rule_sql(self, vid):
+    def get_rule_sql(self, vid, display_comments=True):
         """
         Get all non system rules of view node,
         generate their sql and render
@@ -869,12 +896,12 @@ class ViewNode(PGChildNodeView, VacuumSettings):
                 res = parse_rule_definition(res)
                 SQL = render_template("/".join(
                     [self.rule_temp_path, 'sql/create.sql']),
-                    data=res, display_comments=True)
+                    data=res, display_comments=display_comments)
                 SQL_data += '\n'
                 SQL_data += SQL
         return SQL_data
 
-    def get_compound_trigger_sql(self, vid):
+    def get_compound_trigger_sql(self, vid, display_comments=True):
         """
         Get all compound trigger nodes associated with view node,
         generate their sql and render into sql tab
@@ -945,13 +972,13 @@ class ViewNode(PGChildNodeView, VacuumSettings):
                     [self.ct_trigger_temp_path,
                      'sql/{0}/#{1}#/create.sql'.format(
                          self.manager.server_type, self.manager.version)]),
-                    data=res_rows, display_comments=True)
+                    data=res_rows, display_comments=display_comments)
                 SQL_data += '\n'
                 SQL_data += SQL
 
         return SQL_data
 
-    def get_trigger_sql(self, vid):
+    def get_trigger_sql(self, vid, display_comments=True):
         """
         Get all trigger nodes associated with view node,
         generate their sql and render
@@ -1038,13 +1065,13 @@ class ViewNode(PGChildNodeView, VacuumSettings):
                 [self.trigger_temp_path,
                  'sql/{0}/#{1}#/create.sql'.format(
                      self.manager.server_type, self.manager.version)]),
-                data=res_rows, display_comments=True)
+                data=res_rows, display_comments=display_comments)
             SQL_data += '\n'
             SQL_data += SQL
 
         return SQL_data
 
-    def get_index_sql(self, did, vid):
+    def get_index_sql(self, did, vid, display_comments=True):
         """
         Get all index associated with view node,
         generate their sql and render
@@ -1084,17 +1111,23 @@ class ViewNode(PGChildNodeView, VacuumSettings):
             SQL = render_template("/".join(
                 [self.index_temp_path,
                  'sql/#{0}#/create.sql'.format(self.manager.version)]),
-                data=data, display_comments=True)
+                data=data, display_comments=display_comments)
             SQL_data += '\n'
             SQL_data += SQL
         return SQL_data
 
     @check_precondition
-    def sql(self, gid, sid, did, scid, vid):
+    def sql(self, gid, sid, did, scid, vid, diff_schema=None,
+            json_resp=True):
         """
         This function will generate sql to render into the sql panel
         """
 
+        display_comments = True
+
+        if not json_resp:
+            display_comments = False
+
         SQL_data = ''
         SQL = render_template("/".join(
             [self.template_path, 'sql/properties.sql']),
@@ -1111,6 +1144,9 @@ class ViewNode(PGChildNodeView, VacuumSettings):
             )
 
         result = res['rows'][0]
+        if diff_schema:
+            result['schema'] = diff_schema
+
         # sending result to formtter
         frmtd_reslt = self.formatter(result)
 
@@ -1152,18 +1188,20 @@ class ViewNode(PGChildNodeView, VacuumSettings):
             [self.template_path, 'sql/create.sql']),
             data=result,
             conn=self.conn,
-            display_comments=True
+            display_comments=display_comments
         )
         SQL += "\n"
         SQL += render_template("/".join(
             [self.template_path, 'sql/grant.sql']), data=result)
 
         SQL_data += SQL
-        SQL_data += self.get_rule_sql(vid)
-        SQL_data += self.get_trigger_sql(vid)
-        SQL_data += self.get_compound_trigger_sql(vid)
-        SQL_data += self.get_index_sql(did, vid)
+        SQL_data += self.get_rule_sql(vid, display_comments)
+        SQL_data += self.get_trigger_sql(vid, display_comments)
+        SQL_data += self.get_compound_trigger_sql(vid, display_comments)
+        SQL_data += self.get_index_sql(did, vid, display_comments)
 
+        if not json_resp:
+            return SQL_data
         return ajax_response(response=SQL_data)
 
     @check_precondition
@@ -1357,6 +1395,60 @@ class ViewNode(PGChildNodeView, VacuumSettings):
 
         return ajax_response(response=sql)
 
+    @check_precondition
+    def fetch_objects_to_compare(self, sid, did, scid, oid=None):
+        """
+        This function will fetch the list of all the views for
+        specified schema id.
+
+        :param sid: Server Id
+        :param did: Database Id
+        :param scid: Schema Id
+        :return:
+        """
+        res = dict()
+
+        if not oid:
+            SQL = render_template("/".join([self.template_path,
+                                            'sql/nodes.sql']), did=did,
+                                  scid=scid, datlastsysoid=self.datlastsysoid)
+            status, views = self.conn.execute_2darray(SQL)
+            if not status:
+                current_app.logger.error(views)
+                return False
+
+            for row in views['rows']:
+                status, data = self._fetch_properties(scid, row['oid'])
+                if status:
+                    res[row['name']] = data
+        else:
+            status, data = self._fetch_properties(scid, oid)
+            if not status:
+                current_app.logger.error(data)
+                return False
+            res = data
+
+        return res
+
+    def get_sql_from_diff(self, gid, sid, did, scid, oid, data=None,
+                          diff_schema=None, drop_sql=False):
+        sql = ''
+        if data:
+            if diff_schema:
+                data['schema'] = diff_schema
+            sql, nameOrError = self.getSQL(gid, sid, did, data, oid)
+        else:
+            if drop_sql:
+                sql = self.delete(gid=gid, sid=sid, did=did,
+                                  scid=scid, vid=oid, only_sql=True)
+            elif diff_schema:
+                sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, vid=oid,
+                               diff_schema=diff_schema, json_resp=False)
+            else:
+                sql = self.sql(gid=gid, sid=sid, did=did, scid=scid, vid=oid,
+                               json_resp=False)
+        return sql
+
 
 # Override the operations for materialized view
 mview_operations = {
@@ -1631,11 +1723,17 @@ class MViewNode(ViewNode, VacuumSettings):
         return SQL, data['name'] if 'name' in data else old_data['name']
 
     @check_precondition
-    def sql(self, gid, sid, did, scid, vid):
+    def sql(self, gid, sid, did, scid, vid, diff_schema=None,
+            json_resp=True):
         """
         This function will generate sql to render into the sql panel
         """
 
+        display_comments = True
+
+        if not json_resp:
+            display_comments = False
+
         SQL_data = ''
         SQL = render_template("/".join(
             [self.template_path, 'sql/properties.sql']),
@@ -1654,6 +1752,9 @@ class MViewNode(ViewNode, VacuumSettings):
 
         result = res['rows'][0]
 
+        if diff_schema:
+            result['schema'] = diff_schema
+
         # sending result to formtter
         frmtd_reslt = self.formatter(result)
 
@@ -1732,17 +1833,20 @@ class MViewNode(ViewNode, VacuumSettings):
             [self.template_path, 'sql/create.sql']),
             data=result,
             conn=self.conn,
-            display_comments=True
+            display_comments=display_comments
         )
         SQL += "\n"
         SQL += render_template("/".join(
             [self.template_path, 'sql/grant.sql']), data=result)
 
         SQL_data += SQL
-        SQL_data += self.get_rule_sql(vid)
-        SQL_data += self.get_trigger_sql(vid)
-        SQL_data += self.get_index_sql(did, vid)
+        SQL_data += self.get_rule_sql(vid, display_comments)
+        SQL_data += self.get_trigger_sql(vid, display_comments)
+        SQL_data += self.get_index_sql(did, vid, display_comments)
         SQL_data = SQL_data.strip('\n')
+
+        if not json_resp:
+            return SQL_data
         return ajax_response(response=SQL_data)
 
     @check_precondition
@@ -1756,9 +1860,9 @@ class MViewNode(ViewNode, VacuumSettings):
         values
         """
 
-        res = self.get_vacuum_table_settings(self.conn)
+        res = self.get_vacuum_table_settings(self.conn, sid)
         return ajax_response(
-            response=res['rows'],
+            response=res,
             status=200
         )
 
@@ -1772,10 +1876,10 @@ class MViewNode(ViewNode, VacuumSettings):
           - setting
         values
         """
-        res = self.get_vacuum_toast_settings(self.conn)
+        res = self.get_vacuum_toast_settings(self.conn, sid)
 
         return ajax_response(
-            response=res['rows'],
+            response=res,
             status=200
         )
 
@@ -1785,21 +1889,39 @@ class MViewNode(ViewNode, VacuumSettings):
         Fetches the properties of an individual view
         and render in the properties tab
         """
+        status, res = self._fetch_properties(did, scid, vid)
+        if not status:
+            return res
+
+        return ajax_response(
+            response=res,
+            status=200
+        )
+
+    def _fetch_properties(self, did, scid, vid):
+        """
+        This function is used to fetch the properties of the specified object
+        :param did:
+        :param scid:
+        :param vid:
+        :return:
+        """
         SQL = render_template("/".join(
             [self.template_path, 'sql/properties.sql']
         ), did=did, vid=vid, datlastsysoid=self.datlastsysoid)
         status, res = self.conn.execute_dict(SQL)
         if not status:
-            return internal_server_error(errormsg=res)
+            return False, internal_server_error(errormsg=res)
 
         if len(res['rows']) == 0:
-            return gone(gettext("""Could not find the materialized view."""))
+            return False, gone(
+                gettext("""Could not find the materialized view."""))
 
         SQL = render_template("/".join(
             [self.template_path, 'sql/acl.sql']), vid=vid)
         status, dataclres = self.conn.execute_dict(SQL)
         if not status:
-            return internal_server_error(errormsg=res)
+            return False, internal_server_error(errormsg=res)
 
         for row in dataclres['rows']:
             priv = parse_priv_from_db(row)
@@ -1818,10 +1940,7 @@ class MViewNode(ViewNode, VacuumSettings):
         result['vacuum_toast'] = self.parse_vacuum_data(
             self.conn, result, 'toast')
 
-        return ajax_response(
-            response=result,
-            status=200
-        )
+        return True, result
 
     @check_precondition
     def refresh_data(self, gid, sid, did, scid, vid):
@@ -1873,6 +1992,34 @@ class MViewNode(ViewNode, VacuumSettings):
             current_app.logger.exception(e)
             return internal_server_error(errormsg=str(e))
 
+    @check_precondition
+    def fetch_objects_to_compare(self, sid, did, scid, oid=None):
+        """
+        This function will fetch the list of all the mviews for
+        specified schema id.
+
+        :param sid: Server Id
+        :param did: Database Id
+        :param scid: Schema Id
+        :return:
+        """
+        res = dict()
+        SQL = render_template("/".join([self.template_path,
+                                        'sql/nodes.sql']), did=did,
+                              scid=scid, datlastsysoid=self.datlastsysoid)
+        status, rset = self.conn.execute_2darray(SQL)
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        for row in rset['rows']:
+            status, data = self._fetch_properties(did, scid, row['oid'])
+            if status:
+                res[row['name']] = data
+
+        return res
+
 
+SchemaDiffRegistry('view', ViewNode)
 ViewNode.register_node_view(view_blueprint)
+SchemaDiffRegistry('mview', MViewNode)
 MViewNode.register_node_view(mview_blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/pg/9.2_plus/sql/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/pg/9.2_plus/sql/update.sql
index 38606cc0b..d49f7fb9f 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/pg/9.2_plus/sql/update.sql
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/pg/9.2_plus/sql/update.sql
@@ -19,7 +19,7 @@ ALTER TABLE {{ conn|qtIdent(view_schema, view_name) }}
 {% endif %}
 {% if def and def != o_data.definition.rstrip(';') %}
 CREATE OR REPLACE VIEW {{ conn|qtIdent(view_schema, view_name) }}
-    WITH (security_barrier={{ data.security_barrier|lower if data.security_barrier else o_data.security_barrier|default('false', 'true')|lower }})
+    WITH (security_barrier={{ data.security_barrier|lower if data.security_barrier is defined else o_data.security_barrier|default('false', 'true')|lower }})
     AS
     {{ def }};
 {% else %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/pg/9.3_plus/sql/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/pg/9.3_plus/sql/update.sql
index 38606cc0b..d49f7fb9f 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/pg/9.3_plus/sql/update.sql
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/pg/9.3_plus/sql/update.sql
@@ -19,7 +19,7 @@ ALTER TABLE {{ conn|qtIdent(view_schema, view_name) }}
 {% endif %}
 {% if def and def != o_data.definition.rstrip(';') %}
 CREATE OR REPLACE VIEW {{ conn|qtIdent(view_schema, view_name) }}
-    WITH (security_barrier={{ data.security_barrier|lower if data.security_barrier else o_data.security_barrier|default('false', 'true')|lower }})
+    WITH (security_barrier={{ data.security_barrier|lower if data.security_barrier is defined else o_data.security_barrier|default('false', 'true')|lower }})
     AS
     {{ def }};
 {% else %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/pg/9.4_plus/sql/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/pg/9.4_plus/sql/update.sql
index 4235f5c90..805c658d1 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/pg/9.4_plus/sql/update.sql
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/pg/9.4_plus/sql/update.sql
@@ -19,7 +19,7 @@ ALTER TABLE {{ conn|qtIdent(view_schema, view_name) }}
 {% endif %}
 {% if def and def != o_data.definition.rstrip(';') %}
 CREATE OR REPLACE VIEW {{ conn|qtIdent(view_schema, view_name) }}
-    WITH ({% if (data.check_option or o_data.check_option) %}check_option={{ data.check_option if data.check_option else o_data.check_option }}{{', ' }}{% endif %}security_barrier={{ data.security_barrier|lower if data.security_barrier else o_data.security_barrier|default('false', 'true')|lower }})
+    WITH ({% if (data.check_option or o_data.check_option) %}check_option={{ data.check_option if data.check_option else o_data.check_option }}{{', ' }}{% endif %}security_barrier={{ data.security_barrier|lower if data.security_barrier is defined else o_data.security_barrier|default('false', 'true')|lower }})
     AS
     {{ def }};
 {% else %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/templates/databases/css/database.css b/web/pgadmin/browser/server_groups/servers/databases/templates/databases/css/database.css
index f0b12e306..0c9ae10dd 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/templates/databases/css/database.css
+++ b/web/pgadmin/browser/server_groups/servers/databases/templates/databases/css/database.css
@@ -11,4 +11,9 @@
   background-image: url('{{ url_for('NODE-database.static', filename='img/databasebad.svg') }}') !important;
   border-radius: 10px;
   background-size: 20px !important;
+  background-repeat: no-repeat;
+  vertical-align: middle;
+  align-content: center;
+  height: 1.3em;
+
 }
diff --git a/web/pgadmin/static/bundle/slickgrid.js b/web/pgadmin/static/bundle/slickgrid.js
index 731b42026..20670b981 100644
--- a/web/pgadmin/static/bundle/slickgrid.js
+++ b/web/pgadmin/static/bundle/slickgrid.js
@@ -14,9 +14,12 @@ import 'slickgrid/slick.grid';
 import 'slickgrid/slick.dataview';
 import 'slickgrid/slick.editors';
 import 'slickgrid/slick.formatters';
+import 'slickgrid/slick.groupitemmetadataprovider';
 import 'slickgrid/plugins/slick.autotooltips';
 import 'slickgrid/plugins/slick.cellrangedecorator';
 import 'slickgrid/plugins/slick.cellrangeselector';
+import 'slickgrid/plugins/slick.checkboxselectcolumn';
+import 'slickgrid/plugins/slick.rowselectionmodel';
 import 'sources/slickgrid/custom_header_buttons';
 
 export default window.Slick;
diff --git a/web/pgadmin/static/js/backform.pgadmin.js b/web/pgadmin/static/js/backform.pgadmin.js
index eb0821284..d4dbbd9d9 100644
--- a/web/pgadmin/static/js/backform.pgadmin.js
+++ b/web/pgadmin/static/js/backform.pgadmin.js
@@ -817,7 +817,7 @@ define([
     },
   });
 
-  Backform.Accordian = Backform.Dialog.extend({
+  Backform.Accordian   = Backform.Dialog.extend({
     className: function() {
       return 'set-group pg-el-12';
     },
@@ -2129,7 +2129,9 @@ define([
 
     formatter: Select2Formatter,
     template: _.template([
-      '<label class="<%=Backform.controlLabelClassName%>" for="<%=cId%>"><%=label%></label>',
+      '<% if(label == false) {} else {%>',
+      '  <label class="<%=Backform.controlLabelClassName%>" for="<%=cId%>"><%=label%></label>',
+      '<% }%>',
       '<div class="<%=Backform.controlsClassName%>">',
       ' <select id="<%=cId%>" class="<%=Backform.controlClassName%> <%=extraClasses.join(\' \')%>"',
       '  name="<%=name%>" value="<%-value%>" <%=disabled ? "disabled" : ""%>',
@@ -2161,7 +2163,6 @@ define([
       '</div>',
     ].join('\n')),
     render: function() {
-
       if (this.$sel && this.$sel.select2 &&
         this.$sel.select2.hasOwnProperty('destroy')) {
         this.$sel.select2('destroy');
@@ -2465,7 +2466,7 @@ define([
         self.sqlCtrl.setOption('autoCloseBrackets', sqlEditPreferences.insert_pair_brackets);
         self.sqlCtrl.setOption('matchBrackets', sqlEditPreferences.brace_matching);
         setTimeout(function() {
-          self.sqlCtrl.refresh();
+          if (self.sqlCtrl) self.sqlCtrl.refresh();
         }, 500);
       }
     },
diff --git a/web/pgadmin/static/scss/resources/_default.variables.scss b/web/pgadmin/static/scss/resources/_default.variables.scss
index f769e50b3..e13cf08ba 100644
--- a/web/pgadmin/static/scss/resources/_default.variables.scss
+++ b/web/pgadmin/static/scss/resources/_default.variables.scss
@@ -256,4 +256,11 @@ $loading-bg : rgba($black,0.6);
 $loading-fg : $white;
 
 $loader-icon : url("data:image/svg+xml;charset=UTF-8,%3c?xml version='1.0' encoding='utf-8'?%3e%3csvg version='1.1' id='Layer_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 38 38' style='enable-background:new 0 0 38 38;' xml:space='preserve'%3e%3cstyle type='text/css'%3e .st0%7bfill:none;stroke:%23ebeef3;stroke-width:2;%7d .st1%7bfill:none;stroke:%23326690;stroke-width:2;%7d %3c/style%3e%3cg%3e%3cg transform='translate(1 1)'%3e%3ccircle class='st0' cx='18' cy='18' r='18'/%3e%3cpath class='st1' d='M36,18c0-9.9-8.1-18-18-18 '%3e%3canimateTransform accumulate='none' additive='replace' attributeName='transform' calcMode='linear' dur='0.7s' fill='remove' from='0 18 18' repeatCount='indefinite' restart='always' to='360 18 18' type='rotate'%3e%3c/animateTransform%3e%3c/path%3e%3c/g%3e%3c/g%3e%3c/svg%3e ") !default;
+
 $loader-icon-small: url("data:image/svg+xml,%3C%3Fxml version='1.0' encoding='utf-8'%3F%3E%3C!-- Generator: Adobe Illustrator 23.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --%3E%3Csvg version='1.1' id='Layer_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 38 38' style='enable-background:new 0 0 38 38;' xml:space='preserve'%3E%3Cstyle type='text/css'%3E .st0%7Bfill:none;stroke:%23EBEEF3;stroke-width:5;%7D .st1%7Bfill:none;stroke:%23326690;stroke-width:5;%7D%0A%3C/style%3E%3Cg%3E%3Cg transform='translate(1 1)'%3E%3Ccircle class='st0' cx='18' cy='18' r='16'/%3E%3Cpath class='st1' d='M34,18c0-8.8-7.2-16-16-16 '%3E%3CanimateTransform accumulate='none' additive='replace' attributeName='transform' calcMode='linear' dur='0.7s' fill='remove' from='0 18 18' repeatCount='indefinite' restart='always' to='360 18 18' type='rotate'%3E%3C/animateTransform%3E%3C/path%3E%3C/g%3E%3C/g%3E%3C/svg%3E%0A") !default;
+
+/***************/
+
+$schemadiff-diff-row-color: #fff9c4;
+$schemadiff-source-row-color: #ffebee;
+$schemadiff-target-row-color: #fbe3bf;
diff --git a/web/pgadmin/tools/datagrid/static/js/show_query_tool.js b/web/pgadmin/tools/datagrid/static/js/show_query_tool.js
index b7a8d0338..24b44f3e3 100644
--- a/web/pgadmin/tools/datagrid/static/js/show_query_tool.js
+++ b/web/pgadmin/tools/datagrid/static/js/show_query_tool.js
@@ -11,6 +11,7 @@ import gettext from '../../../../static/js/gettext';
 import url_for from '../../../../static/js/url_for';
 import {getTreeNodeHierarchyFromIdentifier} from '../../../../static/js/tree/pgadmin_tree_node';
 import {getPanelTitle} from './datagrid_panel_title';
+import {getRandomInt} from 'sources/utils';
 
 function hasDatabaseInformation(parentData) {
   return parentData.database;
@@ -66,3 +67,21 @@ export function showQueryTool(datagrid, pgBrowser, alertify, url, aciTreeIdentif
 
   datagrid.launch_grid(transId, gridUrl, true, queryToolTitle, sURL);
 }
+
+export function generateScript(parentData, datagrid) {
+  const queryToolTitle = `${parentData.database}/${parentData.user}@${parentData.server}`;
+  const transId = getRandomInt(1, 9999999);
+
+  let url_endpoint = url_for('datagrid.panel', {
+    'trans_id': transId,
+  });
+
+  url_endpoint += `?is_query_tool=${true}`
+    +`&sgid=${parentData.sgid}`
+    +`&sid=${parentData.sid}`
+    +`&server_type=${parentData.stype}`
+    +`&did=${parentData.did}`;
+
+  datagrid.launch_grid(transId, url_endpoint, true, queryToolTitle, '');
+
+}
diff --git a/web/pgadmin/tools/datagrid/templates/datagrid/index.html b/web/pgadmin/tools/datagrid/templates/datagrid/index.html
index 77f8f31f3..ba5f71fc3 100644
--- a/web/pgadmin/tools/datagrid/templates/datagrid/index.html
+++ b/web/pgadmin/tools/datagrid/templates/datagrid/index.html
@@ -443,6 +443,12 @@ require(['sources/generated/browser_nodes', 'sources/generated/codemirror', 'sou
             {{ url_params|safe}},
             '{{ layout|safe }}'
         );
+
+        // If opening from schema diff, set the generated script to the SQL Editor
+        var schema_ddl_diff = (window.opener !== null) ? window.opener.pgAdmin.ddl_diff : window.top.pgAdmin.ddl_diff;
+        sqlEditorController.set_value_to_editor(schema_ddl_diff);
+        if (window.top !== null) window.top.pgAdmin.ddl_diff = '';
+        if (window.opener !== null) window.opener.pgAdmin.ddl_diff = '';
     });
 });
 {% endblock %}
diff --git a/web/pgadmin/tools/schema_diff/__init__.py b/web/pgadmin/tools/schema_diff/__init__.py
new file mode 100644
index 000000000..acd06c3f0
--- /dev/null
+++ b/web/pgadmin/tools/schema_diff/__init__.py
@@ -0,0 +1,613 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2019, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+"""A blueprint module implementing the schema_diff frame."""
+MODULE_NAME = 'schema_diff'
+
+import simplejson as json
+import pickle
+import random
+
+from flask import Response, session, url_for, request
+from flask import render_template, current_app as app
+from flask_security import current_user, login_required
+from flask_babelex import gettext
+from pgadmin.utils import PgAdminModule
+from pgadmin.utils.ajax import make_json_response, bad_request, \
+    internal_server_error, gone, make_response as ajax_response, \
+    not_implemented
+from pgadmin.model import Server
+from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
+from pgadmin.tools.schema_diff.model import SchemaDiffModel
+from config import PG_DEFAULT_DRIVER
+from pgadmin.utils.driver import get_driver
+
+
+class SchemaDiffModule(PgAdminModule):
+    """
+    class SchemaDiffModule(PgAdminModule)
+
+        A module class for Schema Diff derived from PgAdminModule.
+    """
+
+    LABEL = "Schema Diff"
+
+    def get_own_menuitems(self):
+        return {}
+
+    def get_own_javascripts(self):
+        return [{
+            'name': 'pgadmin.schema_diff',
+            'path': url_for('schema_diff.index') + "schema_diff",
+            'when': None
+        }]
+
+    def get_panels(self):
+        return []
+
+    def get_exposed_url_endpoints(self):
+        """
+        Returns:
+            list: URL endpoints for Schema Diff module
+        """
+        return [
+            'schema_diff.initialize',
+            'schema_diff.panel',
+            'schema_diff.servers',
+            'schema_diff.databases',
+            'schema_diff.schemas',
+            'schema_diff.compare',
+            'schema_diff.poll',
+            'schema_diff.ddl_compare',
+            'schema_diff.connect_server',
+            'schema_diff.connect_database',
+            'schema_diff.get_server',
+            'schema_diff.generate_script'
+        ]
+
+    def register_preferences(self):
+        self.preference.register(
+            'display', 'schema_diff_new_browser_tab',
+            gettext("Open in new browser tab"), 'boolean', False,
+            category_label=gettext('Display'),
+            help_str=gettext('If set to True, the Schema Diff '
+                             'will be opened in a new browser tab.')
+        )
+
+
+blueprint = SchemaDiffModule(MODULE_NAME, __name__, static_url_path='/static')
+
+
+@blueprint.route("/")
+@login_required
+def index():
+    return bad_request(
+        errormsg=gettext('This URL cannot be requested directly.')
+    )
+
+
+@blueprint.route(
+    '/panel/<int:trans_id>/<path:editor_title>',
+    methods=["GET"],
+    endpoint='panel'
+)
+def panel(trans_id, editor_title):
+    """
+    This method calls index.html to render the schema diff.
+
+    Args:
+        editor_title: Title of the editor
+    """
+    # If title has slash(es) in it then replace it
+    if request.args and request.args['fslashes'] != '':
+        try:
+            fslashesList = request.args['fslashes'].split(',')
+            for idx in fslashesList:
+                idx = int(idx)
+                editor_title = editor_title[:idx] + '/' + editor_title[idx:]
+        except IndexError as e:
+            app.logger.exception(e)
+
+    return render_template(
+        "schema_diff/index.html",
+        _=gettext,
+        trans_id=trans_id,
+        editor_title=editor_title
+    )
+
+
+@blueprint.route("/schema_diff.js")
+@login_required
+def script():
+    """render the required javascript"""
+    return Response(
+        response=render_template("schema_diff/js/schema_diff.js", _=gettext),
+        status=200,
+        mimetype="application/javascript"
+    )
+
+
+def check_transaction_status(trans_id):
+    """
+    This function is used to check the transaction id
+    is available in the session object.
+
+    Args:
+        trans_id:
+    """
+
+    if 'schemaDiff' not in session:
+        return False, gettext(
+            'Transaction ID not found in the session.'
+        ), None, None
+
+    schema_diff_data = session['schemaDiff']
+
+    # Return from the function if transaction id not found
+    if str(trans_id) not in schema_diff_data:
+        return False, gettext(
+            'Transaction ID not found in the session.'
+        ), None, None
+
+    # Fetch the object for the specified transaction id.
+    # Use pickle.loads function to get the model object
+    session_obj = schema_diff_data[str(trans_id)]
+    diff_model_obj = pickle.loads(session_obj['diff_model_obj'])
+
+    return True, None, diff_model_obj, session_obj
+
+
+def update_session_diff_transaction(trans_id, session_obj, diff_model_obj):
+    """
+    This function is used to update the diff model into the session.
+    :param trans_id:
+    :param session_obj:
+    :param diff_model_obj:
+    :return:
+    """
+    session_obj['diff_model_obj'] = pickle.dumps(diff_model_obj, -1)
+
+    if 'schemaDiff' in session:
+        schema_diff_data = session['schemaDiff']
+        schema_diff_data[str(trans_id)] = session_obj
+        session['schemaDiff'] = schema_diff_data
+
+
+@blueprint.route(
+    '/initialize',
+    methods=["GET"],
+    endpoint="initialize"
+)
+@login_required
+def initialize():
+    """
+    This function will initialize the schema diff and return the list
+    of all the server's.
+    """
+    trans_id = None
+    try:
+        # Create a unique id for the transaction
+        trans_id = str(random.randint(1, 9999999))
+
+        if 'schemaDiff' not in session:
+            schema_diff_data = dict()
+        else:
+            schema_diff_data = session['schemaDiff']
+
+        # Use pickle to store the Schema Diff Model which will be used
+        # later by the diff module.
+        schema_diff_data[trans_id] = {
+            'diff_model_obj': pickle.dumps(SchemaDiffModel(), -1)
+        }
+
+        # Store the schema diff dictionary into the session variable
+        session['schemaDiff'] = schema_diff_data
+
+    except Exception as e:
+        app.logger.exception(e)
+
+    return make_json_response(
+        data={'schemaDiffTransId': trans_id})
+
+
+@blueprint.route(
+    '/servers',
+    methods=["GET"],
+    endpoint="servers"
+)
+@login_required
+def servers():
+    """
+    This function will return the list of servers for the specified
+    server id.
+    """
+    res = []
+    try:
+        """Return a JSON document listing the server groups for the user"""
+        driver = get_driver(PG_DEFAULT_DRIVER)
+
+        from pgadmin.browser.server_groups.servers import\
+            server_icon_and_background
+
+        for server in Server.query.filter_by(user_id=current_user.id):
+            manager = driver.connection_manager(server.id)
+            conn = manager.connection()
+            connected = conn.connected()
+
+            res.append({
+                "value": server.id,
+                "label": server.name,
+                "image": server_icon_and_background(connected, manager,
+                                                    server),
+                "_id": server.id,
+                "connected": connected,
+            })
+
+    except Exception as e:
+        app.logger.exception(e)
+
+    return make_json_response(data=res)
+
+
+@blueprint.route(
+    '/get_server/<int:sid>/<int:did>',
+    methods=["GET"],
+    endpoint="get_server"
+)
+@login_required
+def get_server(sid, did):
+    """
+    This function will return the server details for the specified
+    server id.
+    """
+    try:
+        """Return a JSON document listing the server groups for the user"""
+        driver = get_driver(PG_DEFAULT_DRIVER)
+
+        server = Server.query.filter_by(id=sid).first()
+        manager = driver.connection_manager(sid)
+        conn = manager.connection(did=did)
+        connected = conn.connected()
+
+        res = {
+            "sid": sid,
+            "name": server.name,
+            "user": server.username,
+            "gid": server.servergroup_id,
+            "type": manager.server_type,
+            "connected": connected,
+            "database": conn.db
+        }
+
+    except Exception as e:
+        app.logger.exception(e)
+
+    return make_json_response(data=res)
+
+
+@blueprint.route(
+    '/server/connect/<int:sid>',
+    methods=["POST"],
+    endpoint="connect_server"
+)
+@login_required
+def connect_server(sid):
+    server = Server.query.filter_by(id=sid).first()
+    view = SchemaDiffRegistry.get_node_view('server')
+    return view.connect(server.servergroup_id, sid)
+
+
+@blueprint.route(
+    '/database/connect/<int:sid>/<int:did>',
+    methods=["POST"],
+    endpoint="connect_database"
+)
+@login_required
+def connect_database(sid, did):
+    server = Server.query.filter_by(id=sid).first()
+    view = SchemaDiffRegistry.get_node_view('database')
+    return view.connect(server.servergroup_id, sid, did)
+
+
+@blueprint.route(
+    '/databases/<int:sid>',
+    methods=["GET"],
+    endpoint="databases"
+)
+@login_required
+def databases(sid):
+    """
+    This function will return the list of databases for the specified
+    server id.
+    """
+    res = []
+    try:
+        view = SchemaDiffRegistry.get_node_view('database')
+
+        server = Server.query.filter_by(id=sid).first()
+        response = view.nodes(gid=server.servergroup_id, sid=sid)
+        databases = json.loads(response.data)['data']
+        for db in databases:
+            res.append({
+                "value": db['_id'],
+                "label": db['label'],
+                "_id": db['_id'],
+                "connected": db['connected'],
+                "allowConn": db['allowConn'],
+                "image": db['icon'],
+                "canDisconn": db['canDisconn']
+            })
+
+    except Exception as e:
+        app.logger.exception(e)
+
+    return make_json_response(data=res)
+
+
+@blueprint.route(
+    '/schemas/<int:sid>/<int:did>',
+    methods=["GET"],
+    endpoint="schemas"
+)
+@login_required
+def schemas(sid, did):
+    """
+    This function will return the list of schemas for the specified
+    server id and database id.
+    """
+    res = []
+    try:
+        view = SchemaDiffRegistry.get_node_view('schema')
+        server = Server.query.filter_by(id=sid).first()
+        response = view.nodes(gid=server.servergroup_id, sid=sid, did=did)
+        schemas = json.loads(response.data)['data']
+        for sch in schemas:
+            res.append({
+                "value": sch['_id'],
+                "label": sch['label'],
+                "_id": sch['_id'],
+                "image": sch['icon'],
+            })
+    except Exception as e:
+        app.logger.exception(e)
+
+    return make_json_response(data=res)
+
+
+@blueprint.route(
+    '/compare/<int:trans_id>/<int:source_sid>/<int:source_did>/'
+    '<int:source_scid>/<int:target_sid>/<int:target_did>/<int:target_scid>',
+    methods=["GET"],
+    endpoint="compare"
+)
+@login_required
+def compare(trans_id, source_sid, source_did, source_scid,
+            target_sid, target_did, target_scid):
+    """
+    This function will compare the two schemas.
+    """
+    # Check the transaction and connection status
+    status, error_msg, diff_model_obj, session_obj = \
+        check_transaction_status(trans_id)
+
+    if error_msg == gettext('Transaction ID not found in the session.'):
+        return make_json_response(success=0, errormsg=error_msg, status=404)
+
+    if not check_version_compatibility(source_sid, target_sid):
+        return not_implemented(errormsg=gettext("Version mismatch."))
+
+    comparison_result = []
+
+    diff_model_obj.set_comparison_info("Comparing objects...", 0)
+    update_session_diff_transaction(trans_id, session_obj,
+                                    diff_model_obj)
+
+    try:
+        all_registered_nodes = SchemaDiffRegistry.get_registered_nodes()
+        node_percent = round(100 / len(all_registered_nodes))
+        total_percent = 0
+
+        for node_name, node_view in all_registered_nodes.items():
+            view = SchemaDiffRegistry.get_node_view(node_name)
+            if hasattr(view, 'compare'):
+                msg = "Comparing " + view.blueprint.COLLECTION_LABEL + " ..."
+                diff_model_obj.set_comparison_info(msg, total_percent)
+                # Update the message and total percentage in session object
+                update_session_diff_transaction(trans_id, session_obj,
+                                                diff_model_obj)
+
+                res = view.compare(source_sid=source_sid,
+                                   source_did=source_did,
+                                   source_scid=source_scid,
+                                   target_sid=target_sid,
+                                   target_did=target_did,
+                                   target_scid=target_scid)
+
+                if res is not None:
+                    comparison_result = comparison_result + res
+            total_percent = total_percent + node_percent
+
+        msg = "Successfully compare the specified schemas."
+        total_percent = 100
+        diff_model_obj.set_comparison_info(msg, total_percent)
+        # Update the message and total percentage done in session object
+        update_session_diff_transaction(trans_id, session_obj, diff_model_obj)
+
+    except Exception as e:
+        app.logger.exception(e)
+
+    return make_json_response(data=comparison_result)
+
+
+@blueprint.route(
+    '/poll/<int:trans_id>', methods=["GET"], endpoint="poll"
+)
+@login_required
+def poll(trans_id):
+    """
+    This function is used to check the schema comparison is completed or not.
+    :param trans_id:
+    :return:
+    """
+
+    # Check the transaction and connection status
+    status, error_msg, diff_model_obj, session_obj = \
+        check_transaction_status(trans_id)
+
+    if error_msg == gettext('Transaction ID not found in the session.'):
+        return make_json_response(success=0, errormsg=error_msg, status=404)
+
+    msg, diff_percentage = diff_model_obj.get_comparison_info()
+
+    if diff_percentage == 100:
+        diff_model_obj.set_comparison_info("Comparing objects...", 0)
+        update_session_diff_transaction(trans_id, session_obj,
+                                        diff_model_obj)
+
+    return make_json_response(data={'compare_msg': msg,
+                                    'diff_percentage': diff_percentage})
+
+
+@blueprint.route(
+    '/generate_script/<int:trans_id>/',
+    methods=["POST"],
+    endpoint="generate_script"
+)
+def generate_script(trans_id):
+    """This function will generate the scripts for the selected objects."""
+    data = request.form if request.form else json.loads(
+        request.data, encoding='utf-8'
+    )
+
+    status, error_msg, diff_model_obj, session_obj = \
+        check_transaction_status(trans_id)
+
+    if error_msg == gettext('Transaction ID not found in the session.'):
+        return make_json_response(success=0, errormsg=error_msg, status=404)
+
+    source_sid = int(data['source_sid'])
+    source_did = int(data['source_did'])
+    source_scid = int(data['source_scid'])
+    target_sid = int(data['target_sid'])
+    target_did = int(data['target_did'])
+    target_scid = int(data['target_scid'])
+    diff_ddl = ''
+
+    for d in data['sel_rows']:
+        node_type = d['node_type']
+        source_oid = int(d['source_oid'])
+        target_oid = int(d['target_oid'])
+        comp_status = d['comp_status']
+
+        view = SchemaDiffRegistry.get_node_view(node_type)
+        if view and hasattr(view, 'ddl_compare') and \
+                comp_status != SchemaDiffModel.COMPARISON_STATUS['identical']:
+            sql = view.ddl_compare(source_sid=source_sid,
+                                   source_did=source_did,
+                                   source_scid=source_scid,
+                                   target_sid=target_sid,
+                                   target_did=target_did,
+                                   target_scid=target_scid,
+                                   source_oid=source_oid,
+                                   target_oid=target_oid,
+                                   comp_status=comp_status,
+                                   generate_script=True)
+
+            diff_ddl += sql['diff_ddl']
+
+    return ajax_response(
+        status=200,
+        response={'diff_ddl': diff_ddl}
+    )
+
+
+@blueprint.route(
+    '/ddl_compare/<int:trans_id>/<int:source_sid>/<int:source_did>/'
+    '<int:source_scid>/<int:target_sid>/<int:target_did>/<int:target_scid>/'
+    '<int:source_oid>/<int:target_oid>/<node_type>/<comp_status>/',
+    methods=["GET"],
+    endpoint="ddl_compare"
+)
+@login_required
+def ddl_compare(trans_id, source_sid, source_did, source_scid,
+                target_sid, target_did, target_scid, source_oid,
+                target_oid, node_type, comp_status):
+    """
+    This function is used to compare the specified object and return the
+    DDL comparison.
+    """
+    # Check the transaction and connection status
+    status, error_msg, diff_model_obj, session_obj = \
+        check_transaction_status(trans_id)
+
+    if error_msg == gettext('Transaction ID not found in the session.'):
+        return make_json_response(success=0, errormsg=error_msg, status=404)
+
+    source_ddl = ''
+    target_ddl = ''
+    diff_ddl = ''
+
+    view = SchemaDiffRegistry.get_node_view(node_type)
+    if view and hasattr(view, 'ddl_compare'):
+        sql = view.ddl_compare(source_sid=source_sid, source_did=source_did,
+                               source_scid=source_scid, target_sid=target_sid,
+                               target_did=target_did, target_scid=target_scid,
+                               source_oid=source_oid, target_oid=target_oid,
+                               comp_status=comp_status)
+        return ajax_response(
+            status=200,
+            response={'source_ddl': sql['source_ddl'],
+                      'target_ddl': sql['target_ddl'],
+                      'diff_ddl': sql['diff_ddl']}
+        )
+
+    msg = gettext('Selected object is not supported for DDL comparison.')
+
+    return ajax_response(
+        status=200,
+        response={'source_ddl': msg,
+                  'target_ddl': msg,
+                  'diff_ddl': msg
+                  }
+    )
+
+
+def check_version_compatibility(sid, tid):
+    """Check the version compatibility of source and target servers."""
+
+    driver = get_driver(PG_DEFAULT_DRIVER)
+    src_server = Server.query.filter_by(id=sid).first()
+    src_manager = driver.connection_manager(src_server.id)
+
+    tar_server = Server.query.filter_by(id=tid).first()
+    tar_manager = driver.connection_manager(tar_server.id)
+
+    src_server_version = src_manager.version
+    tar_server_version = tar_manager.version
+
+    server_versions = [120000, 110000, 100000, 90600, 90500, 90400,
+                       90300, 90200, 90100, 90000]
+
+    for version in server_versions:
+        if version > src_server_version:
+            continue
+
+        src_server_version = version
+        break
+
+    for version in server_versions:
+        if version > tar_server_version:
+            continue
+
+        tar_server_version = version
+        break
+
+    if src_server_version == tar_server_version:
+        return True
+    return False
diff --git a/web/pgadmin/tools/schema_diff/compare.py b/web/pgadmin/tools/schema_diff/compare.py
new file mode 100644
index 000000000..424e229e8
--- /dev/null
+++ b/web/pgadmin/tools/schema_diff/compare.py
@@ -0,0 +1,212 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2019, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+""" Implements Utility class for Table and Partitioned Table. """
+
+import copy
+
+from flask import render_template
+from pgadmin.utils.compile_template_name import compile_template_path
+from pgadmin.utils.driver import get_driver
+from config import PG_DEFAULT_DRIVER
+from pgadmin.tools.schema_diff.directory_compare import compare_dictionaries,\
+    directory_diff
+from pgadmin.tools.schema_diff.model import SchemaDiffModel
+from abc import abstractmethod
+
+
+class SchemaDiffObjectCompare():
+
+    keys_to_ignore = ['oid', 'schema']
+
+    @staticmethod
+    def get_schema(sid, did, scid):
+        """
+        This function will return the schema name.
+        """
+
+        driver = get_driver(PG_DEFAULT_DRIVER)
+        manager = driver.connection_manager(sid)
+        conn = manager.connection(did=did)
+
+        ver = manager.version
+        server_type = manager.server_type
+
+        # Fetch schema name
+        status, schema_name = conn.execute_scalar(
+            render_template(
+                "/".join(['schemas',
+                          '{0}/#{1}#'.format(server_type, ver),
+                          'sql/get_name.sql']),
+                conn=conn, scid=scid
+            )
+        )
+
+        return status, schema_name
+
+    def compare(self, **kwargs):
+        """
+        This function is used to compare all the objects
+        from two different schemas.
+
+        :param kwargs:
+        :return:
+        """
+
+        source_params = {'sid': kwargs.get('source_sid'),
+                         'did': kwargs.get('source_did'),
+                         'scid': kwargs.get('source_scid')
+                         }
+
+        target_params = {'sid': kwargs.get('target_sid'),
+                         'did': kwargs.get('target_did'),
+                         'scid': kwargs.get('target_scid')
+                         }
+
+        if 'source_tid' in kwargs:
+            source_params['tid'] = kwargs['source_tid']
+        if 'target_tid' in kwargs:
+            target_params['tid'] = kwargs['target_tid']
+
+        source = self.fetch_objects_to_compare(**source_params)
+
+        target = self.fetch_objects_to_compare(**target_params)
+
+        # If both the dict have no items then return None.
+        if not (source or target) or (
+                len(source) <= 0 and len(target) <= 0):
+            return None
+
+        return compare_dictionaries(source, target,
+                                    self.node_type,
+                                    self.blueprint.COLLECTION_LABEL,
+                                    self.keys_to_ignore)
+
+    def ddl_compare(self, **kwargs):
+        """
+        This function will compare index properties and
+         return the difference of SQL
+        """
+
+        source = ''
+        target = ''
+        diff = ''
+        comp_status = kwargs.get('comp_status')
+        only_diff = False
+        generate_script = False
+
+        source_params = {'gid': 1,
+                         'sid': kwargs.get('source_sid'),
+                         'did': kwargs.get('source_did'),
+                         'scid': kwargs.get('source_scid'),
+                         'oid': kwargs.get('source_oid')
+                         }
+
+        target_params = {'gid': 1,
+                         'sid': kwargs.get('target_sid'),
+                         'did': kwargs.get('target_did'),
+                         'scid': kwargs.get('target_scid'),
+                         'oid': kwargs.get('target_oid')
+                         }
+
+        if 'source_tid' in kwargs:
+            source_params['tid'] = kwargs['source_tid']
+            only_diff = True
+        if 'target_tid' in kwargs:
+            target_params['tid'] = kwargs['target_tid']
+            only_diff = True
+
+        if 'generate_script' in kwargs and kwargs['generate_script']:
+            generate_script = True
+
+        source_params_adv = copy.deepcopy(source_params)
+        target_params_adv = copy.deepcopy(target_params)
+
+        del source_params_adv['gid']
+        del target_params_adv['gid']
+
+        status, target_schema = self.get_schema(kwargs.get('target_sid'),
+                                                kwargs.get('target_did'),
+                                                kwargs.get('target_scid')
+                                                )
+        if not status:
+            return internal_server_error(errormsg=target_schema)
+
+        if comp_status == SchemaDiffModel.COMPARISON_STATUS['source_only']:
+            if not generate_script:
+                source = self.get_sql_from_diff(**source_params)
+            source_params.update({
+                'diff_schema': target_schema
+            })
+            diff = self.get_sql_from_diff(**source_params)
+
+        elif comp_status == SchemaDiffModel.COMPARISON_STATUS['target_only']:
+            if not generate_script:
+                target = self.get_sql_from_diff(**target_params)
+            target_params.update(
+                {'drop_sql': True})
+            diff = self.get_sql_from_diff(**target_params)
+
+        elif comp_status == SchemaDiffModel.COMPARISON_STATUS['different']:
+            source = self.fetch_objects_to_compare(**source_params_adv)
+            target = self.fetch_objects_to_compare(**target_params_adv)
+
+            if not (source or target):
+                return None
+
+            diff_dict = directory_diff(source,
+                                       target,
+                                       ignore_keys=self.keys_to_ignore,
+                                       difference={}
+                                       )
+
+            diff_dict.update(self.parce_acl(source, target))
+
+            if not generate_script:
+                source = self.get_sql_from_diff(**source_params)
+                target = self.get_sql_from_diff(**target_params)
+
+            target_params.update(
+                {'data': diff_dict})
+            diff = self.get_sql_from_diff(**target_params)
+        else:
+            source = self.get_sql_from_diff(**source_params)
+            target = self.get_sql_from_diff(**target_params)
+
+        if only_diff:
+            return diff
+
+        return {'source_ddl': source,
+                'target_ddl': target,
+                'diff_ddl': diff
+                }
+
+    @staticmethod
+    def parce_acl(source, target):
+        key = 'acl'
+
+        if 'datacl' in source:
+            key = 'datacl'
+        elif 'relacl' in source:
+            key = 'relacl'
+
+        tmp_source = source[key] if\
+            key in source and source[key] is not None else []
+        tmp_target = copy.deepcopy(target[key]) if\
+            key in target and target[key] is not None else []
+
+        diff = {'added': [], 'deleted': []}
+        for acl in tmp_source:
+            if acl in tmp_target:
+                tmp_target.remove(acl)
+            elif acl not in tmp_target:
+                diff['added'].append(acl)
+        diff['deleted'] = tmp_target
+
+        return {key: diff}
diff --git a/web/pgadmin/tools/schema_diff/directory_compare.py b/web/pgadmin/tools/schema_diff/directory_compare.py
new file mode 100644
index 000000000..eeb495d36
--- /dev/null
+++ b/web/pgadmin/tools/schema_diff/directory_compare.py
@@ -0,0 +1,279 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2019, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+"""Directory comparison"""
+
+import copy
+from pgadmin.tools.schema_diff.model import SchemaDiffModel
+
+count = 1
+
+
+def compare_dictionaries(source_dict, target_dict, node, node_label,
+                         ignore_keys=None):
+    """
+    This function will compare the two dictionaries.
+
+    :param source_dict: First Dictionary
+    :param target_dict: Second Dictionary
+    :param node: node type
+    :param ignore_keys: List of keys that will be ignored while comparing
+    :return:
+    """
+
+    dict1 = copy.deepcopy(source_dict)
+    dict2 = copy.deepcopy(target_dict)
+
+    # Find the duplicate keys in both the dictionaries
+    dict1_keys = set(dict1.keys())
+    dict2_keys = set(dict2.keys())
+    intersect_keys = dict1_keys.intersection(dict2_keys)
+
+    # Keys that are available in source and missing in target.
+    source_only = []
+    added = dict1_keys - dict2_keys
+    global count
+    for item in added:
+        source_only.append({
+            'id': count,
+            'type': node,
+            'label': node_label,
+            'title': item,
+            'oid': source_dict[item]['oid'],
+            'status': SchemaDiffModel.COMPARISON_STATUS['source_only']
+        })
+        count += 1
+
+    target_only = []
+    # Keys that are available in target and missing in source.
+    removed = dict2_keys - dict1_keys
+    for item in removed:
+        target_only.append({
+            'id': count,
+            'type': node,
+            'label': node_label,
+            'title': item,
+            'oid': target_dict[item]['oid'],
+            'status': SchemaDiffModel.COMPARISON_STATUS['target_only']
+        })
+        count += 1
+
+    # Compare the values of duplicates keys.
+    identical = []
+    different = []
+    for key in intersect_keys:
+        # ignore the keys if available.
+        for ig_key in ignore_keys:
+            if ig_key in dict1[key]:
+                dict1[key].pop(ig_key)
+            if ig_key in dict2[key]:
+                dict2[key].pop(ig_key)
+
+        # Recursively Compare the two dictionary
+        if are_dictionaries_identical(dict1[key], dict2[key], ignore_keys):
+            identical.append({
+                'id': count,
+                'type': node,
+                'label': node_label,
+                'title': key,
+                'oid': source_dict[key]['oid'],
+                'source_oid': source_dict[key]['oid'],
+                'target_oid': target_dict[key]['oid'],
+                'status': SchemaDiffModel.COMPARISON_STATUS['identical']
+            })
+        else:
+            different.append({
+                'id': count,
+                'type': node,
+                'label': node_label,
+                'title': key,
+                'oid': source_dict[key]['oid'],
+                'source_oid': source_dict[key]['oid'],
+                'target_oid': target_dict[key]['oid'],
+                'status': SchemaDiffModel.COMPARISON_STATUS['different']
+            })
+        count += 1
+
+    return source_only + target_only + different + identical
+
+
+def are_lists_identical(source_list, target_list, ignore_keys):
+    """
+    This function is used to compare two list.
+    :param source_list:
+    :param target_list:
+    :return:
+    """
+    if source_list is None or target_list is None or \
+            len(source_list) != len(target_list):
+        return False
+    else:
+        for index in range(len(source_list)):
+            # Check the type of the value if it is an dictionary then
+            # call are_dictionaries_identical() function.
+            if type(source_list[index]) is dict:
+                if not are_dictionaries_identical(source_list[index],
+                                                  target_list[index],
+                                                  ignore_keys):
+                    return False
+            else:
+                if source_list[index] != target_list[index]:
+                    return False
+    return True
+
+
+def are_dictionaries_identical(source_dict, target_dict, ignore_keys):
+    """
+    This function is used to recursively compare two dictionaries with
+    same keys.
+    :param source_dict:
+    :param target_dict:
+    :return:
+    """
+
+    src_keys = set(source_dict.keys())
+    tar_keys = set(target_dict.keys())
+
+    # ignore the keys if available.
+    for ig_key in ignore_keys:
+        if ig_key in src_keys:
+            source_dict.pop(ig_key)
+        if ig_key in target_dict:
+            target_dict.pop(ig_key)
+
+    # Keys that are available in source and missing in target.
+    src_only = src_keys - tar_keys
+    # Keys that are available in target and missing in source.
+    tar_only = tar_keys - src_keys
+
+    # If number of keys are different in source and target then
+    # return False
+    if len(src_only) != len(tar_only):
+        return False
+    else:
+        # If number of keys are same but key is not present in target then
+        # return False
+        for key in src_only:
+            if key not in tar_only:
+                return False
+
+    for key in source_dict.keys():
+        if type(source_dict[key]) is dict:
+            if not are_dictionaries_identical(source_dict[key],
+                                              target_dict[key], ignore_keys):
+                return False
+        elif type(source_dict[key]) is list:
+            if not are_lists_identical(source_dict[key], target_dict[key],
+                                       ignore_keys):
+                return False
+        else:
+            if source_dict[key] != target_dict[key]:
+                return False
+
+    return True
+
+
+def directory_diff(source_dict, target_dict, ignore_keys=[], difference={}):
+    """
+    This function is used to recursively compare two dictionaries and
+    return the difference.
+    The difference is from source to target
+    :param source_dict: source dict
+    :param target_dict: target dict
+    :param ignore_keys: ignore keys to compare
+    """
+
+    src_keys = set(source_dict.keys())
+    tar_keys = set(target_dict.keys())
+
+    # Keys that are available in source and missing in target.
+    src_only = src_keys - tar_keys
+    # Keys that are available in target and missing in source.
+    tar_only = tar_keys - src_keys
+
+    for key in source_dict.keys():
+        added = []
+        deleted = []
+        updated = []
+        source = None
+
+        # ignore the keys if available.
+        if key in ignore_keys:
+            pass
+        elif key in tar_only:
+            target_only[key] = target_dict[key]
+            # Target only values in deleted list
+            difference[key]['deleted'] = target_dict[key]
+        elif key in src_only:
+            # Source only values in the newly added list
+            if type(source_dict[key]) is list:
+                difference[key] = {}
+                difference[key]['added'] = source_dict[key]
+        elif type(source_dict[key]) is dict:
+            directory_diff(source_dict[key], target_dict[key],
+                           ignore_keys, difference)
+        elif type(source_dict[key]) is list:
+            tmp_target = None
+            for index in range(len(source_dict[key])):
+                source = copy.deepcopy(source_dict[key][index])
+                if type(source) is list:
+                    # TODO
+                    pass
+                elif type(source) is dict:
+                    if 'name' in source or 'colname' in source:
+                        if type(target_dict[key]) is list and len(
+                                target_dict[key]) > 0:
+                            tmp = None
+                            tmp_target = copy.deepcopy(target_dict[key])
+                            for item in tmp_target:
+                                if (
+                                        'name' in item and
+                                        item['name'] == source['name']
+                                ) or (
+                                        'colname' in item and
+                                        item['colname'] == source['colname']
+                                ):
+                                    tmp = copy.deepcopy(item)
+                            if tmp and source != tmp:
+                                updated.append(copy.deepcopy(source))
+                                tmp_target.remove(tmp)
+                            elif tmp and source == tmp:
+                                tmp_target.remove(tmp)
+                            elif tmp is None:
+                                added.append(source)
+                        else:
+                            added.append(source)
+                    difference[key] = {}
+                    difference[key]['added'] = added
+                    difference[key]['changed'] = updated
+                elif target_dict[key] is None or \
+                        (type(target_dict[key]) is list and
+                         len(target_dict[key]) < index and
+                         source != target_dict[key][index]):
+                    difference[key] = source
+                elif type(target_dict[key]) is list and\
+                        len(target_dict[key]) > index:
+                    difference[key] = source
+
+            if type(source) is dict and tmp_target and key in tmp_target and \
+                    tmp_target[key] and len(tmp_target[key]) > 0:
+                if type(tmp_target[key]) is list and \
+                        type(tmp_target[key][0]) is dict:
+                    deleted = deleted + tmp_target[key]
+                else:
+                    deleted.append({key: tmp_target[key]})
+                difference[key]['deleted'] = deleted
+            elif tmp_target and type(tmp_target) is list:
+                difference[key]['deleted'] = tmp_target
+
+        else:
+            if source_dict[key] != target_dict[key]:
+                difference[key] = source_dict[key]
+
+    return difference
diff --git a/web/pgadmin/tools/schema_diff/model.py b/web/pgadmin/tools/schema_diff/model.py
new file mode 100644
index 000000000..4fac21007
--- /dev/null
+++ b/web/pgadmin/tools/schema_diff/model.py
@@ -0,0 +1,76 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2019, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+
+class SchemaDiffModel(object):
+    """
+    SchemaDiffModel
+    """
+
+    COMPARISON_STATUS = {
+        'source_only': 'Source Only',
+        'target_only': 'Target Only',
+        'different': 'Different',
+        'identical': 'Identical'
+    }
+
+    def __init__(self, **kwargs):
+        """
+        This method is used to initialize the class and
+        create a proper object name which will be used
+        to fetch the data using namespace name and object name.
+
+        Args:
+            **kwargs : N number of parameters
+        """
+        self._comparison_result = dict()
+        self._comparison_msg = 'Comparision started...'
+        self._comparison_percentage = 0
+
+    def clear_data(self):
+        """
+        This function clear the model data.
+        """
+        self._comparison_result.clear()
+
+    def set_result(self, node_name, compare_result):
+        """
+        This method set the result of the comparision based on nodes.
+        """
+        self._comparison_result[node_name] = compare_result
+
+    def get_result(self, node_name=None):
+        """
+        This function will return the result for the node if specified
+        else return the complete result.
+        :param node_name: Name of the node ex: Database, Schema, etc..
+        :return:
+        """
+
+        if node_name is not None:
+            return self._comparison_result[node_name]
+
+        return self._comparison_result
+
+    def get_comparison_info(self):
+        """
+        This function is used to get the comparison information.
+        :return:
+        """
+        return self._comparison_msg, self._comparison_percentage
+
+    def set_comparison_info(self, msg, percentage):
+        """
+        This function is used to set the comparison information.
+        :param msg:
+        :param percentage:
+        :return:
+        """
+        self._comparison_msg = msg
+        self._comparison_percentage = percentage
diff --git a/web/pgadmin/tools/schema_diff/node_registry.py b/web/pgadmin/tools/schema_diff/node_registry.py
new file mode 100644
index 000000000..9e7e25533
--- /dev/null
+++ b/web/pgadmin/tools/schema_diff/node_registry.py
@@ -0,0 +1,61 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2019, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+
+class SchemaDiffRegistry(object):
+    """
+    SchemaDiffRegistry
+
+    It is more of a registry for different type of nodes for schema diff.
+    """
+    _registered_nodes = dict()
+
+    def __init__(self, node_name, node_view, parent_node='schema'):
+        if node_name not in SchemaDiffRegistry._registered_nodes:
+            SchemaDiffRegistry._registered_nodes[node_name] = {
+                'view': node_view,
+                'parent': parent_node
+            }
+
+    @classmethod
+    def get_registered_nodes(cls, node_name=None, parent_node='schema'):
+        """
+        This function will return the node's view object if node name
+        is specified or return the complete list of registered nodes.
+
+        :param node_name: Name of the node ex: Database, Schema, etc..
+        :return:
+        """
+        if node_name is not None:
+            if node_name in cls._registered_nodes:
+                return cls._registered_nodes[node_name]['view']
+            else:
+                return None
+
+        registered_nodes = {}
+        for key, value in cls._registered_nodes.items():
+            if value['parent'] == parent_node:
+                registered_nodes[key] = value['view']
+
+        return registered_nodes
+
+    @classmethod
+    def get_node_view(cls, node_name):
+        """
+        This function will return the view object for the "nodes"
+        command as per the specified node name.
+
+        :param node_name: Name of the node ex: Database, Schema, etc..
+        :return:
+        """
+        cmd = {"cmd": "nodes, compare, ddl_compare"}
+        module = SchemaDiffRegistry.get_registered_nodes(node_name)
+        if not module:
+            return None
+        return module(**cmd)
diff --git a/web/pgadmin/tools/schema_diff/static/css/schema_diff.css b/web/pgadmin/tools/schema_diff/static/css/schema_diff.css
new file mode 100644
index 000000000..af9ae3a7f
--- /dev/null
+++ b/web/pgadmin/tools/schema_diff/static/css/schema_diff.css
@@ -0,0 +1,189 @@
+.icon-schema-diff {
+  display: inline-block;
+  align-content: center;
+  vertical-align: middle;
+  height: 18px;
+  width: 18px;
+  background-size: 20px !important;
+  background-repeat: no-repeat;
+  background-position-x: center;
+  background-position-y: center;
+  background-image: url('../img/compare.svg') !important;
+}
+
+.icon-schema-diff-white {
+  display: inline-block;
+  align-content: center;
+  vertical-align: middle;
+  height: 18px;
+  width: 18px;
+  background-size: 20px !important;
+  background-repeat: no-repeat;
+  background-position-x: center;
+  background-position-y: center;
+  background-image: url('../img/compare-white.svg') !important;
+}
+
+.icon-script {
+  display: inline-block;
+  align-content: center;
+  vertical-align: middle;
+  height: 18px;
+  width: 18px;
+  background-size: 20px !important;
+  background-repeat: no-repeat;
+  background-position-x: center;
+  background-position-y: center;
+  background-image: url('../img/script.svg') !important;
+}
+
+.reallyHidden {
+  display: none !important;
+}
+
+#schema-diff-header {
+  margin-top: 2px;
+}
+
+#schema-diff-header .control-label {
+  width: 120px !important;
+  padding: 5px 5px !important;
+}
+
+#schema-diff-grid {
+  background: white;
+  outline: 0;
+  font-size: 9pt;
+  margin-top: 28px;
+}
+
+.slick-header-column.ui-state-default {
+    height: 32px !important;
+}
+
+#schema-diff-grid .grid-header label {
+  display: inline-block;
+  font-weight: bold;
+  margin: auto auto auto 6px;
+}
+
+.grid-header .ui-icon {
+  margin: 4px 4px auto 6px;
+  background-color: transparent;
+  border-color: transparent;
+}
+
+.slick-row .cell-actions {
+  text-align: left;
+}
+
+/* Slick.Editors.Text, Slick.Editors.Date */
+#schema-diff-grid .slick-header > input.editor-text {
+  width: 100%;
+  height: 100%;
+  border: 0;
+  margin: 0;
+  background: transparent;
+  outline: 0;
+  padding: 0;
+}
+
+/* Slick.Editors.Checkbox */
+#schema-diff-grid .slick-header > input.editor-checkbox {
+  margin: 0;
+  height: 100%;
+  padding: 0;
+  border: 0;
+}
+
+.slick-row.selected .cell-selection {
+  background-color: transparent; /* show default selected row background */
+}
+
+#schema-diff-grid .slick-header .ui-state-default,
+#schema-diff-grid .slick-header .ui-widget-content.ui-state-default,
+#schema-diff-grid .slick-header .ui-widget-header .ui-state-default {
+  background: none;
+}
+
+#schema-diff-grid .slick-header .slick-header-column {
+  font-weight: bold;
+  display: block;
+}
+
+
+.slick-group-toggle.collapsed {
+  width: 30px;
+  background: url(../../../../static/img/collapse_expand.svg) 10px 1px no-repeat !important;
+}
+
+.slick-group-toggle.expanded {
+  width: 30px;
+  background: url(../../../../static/img/collapse_expand.svg) -10px 1px no-repeat !important;
+}
+
+
+.slick-group-toggle {
+  margin-right: 0px !important;
+  height: 11px !important;
+}
+
+#schema-diff-ddl-comp .badge .caret {
+    display: inline-block;
+    margin-left: 2px;
+    margin-right: 4px;
+    width: 0.7rem;
+}
+
+#schema-diff-ddl-comp .badge .caret::before {
+  font-family: "FontAwesome";
+  content: "\f078";
+  font-size: 0.7rem;
+  margin-left: 0rem;
+}
+
+#schema-diff-ddl-comp .badge {
+  font-size: inherit;
+  padding: 7px;
+}
+
+#schema-diff-ddl-comp .accordian-group {
+  padding: 0px;
+}
+
+#ddl_comp_fetching_data.pg-sp-container {
+  min-height: 45%;
+  bottom: 10px;
+
+  .pg-sp-content {
+    position: absolute;
+    width: 100%;
+  }
+}
+
+.ddl-copy {
+  z-index: 10;
+  position: absolute;
+  right: 1px;
+  top: 1px;
+}
+
+#schema-diff-grid .pg-panel-message {
+  font-size: 0.875rem;
+}
+
+
+#schema-diff-ddl-comp .sql_field_layout {
+  overflow: auto !important;
+  height: 100%;
+}
+
+#schema-diff-ddl-comp .source_ddl, #schema-diff-ddl-comp .target_ddl, #schema-diff-ddl-comp .diff_ddl {
+  height: 300px;
+  overflow: hidden;
+}
+
+.target-buttons {
+  flex-wrap: wrap;
+  max-width: 40% !important;
+}
diff --git a/web/pgadmin/tools/schema_diff/static/img/compare-white.svg b/web/pgadmin/tools/schema_diff/static/img/compare-white.svg
new file mode 100644
index 000000000..47b95be03
--- /dev/null
+++ b/web/pgadmin/tools/schema_diff/static/img/compare-white.svg
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 23.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Слой_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 26 26" style="enable-background:new 0 0 26 26;" xml:space="preserve">
+<style type="text/css">
+	.st0{fill:#FFFFFF;}
+</style>
+<path class="st0" d="M21.5,2h-9c-1.1,0-2,0.9-2,2v3h-6c-1.1,0-2,0.9-2,2v13c0,1.1,0.9,2,2,2h8c1.1,0,2-0.9,2-2v-3h7c1.1,0,2-0.9,2-2
+	V4C23.5,2.9,22.6,2,21.5,2z M12.5,14.8H8.9l1-1c0.1-0.1,0.1-0.2,0.1-0.3s0-0.2-0.1-0.3l-0.3-0.3c-0.1-0.1-0.2-0.1-0.3-0.1
+	c-0.1,0-0.2,0-0.3,0.1l-2.3,2.3c-0.1,0.1-0.1,0.2-0.1,0.3c0,0.1,0,0.2,0.1,0.3L9,18.1c0.1,0.1,0.2,0.1,0.3,0.1c0.1,0,0.2,0,0.3-0.1
+	l0.3-0.3c0.1-0.1,0.1-0.2,0.1-0.3c0-0.1,0-0.2-0.1-0.3l-1-1h3.6l0,5.8h-8V9h8L12.5,14.8z M21.5,9.8h-3.6l1-1
+	c0.1-0.1,0.1-0.2,0.1-0.3s0-0.2-0.1-0.3l-0.3-0.3c-0.1-0.1-0.2-0.1-0.3-0.1c-0.1,0-0.2,0-0.3,0.1l-2.3,2.3c-0.1,0.1-0.1,0.2-0.1,0.3
+	c0,0.1,0,0.2,0.1,0.3l2.3,2.3c0.1,0.1,0.2,0.1,0.3,0.1c0.1,0,0.2,0,0.3-0.1l0.3-0.3c0.1-0.1,0.1-0.2,0.1-0.3c0-0.1,0-0.2-0.1-0.3
+	l-1-1h3.6l0,5.8h-7V9c0-1.1-0.9-2-2-2V4h9L21.5,9.8z"/>
+</svg>
diff --git a/web/pgadmin/tools/schema_diff/static/img/compare.svg b/web/pgadmin/tools/schema_diff/static/img/compare.svg
new file mode 100644
index 000000000..1366f50a5
--- /dev/null
+++ b/web/pgadmin/tools/schema_diff/static/img/compare.svg
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 23.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Слой_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 26 26" style="enable-background:new 0 0 26 26;" xml:space="preserve">
+<style type="text/css">
+	.st0{fill:#222222;}
+</style>
+<path class="st0" d="M21.5,2h-9c-1.1,0-2,0.9-2,2v3h-6c-1.1,0-2,0.9-2,2v13c0,1.1,0.9,2,2,2h8c1.1,0,2-0.9,2-2v-3h7c1.1,0,2-0.9,2-2
+	V4C23.5,2.9,22.6,2,21.5,2z M12.5,14.8H8.9l1-1c0.1-0.1,0.1-0.2,0.1-0.3s0-0.2-0.1-0.3l-0.3-0.3c-0.1-0.1-0.2-0.1-0.3-0.1
+	c-0.1,0-0.2,0-0.3,0.1l-2.3,2.3c-0.1,0.1-0.1,0.2-0.1,0.3c0,0.1,0,0.2,0.1,0.3L9,18.1c0.1,0.1,0.2,0.1,0.3,0.1c0.1,0,0.2,0,0.3-0.1
+	l0.3-0.3c0.1-0.1,0.1-0.2,0.1-0.3c0-0.1,0-0.2-0.1-0.3l-1-1h3.6l0,5.8h-8V9h8L12.5,14.8z M21.5,9.8h-3.6l1-1
+	c0.1-0.1,0.1-0.2,0.1-0.3s0-0.2-0.1-0.3l-0.3-0.3c-0.1-0.1-0.2-0.1-0.3-0.1c-0.1,0-0.2,0-0.3,0.1l-2.3,2.3c-0.1,0.1-0.1,0.2-0.1,0.3
+	c0,0.1,0,0.2,0.1,0.3l2.3,2.3c0.1,0.1,0.2,0.1,0.3,0.1c0.1,0,0.2,0,0.3-0.1l0.3-0.3c0.1-0.1,0.1-0.2,0.1-0.3c0-0.1,0-0.2-0.1-0.3
+	l-1-1h3.6l0,5.8h-7V9c0-1.1-0.9-2-2-2V4h9L21.5,9.8z"/>
+</svg>
diff --git a/web/pgadmin/tools/schema_diff/static/img/script.svg b/web/pgadmin/tools/schema_diff/static/img/script.svg
new file mode 100644
index 000000000..488b911c7
--- /dev/null
+++ b/web/pgadmin/tools/schema_diff/static/img/script.svg
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 23.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve">
+<style type="text/css">
+	.st0{fill:#222222;}
+</style>
+<g>
+	<path class="st0" d="M40,35V11c0-3.9-3.1-7-7-7H7c-3.9,0-7,3.1-7,7c0,3.1,2.1,5.8,5,6.7V39c0,3.9,3.1,7,7,7h31c3.9,0,7-3.1,7-7v-4
+		H40z M43,42c-0.8,0-1.8-1.4-2.5-3h5C44.9,40.5,43.8,42,43,42z M7,8h19.6C26.2,8.9,26,9.9,26,11c0,1,0.2,2,0.7,3H7c-1.7,0-3-1.3-3-3
+		S5.3,8,7,8z M36.7,42H12c-1.7,0-3-1.3-3-3V18h25v-4h-1c-1.7,0-3-1.3-3-3s1.3-3,3-3s3,1.3,3,3v28C36,40,36.2,41,36.7,42z"/>
+	<rect x="13" y="21" class="st0" width="4" height="4"/>
+	<rect x="19" y="21" class="st0" width="13" height="4"/>
+	<rect x="13" y="28" class="st0" width="4" height="4"/>
+	<rect x="19" y="28" class="st0" width="13" height="4"/>
+	<rect x="13" y="35" class="st0" width="4" height="4"/>
+	<rect x="19" y="35" class="st0" width="13" height="4"/>
+</g>
+</svg>
diff --git a/web/pgadmin/tools/schema_diff/static/js/schema_diff.backform.js b/web/pgadmin/tools/schema_diff/static/js/schema_diff.backform.js
new file mode 100644
index 000000000..ad23c4981
--- /dev/null
+++ b/web/pgadmin/tools/schema_diff/static/js/schema_diff.backform.js
@@ -0,0 +1,500 @@
+/////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2019, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+//////////////////////////////////////////////////////////////
+
+import $ from 'jquery';
+import Backbone from 'backbone';
+import Backform from 'pgadmin.backform';
+import gettext from 'sources/gettext';
+import clipboard from 'sources/selection/clipboard';
+
+var formatNode = function (opt) {
+  if (!opt.id) {
+    return opt.text;
+  }
+
+  var optimage = $(opt.element).data('image');
+
+  if (!optimage) {
+    return opt.text;
+  } else {
+    return $('<span></span>').append(
+      $('<span></span>', {
+        class: 'wcTabIcon ' + optimage,
+      })
+    ).append($('<span></span>').text(opt.text));
+  }
+};
+
+let SchemaDiffSqlControl =
+  Backform.SqlFieldControl.extend({
+    defaults: {
+      label: '',
+      extraClasses: [], // Add default control height
+      helpMessage: null,
+      maxlength: 4096,
+      rows: undefined,
+      copyRequired: false,
+    },
+
+    template: _.template([
+      '<% if (copyRequired) { %><button class="btn btn-secondary ddl-copy d-none">Copy</button> <% } %>',
+      '<div class="pgadmin-controls pg-el-9 pg-el-12 sql_field_layout <%=extraClasses.join(\' \')%>">',
+      '  <textarea ',
+      '    class="<%=Backform.controlClassName%> " name="<%=name%>"',
+      '    maxlength="<%=maxlength%>" placeholder="<%-placeholder%>" <%=disabled ? "disabled" : ""%>',
+      '    rows=<%=rows%>',
+      '    <%=required ? "required" : ""%>><%-value%></textarea>',
+      '  <% if (helpMessage && helpMessage.length) { %>',
+      '    <span class="<%=Backform.helpMessageClassName%>"><%=helpMessage%></span>',
+      '  <% } %>',
+      '</div>',
+    ].join('\n')),
+    initialize: function() {
+      Backform.TextareaControl.prototype.initialize.apply(this, arguments);
+      this.sqlCtrl = null;
+
+      _.bindAll(this, 'onFocus', 'onBlur', 'refreshTextArea', 'copyData',);
+    },
+    render: function() {
+      let obj = Backform.SqlFieldControl.prototype.render.apply(this, arguments);
+      if(this.$el.find('.ddl-copy')) this.$el.find('.ddl-copy').on('click', this.copyData);
+      return obj;
+    },
+    copyData() {
+      event.stopPropagation();
+      clipboard.copyTextToClipboard(this.model.get('diff_ddl'));
+      return false;
+    },
+    onFocus: function() {
+      let $ctrl = this.$el.find('.pgadmin-controls').first(),
+        $copy = this.$el.find('.ddl-copy');
+      if (!$ctrl.hasClass('focused')) $ctrl.addClass('focused');
+      if ($copy.hasClass('d-none')) $copy.removeClass('d-none');
+
+    },
+    onBlur: function() {
+      let $copy = this.$el.find('.ddl-copy');
+      if (!$(event.relatedTarget).hasClass('ddl-copy')) {
+        if (!$copy.hasClass('d-none')) $copy.addClass('d-none');
+        this.$el.find('.pgadmin-controls').first().removeClass('focused');
+      }
+    },
+
+  });
+
+let SchemaDiffSelect2Control =
+  Backform.Select2Control.extend({
+    defaults: _.extend(Backform.Select2Control.prototype.defaults, {
+      url: undefined,
+      transform: undefined,
+      url_with_id: false,
+      select2: {
+        allowClear: true,
+        placeholder: gettext('Select an item...'),
+        width: 'style',
+        templateResult: formatNode,
+        templateSelection: formatNode,
+      },
+      controlsClassName: 'pgadmin-controls pg-el-sm-11 pg-el-12',
+    }),
+    className: function() {
+      return 'pgadmin-controls pg-el-sm-4';
+    },
+    events: {
+      'focus select': 'clearInvalid',
+      'keydown :input': 'processTab',
+      'select2:select': 'onSelect',
+      'select2:selecting': 'beforeSelect',
+      'select2:clear': 'onChange',
+    },
+    template: _.template([
+      '<% if(label == false) {} else {%>',
+      '  <label class="<%=Backform.controlLabelClassName%>"><%=label%></label>',
+      '<% }%>',
+      '<div class="<%=controlsClassName%>">',
+      ' <select class="<%=Backform.controlClassName%> <%=extraClasses.join(\' \')%>"',
+      '  name="<%=name%>" value="<%-value%>" <%=disabled ? "disabled" : ""%>',
+      '  <%=required ? "required" : ""%><%= select2.multiple ? " multiple>" : ">" %>',
+      '  <%=select2.first_empty ? " <option></option>" : ""%>',
+      '  <% for (var i=0; i < options.length; i++) {%>',
+      '   <% var option = options[i]; %>',
+      '   <option ',
+      '    <% if (option.image) { %> data-image=<%=option.image%> <%}%>',
+      '    <% if (option.connected) { %> data-connected=connected <%}%>',
+      '    value=<%- formatter.fromRaw(option.value) %>',
+      '    <% if (option.selected) {%>selected="selected"<%} else {%>',
+      '    <% if (!select2.multiple && option.value === rawValue) {%>selected="selected"<%}%>',
+      '    <% if (select2.multiple && rawValue && rawValue.indexOf(option.value) != -1){%>selected="selected" data-index="rawValue.indexOf(option.value)"<%}%>',
+      '    <%}%>',
+      '    <%= disabled ? "disabled" : ""%>><%-option.label%></option>',
+      '  <%}%>',
+      ' </select>',
+      ' <% if (helpMessage && helpMessage.length) { %>',
+      ' <span class="<%=Backform.helpMessageClassName%>"><%=helpMessage%></span>',
+      ' <% } %>',
+      '</div>',
+    ].join('\n')),
+    beforeSelect: function() {
+      var selVal = arguments[0].params.args.data.id;
+
+      if(this.field.get('connect') && this.$el.find('option[value="'+selVal+'"]').attr('data-connected') !== 'connected') {
+        this.field.get('connect').apply(this, [selVal, this.changeIcon.bind(this)]);
+      } else {
+        $(this.$sel).trigger('change');
+        setTimeout(function(){ this.onChange.apply(this); }.bind(this), 200);
+      }
+    },
+    changeIcon: function(data) {
+      let span = this.$el.find('.select2-selection .select2-selection__rendered span.wcTabIcon'),
+        selSpan = this.$el.find('option:selected');
+
+      if (span.hasClass('icon-server-not-connected')) {
+        let icon = (data.icon) ? data.icon : 'icon-pg';
+        span.removeClass('icon-server-not-connected');
+        span.addClass(icon);
+        span.attr('data-connected', 'connected');
+
+        selSpan.data().image = icon;
+        selSpan.attr('data-connected', 'connected');
+
+        this.onChange.apply(this);
+      }
+      else if (span.hasClass('icon-database-not-connected')) {
+        let icon = (data.icon) ? data.icon : 'pg-icon-database';
+
+        span.removeClass('icon-database-not-connected');
+        span.addClass(icon);
+        span.attr('data-connected', 'connected');
+
+        selSpan.removeClass('icon-database-not-connected');
+        selSpan.data().image = icon;
+        selSpan.attr('data-connected', 'connected');
+
+        this.onChange.apply(this);
+      }
+    },
+    onChange: function() {
+      var model = this.model,
+        attrArr = this.field.get('name').split('.'),
+        name = attrArr.shift(),
+        path = attrArr.join('.'),
+        value = this.getValueFromDOM(),
+        changes = {},
+        that = this;
+
+      if (this.model.errorModel instanceof Backbone.Model) {
+        if (_.isEmpty(path)) {
+          this.model.errorModel.unset(name);
+        } else {
+          var nestedError = this.model.errorModel.get(name);
+          if (nestedError) {
+            this.keyPathSetter(nestedError, path, null);
+            this.model.errorModel.set(name, nestedError);
+          }
+        }
+      }
+
+      changes[name] = _.isEmpty(path) ? value : _.clone(model.get(name)) || {};
+
+      if (!_.isEmpty(path)) that.keyPathSetter(changes[name], path, value);
+      that.stopListening(that.model, 'change:' + name, that.render);
+      model.set(changes);
+      that.listenTo(that.model, 'change:' + name, that.render);
+
+    },
+    render: function() {
+      /*
+       * Initialization from the original control.
+       */
+      this.fetchData();
+      return Backform.Select2Control.prototype.render.apply(this, arguments);
+
+    },
+    fetchData: function() {
+      /*
+       * We're about to fetch the options required for this control.
+       */
+      var self = this,
+        url = self.field.get('url'),
+        m = self.model;
+
+      url = _.isFunction(url) ? url.apply(m) : url;
+
+      if (url && self.field.get('deps')) {
+        url = url.replace('sid', m.get(self.field.get('deps')[0]));
+      }
+
+      // Hmm - we found the url option.
+      // That means - we needs to fetch the options from that node.
+      if (url) {
+        var data;
+
+        m.trigger('pgadmin:view:fetching', m, self.field);
+        $.ajax({
+          async: false,
+          url: url,
+        })
+          .done(function(res) {
+          /*
+           * We will cache this data for short period of time for avoiding
+           * same calls.
+           */
+            data = res.data;
+          })
+          .fail(function() {
+            m.trigger('pgadmin:view:fetch:error', m, self.field);
+          });
+
+        m.trigger('pgadmin:view:fetched', m, self.field);
+        // To fetch only options from cache, we do not need time from 'at'
+        // attribute but only options.
+        //
+
+        /*
+         * Transform the data
+         */
+        var transform = this.field.get('transform') || self.defaults.transform;
+        if (transform && _.isFunction(transform)) {
+          // We will transform the data later, when rendering.
+          // It will allow us to generate different data based on the
+          // dependencies.
+          self.field.set('options', transform.bind(self, data));
+        } else {
+          self.field.set('options', data);
+        }
+      }
+    },
+  });
+
+
+let SchemaDiffHeaderView = Backform.Form.extend({
+  label: '',
+  className: function() {
+    return 'pg-el-sm-12 pg-el-md-12 pg-el-lg-12 pg-el-12';
+  },
+  tabPanelClassName: function() {
+    return Backform.tabClassName;
+  },
+  tabIndex: 0,
+  initialize: function(opts) {
+    this.label = opts.label;
+    Backform.Form.prototype.initialize.apply(this, arguments);
+  },
+  template: _.template(`
+    <div class="row pgadmin-control-group">
+      <div class="control-label">Select Source</div>
+      <div class="col-6 source row"></div>
+    </div>
+    <div class="row pgadmin-control-group">
+      <div class="control-label">Select Target</div>
+      <div class="col-6 target row"></div>
+      <div class="col-5 target-buttons">
+          <div class="action-btns d-flex">
+              <button class="btn btn-primary mr-auto"><i class="icon-schema-diff-white"></i>&nbsp;Compare</button>
+              <button id="generate-script" class="btn btn-secondary mr-1" disabled><i class="icon-script"></i>&nbsp;Generate Script</button>
+              <div class="btn-group mr-1" role="group" aria-label="">
+                <button id="btn-filter" type="button" class="btn btn-sm btn-secondary"
+                        title=""
+                        accesskey=""
+                        tabindex="0">
+                    <i class="fa fa-filter sql-icon-lg" aria-hidden="true"></i>&nbsp;Filter
+                </button>
+                <button id="btn-filter-dropdown" type="button" class="btn btn-sm btn-secondary dropdown-toggle dropdown-toggle-split"
+                        data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"
+                        title=""
+                        accesskey=""
+                        tabindex="0">
+                </button>` +
+      [
+        '<ul class="dropdown-menu filter">',
+        '<li>',
+        '<a class="dropdown-item" id="btn-identical" href="#" tabindex="0">',
+        '<i class="identical fa fa-check" aria-hidden="true"></i>',
+        '<span> ' + gettext('Identical') + ' </span>',
+        '</a>',
+        '</li>',
+        '<li>',
+        '<a class="dropdown-item" id="btn-differentt" href="#" tabindex="0">',
+        '<i class="different fa fa-check" aria-hidden="true"></i>',
+        '<span> ' + gettext('Different') + ' </span>',
+        '</a>',
+        '</li>',
+        '<li>',
+        '<a class="dropdown-item" id="btn-source-only" href="#" tabindex="0">',
+        '<i class="source-only fa fa-check" aria-hidden="true"></i>',
+        '<span> ' + gettext('Source Only') + ' </span>',
+        '</a>',
+        '</li>',
+        '<li>',
+        '<a class="dropdown-item" id="btn-target-only" href="#" tabindex="0">',
+        '<i class="target-only fa fa-check" aria-hidden="true"></i>',
+        '<span> ' + gettext('Target Only') + ' </span>',
+        '</a>',
+        '</li>',
+        '</ul>',
+        '</div>',
+        '</div>',
+        '</div>',
+        '</div>',
+      ].join('\n')
+  ),
+  render: function() {
+    this.cleanup();
+
+    var controls = this.controls,
+      m = this.model,
+      self = this,
+      idx = (this.tabIndex * 100);
+
+    this.$el.empty();
+
+    $(this.template()).appendTo(this.$el);
+
+    this.fields.each(function(f) {
+      var cntr = new(f.get('control'))({
+        field: f,
+        model: m,
+        dialog: self,
+        tabIndex: idx,
+      });
+
+      if (f.get('group') && f.get('group') == 'source') {
+        self.$el.find('.source').append(cntr.render().$el);
+      }
+      else {
+        self.$el.find('.target').append(cntr.render().$el);
+      }
+
+      controls.push(cntr);
+    });
+
+    return this;
+  },
+  remove: function(opts) {
+    if (opts && opts.data) {
+      if (this.model) {
+        if (this.model.reset) {
+          this.model.reset({
+            validate: false,
+            silent: true,
+            stop: true,
+          });
+        }
+        this.model.clear({
+          validate: false,
+          silent: true,
+          stop: true,
+        });
+        delete(this.model);
+      }
+      if (this.errorModel) {
+        this.errorModel.clear({
+          validate: false,
+          silent: true,
+          stop: true,
+        });
+        delete(this.errorModel);
+      }
+    }
+    this.cleanup();
+    Backform.Form.prototype.remove.apply(this, arguments);
+  },
+});
+
+let SchemaDiffFooterView = Backform.Form.extend({
+  className: function() {
+    return 'set-group pg-el-12';
+  },
+  tabPanelClassName: function() {
+    return Backform.tabClassName;
+  },
+  legendClass: 'badge',
+  contentClass: Backform.accordianContentClassName,
+  template: {
+    'content': _.template(`
+       <div class="pg-el-sm-12 row <%=contentClass%>">
+                  <div class="pg-el-sm-4 ddl-source">Source</div>
+                  <div class="pg-el-sm-4 ddl-target">Target</div>
+                  <div class="pg-el-sm-4 ddl-diff">Difference
+                  </div>
+              </div>
+      </div>
+    `),
+  },
+  initialize: function(opts) {
+    this.label = opts.label;
+    Backform.Form.prototype.initialize.apply(this, arguments);
+  },
+  render: function() {
+    this.cleanup();
+
+    let m = this.model,
+      $el = this.$el,
+      tmpl = this.template,
+      controls = this.controls,
+      data = {
+        'className': _.result(this, 'className'),
+        'legendClass': _.result(this, 'legendClass'),
+        'contentClass': _.result(this, 'contentClass'),
+        'collapse': _.result(this, 'collapse'),
+      },
+      idx = (this.tabIndex * 100);
+
+    this.$el.empty();
+
+    let el = $((tmpl['content'])(data)).appendTo($el);
+
+    this.fields.each(function(f) {
+      let cntr = new(f.get('control'))({
+        field: f,
+        model: m,
+        dialog: self,
+        tabIndex: idx,
+        name: f.get('name'),
+      });
+
+      if (f.get('group') && f.get('group') == 'ddl-source') {
+        el.find('.ddl-source').append(cntr.render().$el);
+      }
+      else if (f.get('group') && f.get('group') == 'ddl-target') {
+        el.find('.ddl-target').append(cntr.render().$el);
+      }
+      else {
+        el.find('.ddl-diff').append(cntr.render().$el);
+      }
+      controls.push(cntr);
+    });
+
+    let $diff_sc = this.$el.find('.source_ddl'),
+      $diff_tr = this.$el.find('.target_ddl'),
+      $diff = this.$el.find('.diff_ddl'),
+      footer_height = this.$el.parent().height() - 50;
+    $diff_sc.height(footer_height);
+    $diff_sc.css({
+      'height': footer_height + 'px',
+    });
+    $diff_tr.height(footer_height);
+    $diff_tr.css({
+      'height': footer_height + 'px',
+    });
+    $diff.height(footer_height);
+    $diff.css({
+      'height': footer_height + 'px',
+    });
+
+
+    return this;
+  },
+});
+export {
+  SchemaDiffSelect2Control,
+  SchemaDiffHeaderView,
+  SchemaDiffFooterView,
+  SchemaDiffSqlControl,
+};
diff --git a/web/pgadmin/tools/schema_diff/static/js/schema_diff.js b/web/pgadmin/tools/schema_diff/static/js/schema_diff.js
new file mode 100644
index 000000000..a565019bc
--- /dev/null
+++ b/web/pgadmin/tools/schema_diff/static/js/schema_diff.js
@@ -0,0 +1,145 @@
+/////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2019, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+//////////////////////////////////////////////////////////////
+
+define('pgadmin.schemadiff', [
+  'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
+  'sources/pgadmin', 'sources/csrf', 'pgadmin.browser.node',
+], function(
+  gettext, url_for, $, _, pgAdmin, csrfToken
+) {
+
+  var wcDocker = window.wcDocker,
+    pgBrowser = pgAdmin.Browser;
+  /* Return back, this has been called more than once */
+  if (pgBrowser.SchemaDiff)
+    return pgBrowser.SchemaDiff;
+
+  // Create an Object Restore of pgBrowser class
+  pgBrowser.SchemaDiff = {
+    init: function() {
+      if (this.initialized)
+        return;
+
+      this.initialized = true;
+      csrfToken.setPGCSRFToken(pgAdmin.csrf_token_header, pgAdmin.csrf_token);
+
+
+      // Define the nodes on which the menus to be appear
+      var menus = [{
+        name: 'schema_diff',
+        module: this,
+        applies: ['tools'],
+        callback: 'show_schema_diff_tool',
+        priority: 1,
+        label: gettext('Schema Diff'),
+        enable: true,
+      }];
+
+      pgBrowser.add_menus(menus);
+
+      // Creating a new pgBrowser frame to show the data.
+      var schemaDiffFrameType = new pgBrowser.Frame({
+        name: 'frm_schemadiff',
+        showTitle: true,
+        isCloseable: true,
+        isPrivate: true,
+        url: 'about:blank',
+      });
+
+      let self = this;
+      /* Cache may take time to load for the first time
+       * Keep trying till available
+       */
+      let cacheIntervalId = setInterval(function() {
+        if(pgBrowser.preference_version() > 0) {
+          self.preferences = pgBrowser.get_preferences_for_module('schema_diff');
+          clearInterval(cacheIntervalId);
+        }
+      },0);
+
+      pgBrowser.onPreferencesChange('schema_diff', function() {
+        self.preferences = pgBrowser.get_preferences_for_module('schema_diff');
+      });
+
+      // Load the newly created frame
+      schemaDiffFrameType.load(pgBrowser.docker);
+      return this;
+    },
+    
+    // Callback to draw schema diff for objects
+    show_schema_diff_tool: function() {
+      var self = this,
+        baseUrl = url_for('schema_diff.initialize', null);
+
+      $.ajax({
+        url: baseUrl,
+        method: 'GET',
+        dataType: 'json',
+        contentType: 'application/json',
+      })
+        .done(function(res) {
+          self.trans_id = res.data.schemaDiffTransId;
+          res.data.panel_title = 'Schema Diff'; //TODO: Set the panel title
+          // TODO: Following function is used to test the fetching of the
+          // databases this should be moved to server selection event later.
+          self.launch_schema_diff(res.data);
+        })
+        .fail(function(xhr) {
+          self.raise_error_on_fail(gettext('Schema Diff initialize error') , xhr);
+        });
+    },
+
+    launch_schema_diff: function(data) {
+      var panel_title = data.panel_title,
+        trans_id = data.schemaDiffTransId,
+        panel_tooltip = '';
+
+      var url_params = {
+          'trans_id': trans_id,
+          'editor_title': panel_title,
+        },
+        baseUrl = url_for('schema_diff.panel', url_params);
+
+      if (this.preferences.schema_diff_new_browser_tab) {
+        window.open(baseUrl, '_blank');
+      } else {
+
+        var propertiesPanel = pgBrowser.docker.findPanels('properties'),
+          schemaDiffPanel = pgBrowser.docker.addPanel('frm_schemadiff', wcDocker.DOCK.STACKED, propertiesPanel[0]);
+
+        // Set panel title and icon
+        schemaDiffPanel.title('<span title="'+panel_tooltip+'">'+panel_title+'</span>');
+        schemaDiffPanel.icon('icon-schema-diff');
+        schemaDiffPanel.focus();
+
+        var openSchemaDiffURL = function(j) {
+          // add spinner element
+          $(j).data('embeddedFrame').$container.append(pgBrowser.SchemaDiff.spinner_el);
+          setTimeout(function() {
+            var frameInitialized = $(j).data('frameInitialized');
+            if (frameInitialized) {
+              var frame = $(j).data('embeddedFrame');
+              if (frame) {
+                frame.openURL(baseUrl);
+                frame.$container.find('.pg-sp-container').delay(1000).hide(1);
+              }
+            } else {
+              openSchemaDiffURL(j);
+            }
+          }, 100);
+        };
+
+        openSchemaDiffURL(schemaDiffPanel);
+      }
+
+    },
+  };
+
+  return pgBrowser.SchemaDiff;
+});
diff --git a/web/pgadmin/tools/schema_diff/static/js/schema_diff_hook.js b/web/pgadmin/tools/schema_diff/static/js/schema_diff_hook.js
new file mode 100644
index 000000000..34616cf12
--- /dev/null
+++ b/web/pgadmin/tools/schema_diff/static/js/schema_diff_hook.js
@@ -0,0 +1,42 @@
+/////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2019, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+//////////////////////////////////////////////////////////////
+
+define([
+  'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
+  'alertify', 'sources/pgadmin', 'pgadmin.browser',
+  'backbone', 'pgadmin.backgrid', 'codemirror', 'pgadmin.backform',
+  'pgadmin.tools.schema_diff_ui','wcdocker', 'pgadmin.browser.frame',
+  'pgadmin.datagrid',
+], function(
+  gettext, url_for, $, _, Alertify, pgAdmin, pgBrowser, Backbone, Backgrid,
+  CodeMirror, Backform, SchemaDiffUIModule
+) {
+  var pgTools = pgAdmin.Tools = pgAdmin.Tools || {};
+  var SchemaDiffUI = SchemaDiffUIModule.default;
+
+  /* Return back, this has been called more than once */
+  if (pgTools.SchemaDiffHook)
+    return pgTools.SchemaDiffHook;
+
+  pgTools.SchemaDiffHook = {
+    load: function(trans_id) {
+      window.onbeforeunload = function() {
+        $.ajax({
+          url: url_for('schemadiff.index') + 'close/'+trans_id,
+          method: 'DELETE',
+        });
+      };
+
+      let schemaUi = new SchemaDiffUI($('#schema-diff-container'), trans_id);
+      schemaUi.render();
+    },
+  };
+
+  return pgTools.SchemaDiffHook;
+});
diff --git a/web/pgadmin/tools/schema_diff/static/js/schema_diff_ui.js b/web/pgadmin/tools/schema_diff/static/js/schema_diff_ui.js
new file mode 100644
index 000000000..0e10ec063
--- /dev/null
+++ b/web/pgadmin/tools/schema_diff/static/js/schema_diff_ui.js
@@ -0,0 +1,836 @@
+/////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2019, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+//////////////////////////////////////////////////////////////
+
+import url_for from 'sources/url_for';
+import $ from 'jquery';
+import gettext from 'sources/gettext';
+import Alertify from 'pgadmin.alertifyjs';
+import Backbone from 'backbone';
+import Slick from 'sources/../bundle/slickgrid';
+import pgAdmin from 'sources/pgadmin';
+import {setPGCSRFToken} from 'sources/csrf';
+import {generateScript} from 'tools/datagrid/static/js/show_query_tool';
+import 'pgadmin.sqleditor';
+
+import {SchemaDiffSelect2Control, SchemaDiffHeaderView,
+  SchemaDiffFooterView, SchemaDiffSqlControl} from './schema_diff.backform';
+
+var wcDocker = window.wcDocker;
+
+export default class SchemaDiffUI {
+  constructor(container, trans_id) {
+    var self = this;
+    this.$container = container;
+    this.header = null;
+    this.trans_id = trans_id;
+    this.filters = ['Identical', 'Different', 'Source Only', 'Target Only'];
+    this.sel_filters = ['Identical', 'Different', 'Source Only', 'Target Only'];
+    this.dataView = null;
+    this.grid = null,
+    this.selection = {};
+
+    this.model = new Backbone.Model({
+      source_sid: undefined,
+      source_did: undefined,
+      source_scid: undefined,
+      target_sid: undefined,
+      target_did: undefined,
+      target_scid: undefined,
+      source_ddl: undefined,
+      target_ddl: undefined,
+      diff_ddl: undefined,
+    });
+
+    setPGCSRFToken(pgAdmin.csrf_token_header, pgAdmin.csrf_token);
+
+    this.docker = new wcDocker(
+      this.$container, {
+        allowContextMenu: false,
+        allowCollapse: false,
+        loadingClass: 'pg-sp-icon',
+        themePath: url_for('static', {
+          'filename': 'css',
+        }),
+        theme: 'webcabin.overrides.css',
+      }
+    );
+
+    this.header_panel = new pgAdmin.Browser.Panel({
+      name: 'schema_diff_header_panel',
+      showTitle: false,
+      isCloseable: false,
+      isPrivate: true,
+      content: '<div id="schema-diff-header" class="pg-el-container" el="sm"></div><div id="schema-diff-grid" class="pg-el-container" el="sm"></div>',
+      elContainer: true,
+    });
+
+    this.footer_panel = new pgAdmin.Browser.Panel({
+      name: 'schema_diff_footer_panel',
+      title: gettext('DDL Comparison'),
+      isCloseable: false,
+      isPrivate: true,
+      height: '60',
+      content: '<div id="schema-diff-ddl-comp" class="pg-el-container" el="sm"></div>',
+    });
+
+    this.header_panel.load(this.docker);
+    this.footer_panel.load(this.docker);
+
+
+    this.panel_obj = this.docker.addPanel('schema_diff_header_panel', wcDocker.DOCK.TOP, {w:'95%', h:'50%'});
+    this.footer_panel_obj = this.docker.addPanel('schema_diff_footer_panel', wcDocker.DOCK.BOTTOM, this.panel_obj, {w:'95%', h:'50%'});
+
+    self.footer_panel_obj.on(wcDocker.EVENT.VISIBILITY_CHANGED, function() {
+      setTimeout(function() {
+        this.resize_grid();
+      }.bind(self), 200);
+    });
+
+    self.footer_panel_obj.on(wcDocker.EVENT.RESIZE_ENDED, function() {
+      setTimeout(function() {
+        this.resize_panels();
+      }.bind(self), 200);
+    });
+
+  }
+
+
+  raise_error_on_fail(alert_title, xhr) {
+    try {
+      var err = JSON.parse(xhr.responseText);
+      Alertify.alert(alert_title, err.errormsg);
+    } catch (e) {
+      Alertify.alert(alert_title, e.statusText);
+    }
+  }
+
+  resize_panels() {
+    let $src_ddl = $('#schema-diff-ddl-comp .source_ddl'),
+      $tar_ddl = $('#schema-diff-ddl-comp .target_ddl'),
+      $diff_ddl = $('#schema-diff-ddl-comp .diff_ddl'),
+      footer_height = $('#schema-diff-ddl-comp').height() - 50;
+
+    $src_ddl.height(footer_height);
+    $src_ddl.css({
+      'height': footer_height + 'px',
+    });
+    $tar_ddl.height(footer_height);
+    $tar_ddl.css({
+      'height': footer_height + 'px',
+    });
+    $diff_ddl.height(footer_height);
+    $diff_ddl.css({
+      'height': footer_height + 'px',
+    });
+
+    this.resize_grid();
+  }
+
+  compare_schemas() {
+    var self = this,
+      url_params = self.model.toJSON();
+
+    if (url_params['source_sid'] == '' || _.isUndefined(url_params['source_sid']) ||
+      url_params['source_did'] == '' || _.isUndefined(url_params['source_did']) ||
+       url_params['source_scid'] == '' || _.isUndefined(url_params['source_scid']) ||
+       url_params['target_sid'] == '' || _.isUndefined(url_params['target_sid']) ||
+       url_params['target_did'] == '' || _.isUndefined(url_params['target_did']) ||
+       url_params['target_scid'] == '' || _.isUndefined(url_params['target_scid'])
+    ) {
+      Alertify.alert(gettext('Selection Error'), gettext('Please select source and target.'));
+      return false;
+    }
+
+    this.selection = JSON.parse(JSON.stringify(url_params));
+
+    url_params['trans_id'] = self.trans_id;
+
+    _.each(url_params, function(key, val) {
+      url_params[key] = parseInt(val, 10);
+    });
+
+    var baseUrl = url_for('schema_diff.compare', url_params);
+
+    self.model.set({
+      'source_ddl': undefined,
+      'target_ddl': undefined,
+      'diff_ddl': undefined,
+    });
+
+    self.render_grid([]);
+    self.footer.render();
+    self.startDiffPoller();
+
+    return $.ajax({
+      url: baseUrl,
+      method: 'GET',
+      dataType: 'json',
+      contentType: 'application/json',
+    })
+      .done(function (res) {
+        self.stopDiffPoller();
+        self.render_grid(res.data);
+      })
+      .fail(function (xhr) {
+        self.raise_error_on_fail(gettext('Schema compare error'), xhr);
+        self.stopDiffPoller();
+      });
+  }
+
+  generate_script() {
+    var self = this,
+      baseServerUrl = url_for('schema_diff.get_server', {'sid': self.selection['target_sid'],
+        'did': self.selection['target_did']}),
+      sel_rows = self.grid ? self.grid.getSelectedRows() : [],
+      sel_rows_data = [],
+      url_params = self.selection,
+      generated_script = undefined,
+      open_query_tool;
+
+    _.each(url_params, function(key, val) {
+      url_params[key] = parseInt(val, 10);
+    });
+
+    $('#diff_fetching_data').removeClass('d-none');
+    $('#diff_fetching_data').find('.schema-diff-busy-text').text('Generating script...');
+
+
+    open_query_tool = function get_server_details() {
+      $.ajax({
+        url: baseServerUrl,
+        method: 'GET',
+        dataType: 'json',
+        contentType: 'application/json',
+      })
+        .done(function (res) {
+          let data = res.data;
+          let server_data = {};
+          if (data) {
+            server_data['sgid'] = data.gid;
+            server_data['sid'] = data.sid;
+            server_data['stype'] = data.type;
+            server_data['server'] = data.name;
+            server_data['user'] = data.user;
+            server_data['did'] = self.model.get('target_did');
+            server_data['database'] = data.database;
+
+            if (_.isUndefined(generated_script))
+              generated_script = 'BEGIN;' + '\n' + self.model.get('diff_ddl') + '\n' + 'END;';
+
+            let preferences = (window.opener !== null) ? window.opener.pgAdmin.Browser.get_preferences_for_module('schema_diff') : window.top.pgAdmin.Browser.get_preferences_for_module('schema_diff');
+            if (preferences.schema_diff_new_browser_tab) {
+              window.opener.pgAdmin.ddl_diff = generated_script;
+              generateScript(server_data, window.opener.pgAdmin.DataGrid);
+            } else {
+              window.top.pgAdmin.ddl_diff = generated_script;
+              generateScript(server_data, window.top.pgAdmin.DataGrid);
+            }
+          }
+
+          $('#diff_fetching_data').find('.schema-diff-busy-text').text('');
+          $('#diff_fetching_data').addClass('d-none');
+
+        })
+        .fail(function (xhr) {
+          self.raise_error_on_fail(gettext('Generate script error'), xhr);
+          $('#diff_fetching_data').find('.schema-diff-busy-text').text('');
+          $('#diff_fetching_data').addClass('d-none');
+        });
+    };
+
+    if (sel_rows.length > 0) {
+      for (var row = 0; row < sel_rows.length; row++) {
+        let data = self.grid.getData().getItem(sel_rows[row]);
+
+        if (data.type) {
+          let tmp_data = {
+            'node_type': data.type,
+            'source_oid': parseInt(data.oid, 10),
+            'target_oid': parseInt(data.oid, 10),
+            'comp_status': data.status,
+          };
+
+          if(data.status && (data.status.toLowerCase() == 'different' || data.status.toLowerCase() == 'identical')) {
+            tmp_data['target_oid'] = data.target_oid;
+          }
+          sel_rows_data.push(tmp_data);
+        }
+      }
+
+      url_params['sel_rows'] = sel_rows_data;
+
+      let baseUrl = url_for('schema_diff.generate_script', {'trans_id': self.trans_id});
+
+      $.ajax({
+        url: baseUrl,
+        method: 'POST',
+        dataType: 'json',
+        contentType: 'application/json',
+        data: JSON.stringify(url_params),
+      })
+        .done(function (res) {
+          if (res) {
+            generated_script = 'BEGIN;' + '\n' + res.diff_ddl + '\n' + 'END;';
+          }
+          open_query_tool();
+        })
+        .fail(function (xhr) {
+          self.raise_error_on_fail(gettext('Generate script error'), xhr);
+          $('#diff_fetching_data').addClass('d-none');
+        });
+    } else if (!_.isUndefined(self.model.get('diff_ddl'))) {
+      open_query_tool();
+    }
+    return false;
+  }
+
+  render_grid(data) {
+
+    var self = this;
+    var grid;
+
+    if (self.grid) {
+      // Only render the data
+      self.render_grid_data(data);
+      return;
+    }
+    // Checkbox Column
+    var checkboxSelector = new Slick.CheckboxSelectColumn({
+      cssClass: 'slick-cell-checkboxsel',
+      minWidth: 30,
+    });
+
+    // Format Schema object title with appropriate icon
+    var formatColumnTitle = function (row, cell, value, columnDef, dataContext) {
+      let icon = 'icon-' + dataContext.type;
+      return '<i class="ml-5 wcTabIcon '+ icon +'"></i><span>' + value + '</span>';
+    };
+
+    // Grid Columns
+    var grid_width =  (self.grid_width - 47) / 2 ;
+    var columns = [
+      checkboxSelector.getColumnDefinition(),
+      {id: 'title', name: 'Schema Objects', field: 'title', minWidth: grid_width, formatter: formatColumnTitle},
+      {id: 'status', name: 'Comparison Result', field: 'status', minWidth: grid_width},
+      {id: 'label', name: 'Schema Objects', field: 'label',  width: 0, minWidth: 0, maxWidth: 0,
+        cssClass: 'reallyHidden', headerCssClass: 'reallyHidden'},
+      {id: 'type', name: 'Schema Objects', field: 'type',  width: 0, minWidth: 0, maxWidth: 0,
+        cssClass: 'reallyHidden', headerCssClass: 'reallyHidden'},
+      {id: 'id', name: 'id', field: 'id', width: 0, minWidth: 0, maxWidth: 0,
+        cssClass: 'reallyHidden', headerCssClass: 'reallyHidden' },
+
+    ];
+
+    // Grid Options
+    var options = {
+      enableCellNavigation: true,
+      enableColumnReorder: false,
+      enableRowSelection: true,
+    };
+
+    // Grouping by Schema Object
+    self.groupBySchemaObject = function() {
+      self.dataView.setGrouping({
+        getter: 'type',
+        formatter: function (g) {
+          let icon = 'icon-coll-' + g.value;
+          return '<i class="wcTabIcon '+ icon +'"></i><span>' + g.rows[0].label + '</span>';
+        },
+        aggregateCollapsed: true,
+        lazyTotalsCalculation: true,
+      });
+    };
+
+    var groupItemMetadataProvider = new Slick.Data.GroupItemMetadataProvider({ checkboxSelect: true,
+      checkboxSelectPlugin: checkboxSelector });
+
+    // Dataview for grid
+    self.dataView = new Slick.Data.DataView({
+      groupItemMetadataProvider: groupItemMetadataProvider,
+      inlineFilters: false,
+    });
+
+    // Wire up model events to drive the grid
+    self.dataView.onRowCountChanged.subscribe(function () {
+      grid.updateRowCount();
+      grid.render();
+    });
+    self.dataView.onRowsChanged.subscribe(function (e, args) {
+      grid.invalidateRows(args.rows);
+      grid.render();
+    });
+
+    // Change Row css on the basis of item status
+    self.dataView.getItemMetadata = function(row) {
+      var item = self.dataView.getItem(row);
+      if (item.__group) {
+        return groupItemMetadataProvider.getGroupRowMetadata(item);
+      }
+
+      if(item.status === 'Different') {
+        return { cssClasses: 'different' };
+      } else if (item.status === 'Source Only') {
+        return { cssClasses: 'source' };
+      } else if (item.status === 'Target Only') {
+        return { cssClasses: 'target' };
+      }
+
+      return null;
+    };
+
+    // Grid filter
+    self.filter = function (item) {
+      let self = this;
+      if (self.sel_filters.indexOf(item.status) !== -1) return true;
+      return false;
+    };
+
+    let $data_grid = $('#schema-diff-grid');
+    grid = this.grid = new Slick.Grid($data_grid, self.dataView, columns, options);
+    grid.registerPlugin(groupItemMetadataProvider);
+    grid.setSelectionModel(new Slick.RowSelectionModel({selectActiveRow: false}));
+    grid.registerPlugin(checkboxSelector);
+
+    grid.onClick.subscribe(function(e, args) {
+      if (args.row) {
+        data = args.grid.getData().getItem(args.row);
+        if (data.status) this.ddlCompare(data);
+      }
+    }.bind(self));
+
+    grid.onSelectedRowsChanged.subscribe(self.handle_generate_button.bind(self));
+
+    self.model.on('change:diff_ddl', self.handle_generate_button.bind(self));
+
+    $('#schema-diff-grid').on('keyup', function() {
+      if ((event.keyCode == 38 || event.keyCode ==40) && this.grid.getActiveCell().row) {
+        data = this.grid.getData().getItem(this.grid.getActiveCell().row);
+        this.ddlCompare(data);
+      }
+    }.bind(self));
+
+    self.render_grid_data(data);
+  }
+
+
+
+  render_grid_data(data) {
+    var self = this;
+    self.dataView.beginUpdate();
+    self.dataView.setItems(data);
+    self.dataView.setFilter(self.filter.bind(self));
+    self.groupBySchemaObject();
+    self.dataView.endUpdate();
+
+    self.resize_grid();
+  }
+
+  handle_generate_button(){
+    if (this.grid.getSelectedRows().length > 0 || (this.model.get('diff_ddl') != '' && !_.isUndefined(this.model.get('diff_ddl')))) {
+      this.header.$el.find('button#generate-script').removeAttr('disabled');
+    } else {
+      this.header.$el.find('button#generate-script').attr('disabled', true);
+    }
+  }
+
+  resize_grid() {
+    let $data_grid = $('#schema-diff-grid'),
+      grid_height = (this.panel_obj.height() > 0) ? this.panel_obj.height() - 100 : this.grid_height - 100;
+
+    $data_grid.height(grid_height);
+    $data_grid.css({
+      'height': grid_height + 'px',
+    });
+    if (this.grid) this.grid.resizeCanvas();
+  }
+
+  getCompareStatus() {
+    var self = this,
+      url_params = {'trans_id': self.trans_id},
+      baseUrl = url_for('schema_diff.poll', url_params);
+
+    $.ajax({
+      url: baseUrl,
+      method: 'GET',
+      dataType: 'json',
+      contentType: 'application/json',
+    })
+      .done(function (res) {
+        let msg = res.data.compare_msg + res.data.diff_percentage + '% completed';
+        $('#diff_fetching_data').find('.schema-diff-busy-text').text(msg);
+      })
+      .fail(function (xhr) {
+        self.raise_error_on_fail(gettext('Poll error'), xhr);
+        self.stopDiffPoller('fail');
+      });
+  }
+
+  startDiffPoller() {
+    $('#ddl_comp_fetching_data').addClass('d-none');
+    $('#diff_fetching_data').removeClass('d-none');
+    /* Execute once for the first time as setInterval will not do */
+    this.getCompareStatus();
+    this.diff_poller_int_id = setInterval(this.getCompareStatus.bind(this), 1000);
+  }
+
+  stopDiffPoller(status) {
+    clearInterval(this.diff_poller_int_id);
+    // The last polling for comparison
+    if (status !== 'fail') this.getCompareStatus();
+
+    $('#diff_fetching_data').find('.schema-diff-busy-text').text('');
+    $('#diff_fetching_data').addClass('d-none');
+
+  }
+
+  ddlCompare(data) {
+    var self = this,
+      node_type = data.type,
+      source_oid = data.oid,
+      target_oid = data.oid;
+
+    self.model.set({
+      'source_ddl': undefined,
+      'target_ddl': undefined,
+      'diff_ddl': undefined,
+    });
+
+    var url_params = self.selection;
+
+    if(data.status && (data.status.toLowerCase() == 'different' || data.status.toLowerCase() == 'identical')) {
+      target_oid = data.target_oid;
+    }
+
+    url_params['trans_id'] = self.trans_id;
+    url_params['source_oid'] = source_oid;
+    url_params['target_oid'] = target_oid;
+    url_params['comp_status'] = data.status;
+    url_params['node_type'] = node_type;
+
+    _.each(url_params, function(key, val) {
+      url_params[key] = parseInt(val, 10);
+    });
+
+    $('#ddl_comp_fetching_data').removeClass('d-none');
+
+    var baseUrl = url_for('schema_diff.ddl_compare', url_params);
+    self.model.url = baseUrl;
+
+    self.model.fetch({
+      success: function() {
+        self.footer.render();
+        $('#ddl_comp_fetching_data').addClass('d-none');
+      },
+      error: function() {
+        self.footer.render();
+        $('#ddl_comp_fetching_data').addClass('d-none');
+      },
+    });
+  }
+
+  render() {
+    let self = this;
+    let panel = self.docker.findPanels('schema_diff_header_panel')[0];
+
+    var header = panel.$container.find('#schema-diff-header');
+
+    self.header  = new SchemaDiffHeaderView({
+      el: header,
+      model: this.model,
+      fields: [{
+        name: 'source_sid', label: false,
+        control: SchemaDiffSelect2Control,
+        url: url_for('schema_diff.servers'),
+        select2: {
+          allowClear: true,
+          placeholder: gettext('Select server...'),
+        },
+        connect: function() {
+          self.connect_server(arguments[0], arguments[1]);
+        },
+        group: 'source',
+        disabled: function() {
+          return false;
+        },
+      }, {
+        name: 'source_did',
+        group: 'source',
+        deps: ['source_sid'],
+        control: SchemaDiffSelect2Control,
+        url: function() {
+          if (this.get('source_sid'))
+            return url_for('schema_diff.databases', {'sid': this.get('source_sid')});
+          return false;
+        },
+        select2: {
+          allowClear: true,
+          placeholder: gettext('Select database...'),
+        },
+        disabled: function(m) {
+          if (!_.isUndefined(m.get('source_sid')) && !_.isNull(m.get('source_sid')))
+            return false;
+          return true;
+        },
+        connect: function() {
+          self.connect_database(this.model.get('source_sid'), arguments[0], arguments[1]);
+        },
+      }, {
+        name: 'source_scid',
+        control: SchemaDiffSelect2Control,
+        group: 'source',
+        deps: ['source_sid', 'source_did'],
+        url: function() {
+          if (this.get('source_sid') && this.get('source_did'))
+            return url_for('schema_diff.schemas', {'sid': this.get('source_sid'), 'did': this.get('source_did')});
+          return false;
+        },
+        select2: {
+          allowClear: true,
+          placeholder: gettext('Select schema...'),
+        },
+        disabled: function(m) {
+          if (!_.isUndefined(m.get('source_did')) && !_.isNull(m.get('source_did')))
+            return false;
+          return true;
+        },
+      }, {
+        name: 'target_sid', label: false,
+        control: SchemaDiffSelect2Control,
+        group: 'target',
+        url: url_for('schema_diff.servers'),
+        select2: {
+          allowClear: true,
+          placeholder: gettext('Select server...'),
+        },
+        disabled: function() {
+          return false;
+        },
+        connect: function() {
+          self.connect_server(arguments[0], arguments[1]);
+        },
+      }, {
+        name: 'target_did',
+        control: SchemaDiffSelect2Control,
+        group: 'target',
+        deps: ['target_sid'],
+        url: function() {
+          if (this.get('target_sid'))
+            return url_for('schema_diff.databases', {'sid': this.get('target_sid')});
+          return false;
+        },
+        select2: {
+          allowClear: true,
+          placeholder: gettext('Select database...'),
+        },
+        disabled: function(m) {
+          if (!_.isUndefined(m.get('target_sid')) && !_.isNull(m.get('target_sid')))
+            return false;
+          return true;
+        },
+        connect: function() {
+          self.connect_database(this.model.get('target_sid'), arguments[0], arguments[1]);
+        },
+      }, {
+        name: 'target_scid',
+        control: SchemaDiffSelect2Control,
+        group: 'target',
+        deps: ['target_sid', 'target_did'],
+        url: function() {
+          if (this.get('target_sid') && this.get('target_did'))
+            return url_for('schema_diff.schemas', {'sid': this.get('target_sid'), 'did': this.get('target_did')});
+          return false;
+        },
+        select2: {
+          allowClear: true,
+          placeholder: gettext('Select schema...'),
+        },
+        disabled: function(m) {
+          if (!_.isUndefined(m.get('target_did')) && !_.isNull(m.get('target_did')))
+            return false;
+          return true;
+        },
+      }],
+    });
+
+    self.footer  = new SchemaDiffFooterView({
+      model: this.model,
+      fields: [{
+        name: 'source_ddl', label: false,
+        control: SchemaDiffSqlControl,
+        group: 'ddl-source',
+      }, {
+        name: 'target_ddl', label: false,
+        control: SchemaDiffSqlControl,
+        group: 'ddl-target',
+      }, {
+        name: 'diff_ddl', label: false,
+        control: SchemaDiffSqlControl,
+        group: 'ddl-diff', copyRequired: true,
+      }],
+    });
+
+    self.header.render();
+
+    self.header.$el.find('button.btn-primary').on('click', self.compare_schemas.bind(self));
+    self.header.$el.find('button#generate-script').on('click', self.generate_script.bind(self));
+    self.header.$el.find('ul.filter a.dropdown-item').on('click', self.refresh_filters.bind(self));
+
+    let footer_panel = self.docker.findPanels('schema_diff_footer_panel')[0],
+      header_panel = self.docker.findPanels('schema_diff_header_panel')[0];
+
+    footer_panel.$container.find('#schema-diff-ddl-comp').append(self.footer.render().$el);
+    header_panel.$container.find('#schema-diff-grid').append(`<div class='obj_properties container-fluid'>
+    <div class='alert alert-info pg-panel-message'>` + gettext('Select the server, database and schema for the source and target and click <b>Compare</b> to compare them.') + '</div></div>');
+
+    self.grid_width = $('#schema-diff-grid').width();
+    self.grid_height = this.panel_obj.height();
+  }
+
+  refresh_filters(event) {
+    let self = this;
+    _.each(self.filters, function(filter) {
+      let index = self.sel_filters.indexOf(filter);
+      let filter_class = '.' + filter.replace(' ', '-').toLowerCase();
+      if ($(event.currentTarget).find(filter_class).length == 1) {
+        if ($(filter_class).hasClass('visibility-hidden') === true) {
+          $(filter_class).removeClass('visibility-hidden');
+          if (index === -1) self.sel_filters.push(filter);
+        } else {
+          $(filter_class).addClass('visibility-hidden');
+          if(index !== -1 ) delete self.sel_filters[index];
+        }
+      }
+    });
+    // Refresh the grid
+    self.dataView.refresh();
+  }
+
+  connect_database(server_id, db_id, callback) {
+    var url = url_for('schema_diff.connect_database', {'sid': server_id, 'did': db_id});
+    $.post(url)
+      .done(function(res) {
+        if (res.success && res.data) {
+          callback(res.data);
+        }
+      })
+      .fail(function() {
+        // Fail
+      });
+
+  }
+
+  connect_server(server_id, callback) {
+    var  onFailure = function(
+        xhr, status, error, server_id, callback
+      ) {
+        Alertify.pgNotifier('error', xhr, error, function(msg) {
+          setTimeout(function() {
+            Alertify.dlgServerPass(
+              gettext('Connect to Server'),
+              msg,
+              server_id,
+              callback
+            ).resizeTo();
+          }, 100);
+        });
+      },
+      onSuccess = function(res, callback) {
+        if (res && res.data) {
+          // We're not reconnecting
+          callback(res.data);
+        }
+      };
+
+
+    // Ask Password and send it back to the connect server
+    if (!Alertify.dlgServerPass) {
+      Alertify.dialog('dlgServerPass', function factory() {
+        return {
+          main: function(
+            title, message, server_id, success_callback, _onSuccess, _onFailure, _onCancel
+          ) {
+            this.set('title', title);
+            this.message = message;
+            this.server_id = server_id;
+            this.success_callback = success_callback;
+            this.onSuccess = _onSuccess || onSuccess;
+            this.onFailure = _onFailure || onFailure;
+            this.onCancel = _onCancel || onCancel;
+          },
+          setup:function() {
+            return {
+              buttons:[{
+                text: gettext('Cancel'), className: 'btn btn-secondary fa fa-times pg-alertify-button',
+                key: 27,
+              },{
+                text: gettext('OK'), key: 13, className: 'btn btn-primary fa fa-check pg-alertify-button',
+              }],
+              focus: {element: '#password', select: true},
+              options: {
+                modal: 0, resizable: false, maximizable: false, pinnable: false,
+              },
+            };
+          },
+          build:function() {},
+          prepare:function() {
+            this.setContent(this.message);
+          },
+          callback: function(closeEvent) {
+            var _onFailure = this.onFailure,
+              _onSuccess = this.onSuccess,
+              _onCancel = this.onCancel,
+              _success_callback = this.success_callback;
+
+            if (closeEvent.button.text == gettext('OK')) {
+
+              var _url = url_for('schema_diff.connect_server', {'sid': this.server_id});
+
+              $.ajax({
+                type: 'POST',
+                timeout: 30000,
+                url: _url,
+                data: $('#frmPassword').serialize(),
+              })
+                .done(function(res) {
+                  if (res.success == 1) {
+                    return _onSuccess(res, _success_callback);
+                  }
+                })
+                .fail(function(xhr, status, error) {
+                  return _onFailure(
+                    xhr, status, error, this.server_id, _success_callback
+                  );
+                });
+            } else {
+              _onCancel && typeof(_onCancel) == 'function' &&
+                _onCancel();
+            }
+          },
+        };
+      });
+    }
+
+    var onCancel = function() {
+      return false;
+    };
+
+    var url = url_for('schema_diff.connect_server', {'sid': server_id});
+    $.post(url)
+      .done(function(res) {
+        if (res.success == 1) {
+          return onSuccess(res, callback);
+        }
+      })
+      .fail(function(xhr, status, error) {
+        return onFailure(
+          xhr, status, error, server_id, callback
+        );
+      });
+  }
+}
diff --git a/web/pgadmin/tools/schema_diff/static/scss/_schema_diff.scss b/web/pgadmin/tools/schema_diff/static/scss/_schema_diff.scss
new file mode 100644
index 000000000..f41f9f8b0
--- /dev/null
+++ b/web/pgadmin/tools/schema_diff/static/scss/_schema_diff.scss
@@ -0,0 +1,81 @@
+#schema-diff-container {
+  position: absolute;
+  left: 0;
+  right: 0;
+  top: 0;
+  bottom: 0;
+  padding-top: 10px;
+  background-color: $color-gray-light;
+}
+
+#schema-diff-grid .slick-header .slick-header-columns {
+  background: $color-bg;
+  height: 40px;
+  border-bottom: $panel-border;
+}
+
+#schema-diff-grid .slick-header .slick-header-column.ui-state-default {
+  padding: 4px 0 3px 6px;
+  border-bottom: $panel-border;
+  border-right: $panel-border;
+}
+
+.slick-row:hover .slick-cell{
+  border-top: $table-hover-border;
+  border-bottom: $table-hover-border;
+  background-color: $table-hover-bg-color;
+}
+
+#schema-diff-grid .slick-header .slick-header-column.selected {
+  background-color: $color-primary;
+  color: $color-primary-fg;
+}
+.slick-row .slick-cell {
+  border-bottom: $panel-border;
+  border-right: $panel-border;
+  z-index: 0;
+}
+
+#schema-diff-grid {
+  background: none;
+  background-color: $color-gray-light;
+}
+
+#schema-diff-grid .slick-row .slick-cell.l0.r0.selected {
+  background-color: $color-primary;
+  color: $color-primary-fg;
+}
+
+#schema-diff-grid .slick-row > .slick-cell:not(.l0):not(.r0).selected {
+  background-color: $table-hover-bg-color;
+  border-top: $table-hover-border;
+  border-bottom: $table-hover-border;
+}
+
+#schema-diff-grid div.slick-header.ui-state-default {
+  background: $color-bg;
+  border-bottom: none;
+  border-right: none;
+  border-top: none;
+}
+
+#schema-diff-grid .different {
+  background-color: $schemadiff-diff-row-color !important;
+}
+#schema-diff-grid .source {
+  background-color: $schemadiff-source-row-color !important;
+}
+#schema-diff-grid .target {
+  background-color: $schemadiff-target-row-color !important;
+}
+
+#schema-diff-grid .slick-row.active {
+    background-color: $table-bg-selected !important;
+}
+
+#schema-diff-ddl-comp {
+  height: 100%;
+  bottom: 10px;
+  background-color: $color-bg !important;
+  overflow-y: hidden;
+}
diff --git a/web/pgadmin/tools/schema_diff/templates/schema_diff/index.html b/web/pgadmin/tools/schema_diff/templates/schema_diff/index.html
new file mode 100644
index 000000000..641bd86c7
--- /dev/null
+++ b/web/pgadmin/tools/schema_diff/templates/schema_diff/index.html
@@ -0,0 +1,39 @@
+{% extends "base.html" %}
+{% block init_script %}
+try {
+  require(
+    ['sources/generated/schema_diff', 'sources/generated/slickgrid', 'sources/generated/codemirror', 'sources/generated/browser_nodes'],
+    function(pgSchemaDiffHook) {
+      var pgSchemaDiffHook = pgSchemaDiffHook || pgAdmin.Tools.SchemaDiffHook;
+      pgSchemaDiffHook.load({{trans_id}});
+    },
+    function() {
+      console.log(arguments);
+    });
+} catch (err) {
+  console.log(err);
+}
+{% endblock %}
+{% block css_link %}
+<link type="text/css" rel="stylesheet" href="{{ url_for('browser.browser_css')}}"/>
+{% endblock %}
+{% block body %}
+<div id="schema-diff-container">
+    <div id="diff_fetching_data" class="pg-sp-container schema-diff-busy-fetching d-none">
+        <div class="pg-sp-content">
+            <div class="row">
+                <div class="col-12 pg-sp-icon"></div>
+            </div>
+            <div class="row"><div class="col-12 pg-sp-text schema-diff-busy-text"></div></div>
+        </div>
+    </div>
+    <div id="ddl_comp_fetching_data" class="pg-sp-container schema-diff-busy-fetching d-none">
+        <div class="pg-sp-content">
+            <div class="row">
+                <div class="col-12 pg-sp-icon"></div>
+            </div>
+            <div class="row"><div class="col-12 pg-sp-text">{{ _('Comparing objects...') }}</div></div>
+        </div>
+    </div>
+</div>
+{% endblock %}
diff --git a/web/pgadmin/tools/schema_diff/tests/__init__.py b/web/pgadmin/tools/schema_diff/tests/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/web/pgadmin/tools/schema_diff/tests/pg/10_plus/source.sql b/web/pgadmin/tools/schema_diff/tests/pg/10_plus/source.sql
new file mode 100644
index 000000000..99757ceb2
--- /dev/null
+++ b/web/pgadmin/tools/schema_diff/tests/pg/10_plus/source.sql
@@ -0,0 +1,440 @@
+--
+-- PostgreSQL database dump
+--
+
+-- Dumped from database version 10.7
+-- Dumped by pg_dump version 12beta2
+
+-- Started on 2019-11-01 12:54:15 IST
+
+SET statement_timeout = 0;
+SET lock_timeout = 0;
+SET idle_in_transaction_session_timeout = 0;
+SET client_encoding = 'UTF8';
+SET standard_conforming_strings = on;
+SELECT pg_catalog.set_config('search_path', '', false);
+SET check_function_bodies = false;
+SET xmloption = content;
+SET client_min_messages = warning;
+SET row_security = off;
+
+--
+-- TOC entry 17 (class 2615 OID 139770)
+-- Name: source; Type: SCHEMA; Schema: -; Owner: postgres
+--
+
+CREATE SCHEMA source;
+
+
+ALTER SCHEMA source OWNER TO postgres;
+
+SET default_tablespace = '';
+
+
+CREATE EXTENSION btree_gist
+    SCHEMA source;
+
+--
+-- TOC entry 12272 (class 1259 OID 149205)
+-- Name: table_for_partition; Type: TABLE; Schema: source; Owner: postgres
+--
+
+CREATE TABLE source.table_for_partition (
+    col1 bigint NOT NULL
+)
+PARTITION BY RANGE (col1);
+
+
+ALTER TABLE source.table_for_partition OWNER TO postgres;
+
+--
+-- TOC entry 12273 (class 1259 OID 149208)
+-- Name: part1; Type: TABLE; Schema: source; Owner: postgres
+--
+
+CREATE TABLE source.part1 (
+    col1 bigint NOT NULL
+);
+ALTER TABLE ONLY source.table_for_partition ATTACH PARTITION source.part1 FOR VALUES FROM ('1') TO ('23');
+
+
+ALTER TABLE source.part1 OWNER TO postgres;
+
+--
+-- TOC entry 12274 (class 1259 OID 149213)
+-- Name: table_for_partition_1; Type: TABLE; Schema: source; Owner: postgres
+--
+
+CREATE TABLE source.table_for_partition_1 (
+    col1 bigint
+)
+PARTITION BY RANGE (col1);
+
+
+ALTER TABLE source.table_for_partition_1 OWNER TO postgres;
+
+--
+-- TOC entry 12275 (class 1259 OID 149216)
+-- Name: part3; Type: TABLE; Schema: source; Owner: postgres
+--
+
+CREATE TABLE source.part3 (
+    col1 bigint
+);
+ALTER TABLE ONLY source.table_for_partition_1 ATTACH PARTITION source.part3 FOR VALUES FROM ('1') TO ('10');
+
+
+ALTER TABLE source.part3 OWNER TO postgres;
+
+--
+-- TOC entry 12276 (class 1259 OID 149219)
+-- Name: part4; Type: TABLE; Schema: source; Owner: postgres
+--
+
+CREATE TABLE source.part4 (
+    col1 bigint
+);
+ALTER TABLE ONLY source.table_for_partition_1 ATTACH PARTITION source.part4 FOR VALUES FROM ('11') TO ('20');
+
+
+ALTER TABLE source.part4 OWNER TO postgres;
+
+--
+-- TOC entry 12258 (class 1259 OID 148963)
+-- Name: table_for_column; Type: TABLE; Schema: source; Owner: postgres
+--
+
+CREATE TABLE source.table_for_column (
+    col1 bigint NOT NULL,
+    col2 text,
+    col3 text
+);
+
+
+ALTER TABLE source.table_for_column OWNER TO postgres;
+
+--
+-- TOC entry 12256 (class 1259 OID 148895)
+-- Name: table_for_constraints; Type: TABLE; Schema: source; Owner: postgres
+--
+
+CREATE TABLE source.table_for_constraints (
+    col1 integer NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE source.table_for_constraints OWNER TO postgres;
+
+--
+-- TOC entry 61066 (class 0 OID 0)
+-- Dependencies: 12256
+-- Name: TABLE table_for_constraints; Type: COMMENT; Schema: source; Owner: postgres
+--
+
+COMMENT ON TABLE source.table_for_constraints IS 'comments';
+
+
+--
+-- TOC entry 12262 (class 1259 OID 149004)
+-- Name: table_for_identical; Type: TABLE; Schema: source; Owner: postgres
+--
+
+CREATE TABLE source.table_for_identical (
+    col1 integer NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE source.table_for_identical OWNER TO postgres;
+
+--
+-- TOC entry 12260 (class 1259 OID 148977)
+-- Name: table_for_index; Type: TABLE; Schema: source; Owner: postgres
+--
+
+CREATE TABLE source.table_for_index (
+    col1 integer NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE source.table_for_index OWNER TO postgres;
+
+--
+-- TOC entry 12269 (class 1259 OID 149128)
+-- Name: table_for_primary_key; Type: TABLE; Schema: source; Owner: postgres
+--
+
+CREATE TABLE source.table_for_primary_key (
+    col1 integer NOT NULL,
+    col2 text NOT NULL
+);
+
+
+ALTER TABLE source.table_for_primary_key OWNER TO postgres;
+
+--
+-- TOC entry 12264 (class 1259 OID 149024)
+-- Name: table_for_rule; Type: TABLE; Schema: source; Owner: postgres
+--
+
+CREATE TABLE source.table_for_rule (
+    col1 bigint NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE source.table_for_rule OWNER TO postgres;
+
+--
+-- TOC entry 12266 (class 1259 OID 149048)
+-- Name: table_for_trigger; Type: TABLE; Schema: source; Owner: postgres
+--
+
+CREATE TABLE source.table_for_trigger (
+    col1 bigint NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE source.table_for_trigger OWNER TO postgres;
+
+--
+-- TOC entry 56893 (class 2606 OID 148904)
+-- Name: table_for_constraints Exclusion; Type: CONSTRAINT; Schema: source; Owner: postgres
+--
+
+ALTER TABLE ONLY source.table_for_constraints
+    ADD CONSTRAINT "Exclusion" EXCLUDE USING gist (col2 WITH <>) WITH (fillfactor='12') WHERE ((col1 > 1)) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- TOC entry 61067 (class 0 OID 0)
+-- Dependencies: 56893
+-- Name: CONSTRAINT "Exclusion" ON table_for_constraints; Type: COMMENT; Schema: source; Owner: postgres
+--
+
+COMMENT ON CONSTRAINT "Exclusion" ON source.table_for_constraints IS 'comments';
+
+
+--
+-- TOC entry 56891 (class 2606 OID 148911)
+-- Name: table_for_constraints check_con; Type: CHECK CONSTRAINT; Schema: source; Owner: postgres
+--
+
+ALTER TABLE source.table_for_constraints
+    ADD CONSTRAINT check_con CHECK ((col1 > 10)) NOT VALID;
+
+
+--
+-- TOC entry 61068 (class 0 OID 0)
+-- Dependencies: 56891
+-- Name: CONSTRAINT check_con ON table_for_constraints; Type: COMMENT; Schema: source; Owner: postgres
+--
+
+COMMENT ON CONSTRAINT check_con ON source.table_for_constraints IS 'coment';
+
+
+--
+-- TOC entry 56899 (class 2606 OID 148970)
+-- Name: table_for_column table_for_column_pkey; Type: CONSTRAINT; Schema: source; Owner: postgres
+--
+
+ALTER TABLE ONLY source.table_for_column
+    ADD CONSTRAINT table_for_column_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56895 (class 2606 OID 148902)
+-- Name: table_for_constraints table_for_constraints_pkey; Type: CONSTRAINT; Schema: source; Owner: postgres
+--
+
+ALTER TABLE ONLY source.table_for_constraints
+    ADD CONSTRAINT table_for_constraints_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56904 (class 2606 OID 148984)
+-- Name: table_for_index table_for_index_pkey; Type: CONSTRAINT; Schema: source; Owner: postgres
+--
+
+ALTER TABLE ONLY source.table_for_index
+    ADD CONSTRAINT table_for_index_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56913 (class 2606 OID 149135)
+-- Name: table_for_primary_key table_for_primary_key_pkey; Type: CONSTRAINT; Schema: source; Owner: postgres
+--
+
+ALTER TABLE ONLY source.table_for_primary_key
+    ADD CONSTRAINT table_for_primary_key_pkey PRIMARY KEY (col1, col2);
+
+
+--
+-- TOC entry 56909 (class 2606 OID 149031)
+-- Name: table_for_rule table_for_rule_pkey; Type: CONSTRAINT; Schema: source; Owner: postgres
+--
+
+ALTER TABLE ONLY source.table_for_rule
+    ADD CONSTRAINT table_for_rule_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56907 (class 2606 OID 149011)
+-- Name: table_for_identical table_for_table_for_identical_pkey; Type: CONSTRAINT; Schema: source; Owner: postgres
+--
+
+ALTER TABLE ONLY source.table_for_identical
+    ADD CONSTRAINT table_for_table_for_identical_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56911 (class 2606 OID 149055)
+-- Name: table_for_trigger table_for_trigger_pkey; Type: CONSTRAINT; Schema: source; Owner: postgres
+--
+
+ALTER TABLE ONLY source.table_for_trigger
+    ADD CONSTRAINT table_for_trigger_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56897 (class 2606 OID 148913)
+-- Name: table_for_constraints unique; Type: CONSTRAINT; Schema: source; Owner: postgres
+--
+
+ALTER TABLE ONLY source.table_for_constraints
+    ADD CONSTRAINT "unique" UNIQUE (col1);
+
+
+--
+-- TOC entry 61069 (class 0 OID 0)
+-- Dependencies: 56897
+-- Name: CONSTRAINT "unique" ON table_for_constraints; Type: COMMENT; Schema: source; Owner: postgres
+--
+
+COMMENT ON CONSTRAINT "unique" ON source.table_for_constraints IS 'cmnt';
+
+
+--
+-- TOC entry 56900 (class 1259 OID 149023)
+-- Name: index1; Type: INDEX; Schema: source; Owner: postgres
+--
+
+CREATE INDEX index1 ON source.table_for_index USING btree (col2 varchar_pattern_ops);
+
+
+--
+-- TOC entry 56905 (class 1259 OID 149012)
+-- Name: index_identical; Type: INDEX; Schema: source; Owner: postgres
+--
+
+CREATE INDEX index_identical ON source.table_for_identical USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 56901 (class 1259 OID 149211)
+-- Name: index_same; Type: INDEX; Schema: source; Owner: postgres
+--
+
+CREATE INDEX index_same ON source.table_for_index USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 56902 (class 1259 OID 149022)
+-- Name: index_source; Type: INDEX; Schema: source; Owner: postgres
+--
+
+CREATE INDEX index_source ON source.table_for_index USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 61044 (class 2618 OID 149032)
+-- Name: table_for_rule rule1; Type: RULE; Schema: source; Owner: postgres
+--
+
+CREATE RULE rule1 AS
+    ON UPDATE TO source.table_for_rule DO INSTEAD NOTHING;
+
+
+--
+-- TOC entry 61070 (class 0 OID 0)
+-- Dependencies: 61044
+-- Name: RULE rule1 ON table_for_rule; Type: COMMENT; Schema: source; Owner: postgres
+--
+
+COMMENT ON RULE rule1 ON source.table_for_rule IS 'comments';
+
+
+--
+-- TOC entry 61045 (class 2618 OID 149033)
+-- Name: table_for_rule rule2; Type: RULE; Schema: source; Owner: postgres
+--
+
+CREATE RULE rule2 AS
+    ON INSERT TO source.table_for_rule DO NOTHING;
+
+--
+-- TOC entry 12283 (class 1259 OID 347818)
+-- Name: test view; Type: VIEW; Schema: source; Owner: postgres
+--
+
+CREATE VIEW source."test view" AS
+ SELECT pg_class.relname,
+    pg_class.relnamespace,
+    pg_class.reltype,
+    pg_class.reloftype,
+    pg_class.relowner,
+    pg_class.relam,
+    pg_class.relfilenode,
+    pg_class.reltablespace,
+    pg_class.relpages,
+    pg_class.reltuples,
+    pg_class.relallvisible,
+    pg_class.reltoastrelid,
+    pg_class.relhasindex,
+    pg_class.relisshared,
+    pg_class.relpersistence,
+    pg_class.relkind,
+    pg_class.relnatts,
+    pg_class.relchecks,
+    pg_class.relhasoids,
+    pg_class.relhaspkey,
+    pg_class.relhasrules,
+    pg_class.relhastriggers,
+    pg_class.relhassubclass,
+    pg_class.relrowsecurity,
+    pg_class.relforcerowsecurity,
+    pg_class.relispopulated,
+    pg_class.relreplident,
+    pg_class.relispartition,
+    pg_class.relfrozenxid,
+    pg_class.relminmxid,
+    pg_class.relacl,
+    pg_class.reloptions,
+    pg_class.relpartbound
+   FROM pg_class
+ LIMIT 10;
+
+
+ALTER TABLE source."test view" OWNER TO postgres;
+
+--
+-- TOC entry 12286 (class 1259 OID 347832)
+-- Name: test view f; Type: VIEW; Schema: source; Owner: postgres
+--
+
+CREATE VIEW source."test view f" WITH (security_barrier='false') AS
+ SELECT 2;
+
+
+ALTER TABLE source."test view f" OWNER TO postgres;
+
+--
+-- TOC entry 61111 (class 0 OID 0)
+-- Dependencies: 12286
+-- Name: VIEW "test view f"; Type: COMMENT; Schema: source; Owner: postgres
+--
+
+COMMENT ON VIEW source."test view f" IS 'cmn';
diff --git a/web/pgadmin/tools/schema_diff/tests/pg/10_plus/target.sql b/web/pgadmin/tools/schema_diff/tests/pg/10_plus/target.sql
new file mode 100644
index 000000000..c3042ab60
--- /dev/null
+++ b/web/pgadmin/tools/schema_diff/tests/pg/10_plus/target.sql
@@ -0,0 +1,429 @@
+--
+-- PostgreSQL database dump
+--
+
+-- Dumped from database version 10.7
+-- Dumped by pg_dump version 12beta2
+
+-- Started on 2019-11-01 12:55:22 IST
+
+SET statement_timeout = 0;
+SET lock_timeout = 0;
+SET idle_in_transaction_session_timeout = 0;
+SET client_encoding = 'UTF8';
+SET standard_conforming_strings = on;
+SELECT pg_catalog.set_config('search_path', '', false);
+SET check_function_bodies = false;
+SET xmloption = content;
+SET client_min_messages = warning;
+SET row_security = off;
+
+--
+-- TOC entry 18 (class 2615 OID 139771)
+-- Name: target; Type: SCHEMA; Schema: -; Owner: postgres
+--
+
+CREATE SCHEMA target;
+
+ALTER SCHEMA target OWNER TO postgres;
+
+SET default_tablespace = '';
+
+CREATE EXTENSION btree_gist
+    SCHEMA target;
+
+--
+-- TOC entry 12250 (class 1259 OID 139938)
+-- Name: MView; Type: MATERIALIZED VIEW; Schema: target; Owner: postgres
+--
+
+CREATE MATERIALIZED VIEW target."MView" AS
+ SELECT 'tekst'::text AS text
+  WITH NO DATA;
+
+
+ALTER TABLE target."MView" OWNER TO postgres;
+
+--
+-- TOC entry 12277 (class 1259 OID 149234)
+-- Name: table_for_partition_1; Type: TABLE; Schema: target; Owner: postgres
+--
+
+CREATE TABLE target.table_for_partition_1 (
+    col1 bigint
+)
+PARTITION BY RANGE (col1);
+
+
+ALTER TABLE target.table_for_partition_1 OWNER TO postgres;
+
+--
+-- TOC entry 12278 (class 1259 OID 149237)
+-- Name: part3; Type: TABLE; Schema: target; Owner: postgres
+--
+
+CREATE TABLE target.part3 (
+    col1 bigint
+);
+ALTER TABLE ONLY target.table_for_partition_1 ATTACH PARTITION target.part3 FOR VALUES FROM ('13') TO ('56');
+
+
+ALTER TABLE target.part3 OWNER TO postgres;
+
+--
+-- TOC entry 12259 (class 1259 OID 148971)
+-- Name: table_for_column; Type: TABLE; Schema: target; Owner: postgres
+--
+
+CREATE TABLE target.table_for_column (
+    col1 bigint,
+    col2 bigint,
+    col4 text
+);
+
+
+ALTER TABLE target.table_for_column OWNER TO postgres;
+
+--
+-- TOC entry 12268 (class 1259 OID 149089)
+-- Name: table_for_constraints; Type: TABLE; Schema: target; Owner: postgres
+--
+
+CREATE TABLE target.table_for_constraints (
+    col1 integer NOT NULL,
+    col2 text,
+    CONSTRAINT check_con CHECK ((col1 > 30))
+);
+
+
+ALTER TABLE target.table_for_constraints OWNER TO postgres;
+
+--
+-- TOC entry 61066 (class 0 OID 0)
+-- Dependencies: 12268
+-- Name: TABLE table_for_constraints; Type: COMMENT; Schema: target; Owner: postgres
+--
+
+COMMENT ON TABLE target.table_for_constraints IS 'comments';
+
+
+--
+-- TOC entry 61067 (class 0 OID 0)
+-- Dependencies: 12268
+-- Name: CONSTRAINT check_con ON table_for_constraints; Type: COMMENT; Schema: target; Owner: postgres
+--
+
+COMMENT ON CONSTRAINT check_con ON target.table_for_constraints IS 'coment';
+
+
+--
+-- TOC entry 12257 (class 1259 OID 148960)
+-- Name: table_for_del; Type: TABLE; Schema: target; Owner: postgres
+--
+
+CREATE TABLE target.table_for_del (
+);
+
+
+ALTER TABLE target.table_for_del OWNER TO postgres;
+
+--
+-- TOC entry 12271 (class 1259 OID 149172)
+-- Name: table_for_foreign_key; Type: TABLE; Schema: target; Owner: postgres
+--
+
+CREATE TABLE target.table_for_foreign_key (
+    col1 integer NOT NULL,
+    col2 "char",
+    col3 bigint
+);
+
+
+ALTER TABLE target.table_for_foreign_key OWNER TO postgres;
+
+--
+-- TOC entry 12263 (class 1259 OID 149013)
+-- Name: table_for_identical; Type: TABLE; Schema: target; Owner: postgres
+--
+
+CREATE TABLE target.table_for_identical (
+    col1 integer NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE target.table_for_identical OWNER TO postgres;
+
+--
+-- TOC entry 12261 (class 1259 OID 148986)
+-- Name: table_for_index; Type: TABLE; Schema: target; Owner: postgres
+--
+
+CREATE TABLE target.table_for_index (
+    col1 integer NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE target.table_for_index OWNER TO postgres;
+
+--
+-- TOC entry 12270 (class 1259 OID 149144)
+-- Name: table_for_primary_key; Type: TABLE; Schema: target; Owner: postgres
+--
+
+CREATE TABLE target.table_for_primary_key (
+    col1 integer NOT NULL,
+    col2 text NOT NULL
+);
+
+
+ALTER TABLE target.table_for_primary_key OWNER TO postgres;
+
+--
+-- TOC entry 12265 (class 1259 OID 149034)
+-- Name: table_for_rule; Type: TABLE; Schema: target; Owner: postgres
+--
+
+CREATE TABLE target.table_for_rule (
+    col1 bigint NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE target.table_for_rule OWNER TO postgres;
+
+--
+-- TOC entry 12267 (class 1259 OID 149066)
+-- Name: table_for_trigger; Type: TABLE; Schema: target; Owner: postgres
+--
+
+CREATE TABLE target.table_for_trigger (
+    col1 bigint NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE target.table_for_trigger OWNER TO postgres;
+
+
+--
+-- TOC entry 56906 (class 2606 OID 149097)
+-- Name: table_for_constraints Exclusion; Type: CONSTRAINT; Schema: target; Owner: postgres
+--
+
+ALTER TABLE ONLY target.table_for_constraints
+    ADD CONSTRAINT "Exclusion" EXCLUDE USING gist (col2 WITH <>) WITH (fillfactor='15') WHERE ((col1 > 1)) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- TOC entry 61068 (class 0 OID 0)
+-- Dependencies: 56906
+-- Name: CONSTRAINT "Exclusion" ON table_for_constraints; Type: COMMENT; Schema: target; Owner: postgres
+--
+
+COMMENT ON CONSTRAINT "Exclusion" ON target.table_for_constraints IS 'comments';
+
+
+--
+-- TOC entry 56910 (class 2606 OID 149176)
+-- Name: table_for_foreign_key table_for_foreign_key_pkey; Type: CONSTRAINT; Schema: target; Owner: postgres
+--
+
+ALTER TABLE ONLY target.table_for_foreign_key
+    ADD CONSTRAINT table_for_foreign_key_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56897 (class 2606 OID 148993)
+-- Name: table_for_index table_for_index_pkey; Type: CONSTRAINT; Schema: target; Owner: postgres
+--
+
+ALTER TABLE ONLY target.table_for_index
+    ADD CONSTRAINT table_for_index_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56908 (class 2606 OID 149151)
+-- Name: table_for_primary_key table_for_primary_key_pkey; Type: CONSTRAINT; Schema: target; Owner: postgres
+--
+
+ALTER TABLE ONLY target.table_for_primary_key
+    ADD CONSTRAINT table_for_primary_key_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56902 (class 2606 OID 149041)
+-- Name: table_for_rule table_for_rule_pkey; Type: CONSTRAINT; Schema: target; Owner: postgres
+--
+
+ALTER TABLE ONLY target.table_for_rule
+    ADD CONSTRAINT table_for_rule_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56900 (class 2606 OID 149020)
+-- Name: table_for_identical table_for_table_for_identical_pkey; Type: CONSTRAINT; Schema: target; Owner: postgres
+--
+
+ALTER TABLE ONLY target.table_for_identical
+    ADD CONSTRAINT table_for_table_for_identical_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56904 (class 2606 OID 149073)
+-- Name: table_for_trigger table_for_trigger_pkey; Type: CONSTRAINT; Schema: target; Owner: postgres
+--
+
+ALTER TABLE ONLY target.table_for_trigger
+    ADD CONSTRAINT table_for_trigger_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56893 (class 1259 OID 148994)
+-- Name: index1; Type: INDEX; Schema: target; Owner: postgres
+--
+
+CREATE INDEX index1 ON target.table_for_index USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 56894 (class 1259 OID 148995)
+-- Name: index2; Type: INDEX; Schema: target; Owner: postgres
+--
+
+CREATE INDEX index2 ON target.table_for_index USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 56898 (class 1259 OID 149021)
+-- Name: index_identical; Type: INDEX; Schema: target; Owner: postgres
+--
+
+CREATE INDEX index_identical ON target.table_for_identical USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 56895 (class 1259 OID 149212)
+-- Name: index_same; Type: INDEX; Schema: target; Owner: postgres
+--
+
+CREATE INDEX index_same ON target.table_for_index USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 56892 (class 1259 OID 139945)
+-- Name: mview_index; Type: INDEX; Schema: target; Owner: postgres
+--
+
+CREATE INDEX mview_index ON target."MView" USING btree (text text_pattern_ops);
+
+
+--
+-- TOC entry 61045 (class 2618 OID 149042)
+-- Name: table_for_rule rule1; Type: RULE; Schema: target; Owner: postgres
+--
+
+CREATE RULE rule1 AS
+    ON UPDATE TO target.table_for_rule DO INSTEAD NOTHING;
+
+
+--
+-- TOC entry 61069 (class 0 OID 0)
+-- Dependencies: 61045
+-- Name: RULE rule1 ON table_for_rule; Type: COMMENT; Schema: target; Owner: postgres
+--
+
+COMMENT ON RULE rule1 ON target.table_for_rule IS 'comments';
+
+
+--
+-- TOC entry 61046 (class 2618 OID 149043)
+-- Name: table_for_rule rule2; Type: RULE; Schema: target; Owner: postgres
+--
+
+CREATE RULE rule2 AS
+    ON UPDATE TO target.table_for_rule DO NOTHING;
+
+
+--
+-- TOC entry 61047 (class 2618 OID 149044)
+-- Name: table_for_rule rule3; Type: RULE; Schema: target; Owner: postgres
+--
+
+CREATE RULE rule3 AS
+    ON INSERT TO target.table_for_rule DO NOTHING;
+
+
+--
+-- TOC entry 61050 (class 0 OID 139938)
+-- Dependencies: 12250 61062
+-- Name: MView; Type: MATERIALIZED VIEW DATA; Schema: target; Owner: postgres
+--
+
+REFRESH MATERIALIZED VIEW target."MView";
+
+
+--
+-- TOC entry 12284 (class 1259 OID 347823)
+-- Name: test view; Type: VIEW; Schema: target; Owner: postgres
+--
+
+CREATE VIEW target."test view" AS
+ SELECT pg_class.relname,
+    pg_class.relnamespace,
+    pg_class.reltype,
+    pg_class.reloftype,
+    pg_class.relowner,
+    pg_class.relam,
+    pg_class.relfilenode,
+    pg_class.reltablespace,
+    pg_class.relpages,
+    pg_class.reltuples,
+    pg_class.relallvisible,
+    pg_class.reltoastrelid,
+    pg_class.relhasindex,
+    pg_class.relisshared,
+    pg_class.relpersistence,
+    pg_class.relkind,
+    pg_class.relnatts,
+    pg_class.relchecks,
+    pg_class.relhasoids,
+    pg_class.relhaspkey,
+    pg_class.relhasrules,
+    pg_class.relhastriggers,
+    pg_class.relhassubclass,
+    pg_class.relrowsecurity,
+    pg_class.relforcerowsecurity,
+    pg_class.relispopulated,
+    pg_class.relreplident,
+    pg_class.relispartition,
+    pg_class.relfrozenxid,
+    pg_class.relminmxid,
+    pg_class.relacl,
+    pg_class.reloptions,
+    pg_class.relpartbound
+   FROM pg_class
+ LIMIT 10;
+
+
+ALTER TABLE target."test view" OWNER TO postgres;
+
+--
+-- TOC entry 12285 (class 1259 OID 347828)
+-- Name: test view f; Type: VIEW; Schema: target; Owner: postgres
+--
+
+CREATE VIEW target."test view f" WITH (security_barrier='true') AS
+ SELECT 2;
+
+
+ALTER TABLE target."test view f" OWNER TO postgres;
+
+--
+-- TOC entry 61105 (class 0 OID 0)
+-- Dependencies: 12285
+-- Name: VIEW "test view f"; Type: COMMENT; Schema: target; Owner: postgres
+--
+
+COMMENT ON VIEW target."test view f" IS 'cmn';
diff --git a/web/pgadmin/tools/schema_diff/tests/pg/12_plus/source.sql b/web/pgadmin/tools/schema_diff/tests/pg/12_plus/source.sql
new file mode 100644
index 000000000..8ef87e3bc
--- /dev/null
+++ b/web/pgadmin/tools/schema_diff/tests/pg/12_plus/source.sql
@@ -0,0 +1,440 @@
+--
+-- PostgreSQL database dump
+--
+
+-- Dumped from database version 10.7
+-- Dumped by pg_dump version 12beta2
+
+-- Started on 2019-11-01 12:54:15 IST
+
+SET statement_timeout = 0;
+SET lock_timeout = 0;
+SET idle_in_transaction_session_timeout = 0;
+SET client_encoding = 'UTF8';
+SET standard_conforming_strings = on;
+SELECT pg_catalog.set_config('search_path', '', false);
+SET check_function_bodies = false;
+SET xmloption = content;
+SET client_min_messages = warning;
+SET row_security = off;
+
+--
+-- TOC entry 17 (class 2615 OID 139770)
+-- Name: source; Type: SCHEMA; Schema: -; Owner: postgres
+--
+
+CREATE SCHEMA source;
+
+
+ALTER SCHEMA source OWNER TO postgres;
+
+SET default_tablespace = '';
+
+
+CREATE EXTENSION btree_gist
+    SCHEMA source;
+
+--
+-- TOC entry 12272 (class 1259 OID 149205)
+-- Name: table_for_partition; Type: TABLE; Schema: source; Owner: postgres
+--
+
+CREATE TABLE source.table_for_partition (
+    col1 bigint NOT NULL
+)
+PARTITION BY RANGE (col1);
+
+
+ALTER TABLE source.table_for_partition OWNER TO postgres;
+
+--
+-- TOC entry 12273 (class 1259 OID 149208)
+-- Name: part1; Type: TABLE; Schema: source; Owner: postgres
+--
+
+CREATE TABLE source.part1 (
+    col1 bigint NOT NULL
+);
+ALTER TABLE ONLY source.table_for_partition ATTACH PARTITION source.part1 FOR VALUES FROM ('1') TO ('23');
+
+
+ALTER TABLE source.part1 OWNER TO postgres;
+
+--
+-- TOC entry 12274 (class 1259 OID 149213)
+-- Name: table_for_partition_1; Type: TABLE; Schema: source; Owner: postgres
+--
+
+CREATE TABLE source.table_for_partition_1 (
+    col1 bigint
+)
+PARTITION BY RANGE (col1);
+
+
+ALTER TABLE source.table_for_partition_1 OWNER TO postgres;
+
+--
+-- TOC entry 12275 (class 1259 OID 149216)
+-- Name: part3; Type: TABLE; Schema: source; Owner: postgres
+--
+
+CREATE TABLE source.part3 (
+    col1 bigint
+);
+ALTER TABLE ONLY source.table_for_partition_1 ATTACH PARTITION source.part3 FOR VALUES FROM ('1') TO ('10');
+
+
+ALTER TABLE source.part3 OWNER TO postgres;
+
+--
+-- TOC entry 12276 (class 1259 OID 149219)
+-- Name: part4; Type: TABLE; Schema: source; Owner: postgres
+--
+
+CREATE TABLE source.part4 (
+    col1 bigint
+);
+ALTER TABLE ONLY source.table_for_partition_1 ATTACH PARTITION source.part4 FOR VALUES FROM ('11') TO ('20');
+
+
+ALTER TABLE source.part4 OWNER TO postgres;
+
+--
+-- TOC entry 12258 (class 1259 OID 148963)
+-- Name: table_for_column; Type: TABLE; Schema: source; Owner: postgres
+--
+
+CREATE TABLE source.table_for_column (
+    col1 bigint NOT NULL,
+    col2 text,
+    col3 text
+);
+
+
+ALTER TABLE source.table_for_column OWNER TO postgres;
+
+--
+-- TOC entry 12256 (class 1259 OID 148895)
+-- Name: table_for_constraints; Type: TABLE; Schema: source; Owner: postgres
+--
+
+CREATE TABLE source.table_for_constraints (
+    col1 integer NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE source.table_for_constraints OWNER TO postgres;
+
+--
+-- TOC entry 61066 (class 0 OID 0)
+-- Dependencies: 12256
+-- Name: TABLE table_for_constraints; Type: COMMENT; Schema: source; Owner: postgres
+--
+
+COMMENT ON TABLE source.table_for_constraints IS 'comments';
+
+
+--
+-- TOC entry 12262 (class 1259 OID 149004)
+-- Name: table_for_identical; Type: TABLE; Schema: source; Owner: postgres
+--
+
+CREATE TABLE source.table_for_identical (
+    col1 integer NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE source.table_for_identical OWNER TO postgres;
+
+--
+-- TOC entry 12260 (class 1259 OID 148977)
+-- Name: table_for_index; Type: TABLE; Schema: source; Owner: postgres
+--
+
+CREATE TABLE source.table_for_index (
+    col1 integer NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE source.table_for_index OWNER TO postgres;
+
+--
+-- TOC entry 12269 (class 1259 OID 149128)
+-- Name: table_for_primary_key; Type: TABLE; Schema: source; Owner: postgres
+--
+
+CREATE TABLE source.table_for_primary_key (
+    col1 integer NOT NULL,
+    col2 text NOT NULL
+);
+
+
+ALTER TABLE source.table_for_primary_key OWNER TO postgres;
+
+--
+-- TOC entry 12264 (class 1259 OID 149024)
+-- Name: table_for_rule; Type: TABLE; Schema: source; Owner: postgres
+--
+
+CREATE TABLE source.table_for_rule (
+    col1 bigint NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE source.table_for_rule OWNER TO postgres;
+
+--
+-- TOC entry 12266 (class 1259 OID 149048)
+-- Name: table_for_trigger; Type: TABLE; Schema: source; Owner: postgres
+--
+
+CREATE TABLE source.table_for_trigger (
+    col1 bigint NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE source.table_for_trigger OWNER TO postgres;
+
+--
+-- TOC entry 56893 (class 2606 OID 148904)
+-- Name: table_for_constraints Exclusion; Type: CONSTRAINT; Schema: source; Owner: postgres
+--
+
+ALTER TABLE ONLY source.table_for_constraints
+    ADD CONSTRAINT "Exclusion" EXCLUDE USING gist (col2 WITH <>) WITH (fillfactor='12') WHERE ((col1 > 1)) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- TOC entry 61067 (class 0 OID 0)
+-- Dependencies: 56893
+-- Name: CONSTRAINT "Exclusion" ON table_for_constraints; Type: COMMENT; Schema: source; Owner: postgres
+--
+
+COMMENT ON CONSTRAINT "Exclusion" ON source.table_for_constraints IS 'comments';
+
+
+--
+-- TOC entry 56891 (class 2606 OID 148911)
+-- Name: table_for_constraints check_con; Type: CHECK CONSTRAINT; Schema: source; Owner: postgres
+--
+
+ALTER TABLE source.table_for_constraints
+    ADD CONSTRAINT check_con CHECK ((col1 > 10)) NOT VALID;
+
+
+--
+-- TOC entry 61068 (class 0 OID 0)
+-- Dependencies: 56891
+-- Name: CONSTRAINT check_con ON table_for_constraints; Type: COMMENT; Schema: source; Owner: postgres
+--
+
+COMMENT ON CONSTRAINT check_con ON source.table_for_constraints IS 'coment';
+
+
+--
+-- TOC entry 56899 (class 2606 OID 148970)
+-- Name: table_for_column table_for_column_pkey; Type: CONSTRAINT; Schema: source; Owner: postgres
+--
+
+ALTER TABLE ONLY source.table_for_column
+    ADD CONSTRAINT table_for_column_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56895 (class 2606 OID 148902)
+-- Name: table_for_constraints table_for_constraints_pkey; Type: CONSTRAINT; Schema: source; Owner: postgres
+--
+
+ALTER TABLE ONLY source.table_for_constraints
+    ADD CONSTRAINT table_for_constraints_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56904 (class 2606 OID 148984)
+-- Name: table_for_index table_for_index_pkey; Type: CONSTRAINT; Schema: source; Owner: postgres
+--
+
+ALTER TABLE ONLY source.table_for_index
+    ADD CONSTRAINT table_for_index_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56913 (class 2606 OID 149135)
+-- Name: table_for_primary_key table_for_primary_key_pkey; Type: CONSTRAINT; Schema: source; Owner: postgres
+--
+
+ALTER TABLE ONLY source.table_for_primary_key
+    ADD CONSTRAINT table_for_primary_key_pkey PRIMARY KEY (col1, col2);
+
+
+--
+-- TOC entry 56909 (class 2606 OID 149031)
+-- Name: table_for_rule table_for_rule_pkey; Type: CONSTRAINT; Schema: source; Owner: postgres
+--
+
+ALTER TABLE ONLY source.table_for_rule
+    ADD CONSTRAINT table_for_rule_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56907 (class 2606 OID 149011)
+-- Name: table_for_identical table_for_table_for_identical_pkey; Type: CONSTRAINT; Schema: source; Owner: postgres
+--
+
+ALTER TABLE ONLY source.table_for_identical
+    ADD CONSTRAINT table_for_table_for_identical_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56911 (class 2606 OID 149055)
+-- Name: table_for_trigger table_for_trigger_pkey; Type: CONSTRAINT; Schema: source; Owner: postgres
+--
+
+ALTER TABLE ONLY source.table_for_trigger
+    ADD CONSTRAINT table_for_trigger_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56897 (class 2606 OID 148913)
+-- Name: table_for_constraints unique; Type: CONSTRAINT; Schema: source; Owner: postgres
+--
+
+ALTER TABLE ONLY source.table_for_constraints
+    ADD CONSTRAINT "unique" UNIQUE (col1);
+
+
+--
+-- TOC entry 61069 (class 0 OID 0)
+-- Dependencies: 56897
+-- Name: CONSTRAINT "unique" ON table_for_constraints; Type: COMMENT; Schema: source; Owner: postgres
+--
+
+COMMENT ON CONSTRAINT "unique" ON source.table_for_constraints IS 'cmnt';
+
+
+--
+-- TOC entry 56900 (class 1259 OID 149023)
+-- Name: index1; Type: INDEX; Schema: source; Owner: postgres
+--
+
+CREATE INDEX index1 ON source.table_for_index USING btree (col2 varchar_pattern_ops);
+
+
+--
+-- TOC entry 56905 (class 1259 OID 149012)
+-- Name: index_identical; Type: INDEX; Schema: source; Owner: postgres
+--
+
+CREATE INDEX index_identical ON source.table_for_identical USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 56901 (class 1259 OID 149211)
+-- Name: index_same; Type: INDEX; Schema: source; Owner: postgres
+--
+
+CREATE INDEX index_same ON source.table_for_index USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 56902 (class 1259 OID 149022)
+-- Name: index_source; Type: INDEX; Schema: source; Owner: postgres
+--
+
+CREATE INDEX index_source ON source.table_for_index USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 61044 (class 2618 OID 149032)
+-- Name: table_for_rule rule1; Type: RULE; Schema: source; Owner: postgres
+--
+
+CREATE RULE rule1 AS
+    ON UPDATE TO source.table_for_rule DO INSTEAD NOTHING;
+
+
+--
+-- TOC entry 61070 (class 0 OID 0)
+-- Dependencies: 61044
+-- Name: RULE rule1 ON table_for_rule; Type: COMMENT; Schema: source; Owner: postgres
+--
+
+COMMENT ON RULE rule1 ON source.table_for_rule IS 'comments';
+
+
+--
+-- TOC entry 61045 (class 2618 OID 149033)
+-- Name: table_for_rule rule2; Type: RULE; Schema: source; Owner: postgres
+--
+
+CREATE RULE rule2 AS
+    ON INSERT TO source.table_for_rule DO NOTHING;
+
+--
+-- TOC entry 12283 (class 1259 OID 347818)
+-- Name: test view; Type: VIEW; Schema: source; Owner: postgres
+--
+
+CREATE VIEW source."test view" AS
+ SELECT pg_class.relname,
+    pg_class.relnamespace,
+    pg_class.reltype,
+    pg_class.reloftype,
+    pg_class.relowner,
+    pg_class.relam,
+    pg_class.relfilenode,
+    pg_class.reltablespace,
+    pg_class.relpages
+   FROM pg_class
+ LIMIT 10;
+
+
+ALTER TABLE source."test view" OWNER TO postgres;
+
+--
+-- TOC entry 12286 (class 1259 OID 347832)
+-- Name: test view f; Type: VIEW; Schema: source; Owner: postgres
+--
+
+CREATE VIEW source."test view f" WITH (security_barrier='false') AS
+ SELECT 2;
+
+
+ALTER TABLE source."test view f" OWNER TO postgres;
+
+--
+-- TOC entry 61111 (class 0 OID 0)
+-- Dependencies: 12286
+-- Name: VIEW "test view f"; Type: COMMENT; Schema: source; Owner: postgres
+--
+
+COMMENT ON VIEW source."test view f" IS 'cmn';
+
+--
+-- TOC entry 223 (class 1255 OID 67206)
+-- Name: dodaj_klijenta(character varying, character varying, character varying, character varying, integer, character varying, character varying, character varying, boolean, boolean, character varying, character varying, character varying, character varying, numeric, character varying); Type: PROCEDURE; Schema: public; Owner: postgres
+--
+
+CREATE PROCEDURE source.dodaj_klijenta(v_naziv character varying, v_oib character varying, v_pdv_id character varying, v_adresa character varying, v_mjesto integer, v_drzava character varying, v_tip_p_sub character varying, v_vlasnik character varying, v_pdv boolean, v_fisk boolean, v_iban character varying, v_k_osoba character varying, v_email character varying, v_br_tel character varying, v_radna_god numeric, v_schema character varying)
+    LANGUAGE sql
+    AS $$select 1;$$;
+
+
+ALTER PROCEDURE source.dodaj_klijenta(v_naziv character varying, v_oib character varying, v_pdv_id character varying, v_adresa character varying, v_mjesto integer, v_drzava character varying, v_tip_p_sub character varying, v_vlasnik character varying, v_pdv boolean, v_fisk boolean, v_iban character varying, v_k_osoba character varying, v_email character varying, v_br_tel character varying, v_radna_god numeric, v_schema character varying) OWNER TO postgres;
+
+--
+-- TOC entry 220 (class 1255 OID 67205)
+-- Name: proc1(bigint); Type: PROCEDURE; Schema: source; Owner: postgres
+--
+
+CREATE PROCEDURE source.proc1(arg1 bigint)
+    LANGUAGE sql
+    AS $$select 1;$$;
+
+
+ALTER PROCEDURE source.proc1(arg1 bigint) OWNER TO postgres;
diff --git a/web/pgadmin/tools/schema_diff/tests/pg/12_plus/target.sql b/web/pgadmin/tools/schema_diff/tests/pg/12_plus/target.sql
new file mode 100644
index 000000000..d57841744
--- /dev/null
+++ b/web/pgadmin/tools/schema_diff/tests/pg/12_plus/target.sql
@@ -0,0 +1,417 @@
+--
+-- PostgreSQL database dump
+--
+
+-- Dumped from database version 10.7
+-- Dumped by pg_dump version 12beta2
+
+-- Started on 2019-11-01 12:55:22 IST
+
+SET statement_timeout = 0;
+SET lock_timeout = 0;
+SET idle_in_transaction_session_timeout = 0;
+SET client_encoding = 'UTF8';
+SET standard_conforming_strings = on;
+SELECT pg_catalog.set_config('search_path', '', false);
+SET check_function_bodies = false;
+SET xmloption = content;
+SET client_min_messages = warning;
+SET row_security = off;
+
+--
+-- TOC entry 18 (class 2615 OID 139771)
+-- Name: target; Type: SCHEMA; Schema: -; Owner: postgres
+--
+
+CREATE SCHEMA target;
+
+ALTER SCHEMA target OWNER TO postgres;
+
+SET default_tablespace = '';
+
+CREATE EXTENSION btree_gist
+    SCHEMA target;
+
+--
+-- TOC entry 12250 (class 1259 OID 139938)
+-- Name: MView; Type: MATERIALIZED VIEW; Schema: target; Owner: postgres
+--
+
+CREATE MATERIALIZED VIEW target."MView" AS
+ SELECT 'tekst'::text AS text
+  WITH NO DATA;
+
+
+ALTER TABLE target."MView" OWNER TO postgres;
+
+--
+-- TOC entry 12277 (class 1259 OID 149234)
+-- Name: table_for_partition_1; Type: TABLE; Schema: target; Owner: postgres
+--
+
+CREATE TABLE target.table_for_partition_1 (
+    col1 bigint
+)
+PARTITION BY RANGE (col1);
+
+
+ALTER TABLE target.table_for_partition_1 OWNER TO postgres;
+
+--
+-- TOC entry 12278 (class 1259 OID 149237)
+-- Name: part3; Type: TABLE; Schema: target; Owner: postgres
+--
+
+CREATE TABLE target.part3 (
+    col1 bigint
+);
+ALTER TABLE ONLY target.table_for_partition_1 ATTACH PARTITION target.part3 FOR VALUES FROM ('13') TO ('56');
+
+
+ALTER TABLE target.part3 OWNER TO postgres;
+
+--
+-- TOC entry 12259 (class 1259 OID 148971)
+-- Name: table_for_column; Type: TABLE; Schema: target; Owner: postgres
+--
+
+CREATE TABLE target.table_for_column (
+    col1 bigint,
+    col2 bigint,
+    col4 text
+);
+
+
+ALTER TABLE target.table_for_column OWNER TO postgres;
+
+--
+-- TOC entry 12268 (class 1259 OID 149089)
+-- Name: table_for_constraints; Type: TABLE; Schema: target; Owner: postgres
+--
+
+CREATE TABLE target.table_for_constraints (
+    col1 integer NOT NULL,
+    col2 text,
+    CONSTRAINT check_con CHECK ((col1 > 30))
+);
+
+
+ALTER TABLE target.table_for_constraints OWNER TO postgres;
+
+--
+-- TOC entry 61066 (class 0 OID 0)
+-- Dependencies: 12268
+-- Name: TABLE table_for_constraints; Type: COMMENT; Schema: target; Owner: postgres
+--
+
+COMMENT ON TABLE target.table_for_constraints IS 'comments';
+
+
+--
+-- TOC entry 61067 (class 0 OID 0)
+-- Dependencies: 12268
+-- Name: CONSTRAINT check_con ON table_for_constraints; Type: COMMENT; Schema: target; Owner: postgres
+--
+
+COMMENT ON CONSTRAINT check_con ON target.table_for_constraints IS 'coment';
+
+
+--
+-- TOC entry 12257 (class 1259 OID 148960)
+-- Name: table_for_del; Type: TABLE; Schema: target; Owner: postgres
+--
+
+CREATE TABLE target.table_for_del (
+);
+
+
+ALTER TABLE target.table_for_del OWNER TO postgres;
+
+--
+-- TOC entry 12271 (class 1259 OID 149172)
+-- Name: table_for_foreign_key; Type: TABLE; Schema: target; Owner: postgres
+--
+
+CREATE TABLE target.table_for_foreign_key (
+    col1 integer NOT NULL,
+    col2 "char",
+    col3 bigint
+);
+
+
+ALTER TABLE target.table_for_foreign_key OWNER TO postgres;
+
+--
+-- TOC entry 12263 (class 1259 OID 149013)
+-- Name: table_for_identical; Type: TABLE; Schema: target; Owner: postgres
+--
+
+CREATE TABLE target.table_for_identical (
+    col1 integer NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE target.table_for_identical OWNER TO postgres;
+
+--
+-- TOC entry 12261 (class 1259 OID 148986)
+-- Name: table_for_index; Type: TABLE; Schema: target; Owner: postgres
+--
+
+CREATE TABLE target.table_for_index (
+    col1 integer NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE target.table_for_index OWNER TO postgres;
+
+--
+-- TOC entry 12270 (class 1259 OID 149144)
+-- Name: table_for_primary_key; Type: TABLE; Schema: target; Owner: postgres
+--
+
+CREATE TABLE target.table_for_primary_key (
+    col1 integer NOT NULL,
+    col2 text NOT NULL
+);
+
+
+ALTER TABLE target.table_for_primary_key OWNER TO postgres;
+
+--
+-- TOC entry 12265 (class 1259 OID 149034)
+-- Name: table_for_rule; Type: TABLE; Schema: target; Owner: postgres
+--
+
+CREATE TABLE target.table_for_rule (
+    col1 bigint NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE target.table_for_rule OWNER TO postgres;
+
+--
+-- TOC entry 12267 (class 1259 OID 149066)
+-- Name: table_for_trigger; Type: TABLE; Schema: target; Owner: postgres
+--
+
+CREATE TABLE target.table_for_trigger (
+    col1 bigint NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE target.table_for_trigger OWNER TO postgres;
+
+
+--
+-- TOC entry 56906 (class 2606 OID 149097)
+-- Name: table_for_constraints Exclusion; Type: CONSTRAINT; Schema: target; Owner: postgres
+--
+
+ALTER TABLE ONLY target.table_for_constraints
+    ADD CONSTRAINT "Exclusion" EXCLUDE USING gist (col2 WITH <>) WITH (fillfactor='15') WHERE ((col1 > 1)) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- TOC entry 61068 (class 0 OID 0)
+-- Dependencies: 56906
+-- Name: CONSTRAINT "Exclusion" ON table_for_constraints; Type: COMMENT; Schema: target; Owner: postgres
+--
+
+COMMENT ON CONSTRAINT "Exclusion" ON target.table_for_constraints IS 'comments';
+
+
+--
+-- TOC entry 56910 (class 2606 OID 149176)
+-- Name: table_for_foreign_key table_for_foreign_key_pkey; Type: CONSTRAINT; Schema: target; Owner: postgres
+--
+
+ALTER TABLE ONLY target.table_for_foreign_key
+    ADD CONSTRAINT table_for_foreign_key_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56897 (class 2606 OID 148993)
+-- Name: table_for_index table_for_index_pkey; Type: CONSTRAINT; Schema: target; Owner: postgres
+--
+
+ALTER TABLE ONLY target.table_for_index
+    ADD CONSTRAINT table_for_index_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56908 (class 2606 OID 149151)
+-- Name: table_for_primary_key table_for_primary_key_pkey; Type: CONSTRAINT; Schema: target; Owner: postgres
+--
+
+ALTER TABLE ONLY target.table_for_primary_key
+    ADD CONSTRAINT table_for_primary_key_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56902 (class 2606 OID 149041)
+-- Name: table_for_rule table_for_rule_pkey; Type: CONSTRAINT; Schema: target; Owner: postgres
+--
+
+ALTER TABLE ONLY target.table_for_rule
+    ADD CONSTRAINT table_for_rule_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56900 (class 2606 OID 149020)
+-- Name: table_for_identical table_for_table_for_identical_pkey; Type: CONSTRAINT; Schema: target; Owner: postgres
+--
+
+ALTER TABLE ONLY target.table_for_identical
+    ADD CONSTRAINT table_for_table_for_identical_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56904 (class 2606 OID 149073)
+-- Name: table_for_trigger table_for_trigger_pkey; Type: CONSTRAINT; Schema: target; Owner: postgres
+--
+
+ALTER TABLE ONLY target.table_for_trigger
+    ADD CONSTRAINT table_for_trigger_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56893 (class 1259 OID 148994)
+-- Name: index1; Type: INDEX; Schema: target; Owner: postgres
+--
+
+CREATE INDEX index1 ON target.table_for_index USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 56894 (class 1259 OID 148995)
+-- Name: index2; Type: INDEX; Schema: target; Owner: postgres
+--
+
+CREATE INDEX index2 ON target.table_for_index USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 56898 (class 1259 OID 149021)
+-- Name: index_identical; Type: INDEX; Schema: target; Owner: postgres
+--
+
+CREATE INDEX index_identical ON target.table_for_identical USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 56895 (class 1259 OID 149212)
+-- Name: index_same; Type: INDEX; Schema: target; Owner: postgres
+--
+
+CREATE INDEX index_same ON target.table_for_index USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 56892 (class 1259 OID 139945)
+-- Name: mview_index; Type: INDEX; Schema: target; Owner: postgres
+--
+
+CREATE INDEX mview_index ON target."MView" USING btree (text text_pattern_ops);
+
+
+--
+-- TOC entry 61045 (class 2618 OID 149042)
+-- Name: table_for_rule rule1; Type: RULE; Schema: target; Owner: postgres
+--
+
+CREATE RULE rule1 AS
+    ON UPDATE TO target.table_for_rule DO INSTEAD NOTHING;
+
+
+--
+-- TOC entry 61069 (class 0 OID 0)
+-- Dependencies: 61045
+-- Name: RULE rule1 ON table_for_rule; Type: COMMENT; Schema: target; Owner: postgres
+--
+
+COMMENT ON RULE rule1 ON target.table_for_rule IS 'comments';
+
+
+--
+-- TOC entry 61046 (class 2618 OID 149043)
+-- Name: table_for_rule rule2; Type: RULE; Schema: target; Owner: postgres
+--
+
+CREATE RULE rule2 AS
+    ON UPDATE TO target.table_for_rule DO NOTHING;
+
+
+--
+-- TOC entry 61047 (class 2618 OID 149044)
+-- Name: table_for_rule rule3; Type: RULE; Schema: target; Owner: postgres
+--
+
+CREATE RULE rule3 AS
+    ON INSERT TO target.table_for_rule DO NOTHING;
+
+
+--
+-- TOC entry 61050 (class 0 OID 139938)
+-- Dependencies: 12250 61062
+-- Name: MView; Type: MATERIALIZED VIEW DATA; Schema: target; Owner: postgres
+--
+
+REFRESH MATERIALIZED VIEW target."MView";
+
+--
+-- TOC entry 12284 (class 1259 OID 347823)
+-- Name: test view; Type: VIEW; Schema: target; Owner: postgres
+--
+
+CREATE VIEW target."test view" AS
+ SELECT pg_class.relname,
+    pg_class.relnamespace,
+    pg_class.reltype,
+    pg_class.reloftype,
+    pg_class.relowner,
+    pg_class.relam,
+    pg_class.relfilenode,
+    pg_class.reltablespace,
+    pg_class.relpages
+   FROM pg_class
+ LIMIT 10;
+
+
+ALTER TABLE target."test view" OWNER TO postgres;
+
+--
+-- TOC entry 12285 (class 1259 OID 347828)
+-- Name: test view f; Type: VIEW; Schema: target; Owner: postgres
+--
+
+CREATE VIEW target."test view f" WITH (security_barrier='true') AS
+ SELECT 2;
+
+
+ALTER TABLE target."test view f" OWNER TO postgres;
+
+--
+-- TOC entry 61105 (class 0 OID 0)
+-- Dependencies: 12285
+-- Name: VIEW "test view f"; Type: COMMENT; Schema: target; Owner: postgres
+--
+
+COMMENT ON VIEW target."test view f" IS 'cmn';
+
+
+--
+-- TOC entry 437 (class 1255 OID 112907)
+-- Name: dodaj_klijenta(character varying, character varying, character varying, character varying, integer, character varying, character varying, character varying, boolean, boolean, character varying, character varying, character varying, character varying, numeric, character varying); Type: PROCEDURE; Schema: target schema; Owner: postgres
+--
+
+CREATE PROCEDURE target.dodaj_klijenta(v_naziv character varying, v_oib character varying, v_pdv_id character varying, v_adresa character varying, v_mjesto integer, v_drzava character varying, v_tip_p_sub character varying, v_vlasnik character varying, v_pdv boolean, v_fisk boolean, v_iban character varying, v_k_osoba character varying, v_email character varying, v_br_tel character varying, v_radna_god numeric, v_schema character varying)
+    LANGUAGE sql
+    AS $$select 4;$$;
+
+
+ALTER PROCEDURE target.dodaj_klijenta(v_naziv character varying, v_oib character varying, v_pdv_id character varying, v_adresa character varying, v_mjesto integer, v_drzava character varying, v_tip_p_sub character varying, v_vlasnik character varying, v_pdv boolean, v_fisk boolean, v_iban character varying, v_k_osoba character varying, v_email character varying, v_br_tel character varying, v_radna_god numeric, v_schema character varying) OWNER TO postgres;
diff --git a/web/pgadmin/tools/schema_diff/tests/pg/9.2_plus/source.sql b/web/pgadmin/tools/schema_diff/tests/pg/9.2_plus/source.sql
new file mode 100644
index 000000000..af9054eeb
--- /dev/null
+++ b/web/pgadmin/tools/schema_diff/tests/pg/9.2_plus/source.sql
@@ -0,0 +1,311 @@
+--
+-- PostgreSQL database dump
+--
+
+-- Dumped from database version 10.7
+-- Dumped by pg_dump version 12beta2
+
+-- Started on 2019-11-01 12:54:15 IST
+
+SET statement_timeout = 0;
+SET lock_timeout = 0;
+SET client_encoding = 'UTF8';
+SET standard_conforming_strings = on;
+SELECT pg_catalog.set_config('search_path', '', false);
+SET check_function_bodies = false;
+SET xmloption = content;
+SET client_min_messages = warning;
+
+--
+-- TOC entry 17 (class 2615 OID 139770)
+-- Name: source; Type: SCHEMA; Schema: -; Owner: postgres
+--
+
+CREATE SCHEMA source;
+
+
+ALTER SCHEMA source OWNER TO postgres;
+
+SET default_tablespace = '';
+
+
+CREATE EXTENSION btree_gist
+    SCHEMA source;
+
+
+--
+-- TOC entry 12258 (class 1259 OID 148963)
+-- Name: table_for_column; Type: TABLE; Schema: source; Owner: postgres
+--
+
+CREATE TABLE source.table_for_column (
+    col1 bigint NOT NULL,
+    col2 text,
+    col3 text
+);
+
+
+ALTER TABLE source.table_for_column OWNER TO postgres;
+
+--
+-- TOC entry 12256 (class 1259 OID 148895)
+-- Name: table_for_constraints; Type: TABLE; Schema: source; Owner: postgres
+--
+
+CREATE TABLE source.table_for_constraints (
+    col1 integer NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE source.table_for_constraints OWNER TO postgres;
+
+--
+-- TOC entry 61066 (class 0 OID 0)
+-- Dependencies: 12256
+-- Name: TABLE table_for_constraints; Type: COMMENT; Schema: source; Owner: postgres
+--
+
+COMMENT ON TABLE source.table_for_constraints IS 'comments';
+
+
+--
+-- TOC entry 12262 (class 1259 OID 149004)
+-- Name: table_for_identical; Type: TABLE; Schema: source; Owner: postgres;
+--
+
+CREATE TABLE source.table_for_identical (
+    col1 integer NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE source.table_for_identical OWNER TO postgres;;
+
+--
+-- TOC entry 12260 (class 1259 OID 148977)
+-- Name: table_for_index; Type: TABLE; Schema: source; Owner: postgres
+--
+
+CREATE TABLE source.table_for_index (
+    col1 integer NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE source.table_for_index OWNER TO postgres;
+
+--
+-- TOC entry 12269 (class 1259 OID 149128)
+-- Name: table_for_primary_key; Type: TABLE; Schema: source; Owner: postgres
+--
+
+CREATE TABLE source.table_for_primary_key (
+    col1 integer NOT NULL,
+    col2 text NOT NULL
+);
+
+
+ALTER TABLE source.table_for_primary_key OWNER TO postgres;
+
+--
+-- TOC entry 12264 (class 1259 OID 149024)
+-- Name: table_for_rule; Type: TABLE; Schema: source; Owner: postgres
+--
+
+CREATE TABLE source.table_for_rule (
+    col1 bigint NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE source.table_for_rule OWNER TO postgres;
+
+--
+-- TOC entry 12266 (class 1259 OID 149048)
+-- Name: table_for_trigger; Type: TABLE; Schema: source; Owner: postgres
+--
+
+CREATE TABLE source.table_for_trigger (
+    col1 bigint NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE source.table_for_trigger OWNER TO postgres;
+
+--
+-- TOC entry 56893 (class 2606 OID 148904)
+-- Name: table_for_constraints Exclusion; Type: CONSTRAINT; Schema: source; Owner: postgres
+--
+
+ALTER TABLE ONLY source.table_for_constraints
+    ADD CONSTRAINT "Exclusion" EXCLUDE USING gist (col2 WITH <>) WITH (fillfactor='12') WHERE ((col1 > 1)) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- TOC entry 61067 (class 0 OID 0)
+-- Dependencies: 56893
+-- Name: CONSTRAINT "Exclusion" ON table_for_constraints; Type: COMMENT; Schema: source; Owner: postgres
+--
+
+COMMENT ON CONSTRAINT "Exclusion" ON source.table_for_constraints IS 'comments';
+
+
+--
+-- TOC entry 56891 (class 2606 OID 148911)
+-- Name: table_for_constraints check_con; Type: CHECK CONSTRAINT; Schema: source; Owner: postgres
+--
+
+ALTER TABLE source.table_for_constraints
+    ADD CONSTRAINT check_con CHECK ((col1 > 10)) NOT VALID;
+
+
+--
+-- TOC entry 61068 (class 0 OID 0)
+-- Dependencies: 56891
+-- Name: CONSTRAINT check_con ON table_for_constraints; Type: COMMENT; Schema: source; Owner: postgres
+--
+
+COMMENT ON CONSTRAINT check_con ON source.table_for_constraints IS 'coment';
+
+
+--
+-- TOC entry 56899 (class 2606 OID 148970)
+-- Name: table_for_column table_for_column_pkey; Type: CONSTRAINT; Schema: source; Owner: postgres
+--
+
+ALTER TABLE ONLY source.table_for_column
+    ADD CONSTRAINT table_for_column_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56895 (class 2606 OID 148902)
+-- Name: table_for_constraints table_for_constraints_pkey; Type: CONSTRAINT; Schema: source; Owner: postgres
+--
+
+ALTER TABLE ONLY source.table_for_constraints
+    ADD CONSTRAINT table_for_constraints_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56904 (class 2606 OID 148984)
+-- Name: table_for_index table_for_index_pkey; Type: CONSTRAINT; Schema: source; Owner: postgres
+--
+
+ALTER TABLE ONLY source.table_for_index
+    ADD CONSTRAINT table_for_index_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56913 (class 2606 OID 149135)
+-- Name: table_for_primary_key table_for_primary_key_pkey; Type: CONSTRAINT; Schema: source; Owner: postgres
+--
+
+ALTER TABLE ONLY source.table_for_primary_key
+    ADD CONSTRAINT table_for_primary_key_pkey PRIMARY KEY (col1, col2);
+
+
+--
+-- TOC entry 56909 (class 2606 OID 149031)
+-- Name: table_for_rule table_for_rule_pkey; Type: CONSTRAINT; Schema: source; Owner: postgres
+--
+
+ALTER TABLE ONLY source.table_for_rule
+    ADD CONSTRAINT table_for_rule_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56907 (class 2606 OID 149011)
+-- Name: table_for_identical table_for_table_for_identical_pkey; Type: CONSTRAINT; Schema: source; Owner: postgres;
+--
+
+ALTER TABLE ONLY source.table_for_identical
+    ADD CONSTRAINT table_for_table_for_identical_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56911 (class 2606 OID 149055)
+-- Name: table_for_trigger table_for_trigger_pkey; Type: CONSTRAINT; Schema: source; Owner: postgres
+--
+
+ALTER TABLE ONLY source.table_for_trigger
+    ADD CONSTRAINT table_for_trigger_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56897 (class 2606 OID 148913)
+-- Name: table_for_constraints unique; Type: CONSTRAINT; Schema: source; Owner: postgres
+--
+
+ALTER TABLE ONLY source.table_for_constraints
+    ADD CONSTRAINT "unique" UNIQUE (col1);
+
+
+--
+-- TOC entry 61069 (class 0 OID 0)
+-- Dependencies: 56897
+-- Name: CONSTRAINT "unique" ON table_for_constraints; Type: COMMENT; Schema: source; Owner: postgres
+--
+
+COMMENT ON CONSTRAINT "unique" ON source.table_for_constraints IS 'cmnt';
+
+
+--
+-- TOC entry 56900 (class 1259 OID 149023)
+-- Name: index1; Type: INDEX; Schema: source; Owner: postgres
+--
+
+CREATE INDEX index1 ON source.table_for_index USING btree (col2 varchar_pattern_ops);
+
+
+--
+-- TOC entry 56905 (class 1259 OID 149012)
+-- Name: index_identical; Type: INDEX; Schema: source; Owner: postgres;
+--
+
+CREATE INDEX index_identical ON source.table_for_identical USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 56901 (class 1259 OID 149211)
+-- Name: index_same; Type: INDEX; Schema: source; Owner: postgres
+--
+
+CREATE INDEX index_same ON source.table_for_index USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 56902 (class 1259 OID 149022)
+-- Name: index_source; Type: INDEX; Schema: source; Owner: postgres
+--
+
+CREATE INDEX index_source ON source.table_for_index USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 61044 (class 2618 OID 149032)
+-- Name: table_for_rule rule1; Type: RULE; Schema: source; Owner: postgres
+--
+
+CREATE RULE rule1 AS
+    ON UPDATE TO source.table_for_rule DO INSTEAD NOTHING;
+
+
+--
+-- TOC entry 61070 (class 0 OID 0)
+-- Dependencies: 61044
+-- Name: RULE rule1 ON table_for_rule; Type: COMMENT; Schema: source; Owner: postgres
+--
+
+COMMENT ON RULE rule1 ON source.table_for_rule IS 'comments';
+
+
+--
+-- TOC entry 61045 (class 2618 OID 149033)
+-- Name: table_for_rule rule2; Type: RULE; Schema: source; Owner: postgres
+--
+
+CREATE RULE rule2 AS
+    ON INSERT TO source.table_for_rule DO NOTHING;
+
diff --git a/web/pgadmin/tools/schema_diff/tests/pg/9.2_plus/target.sql b/web/pgadmin/tools/schema_diff/tests/pg/9.2_plus/target.sql
new file mode 100644
index 000000000..ddc4fda28
--- /dev/null
+++ b/web/pgadmin/tools/schema_diff/tests/pg/9.2_plus/target.sql
@@ -0,0 +1,337 @@
+--
+-- PostgreSQL database dump
+--
+
+-- Dumped from database version 10.7
+-- Dumped by pg_dump version 12beta2
+
+-- Started on 2019-11-01 12:55:22 IST
+
+SET statement_timeout = 0;
+SET lock_timeout = 0;
+SET client_encoding = 'UTF8';
+SET standard_conforming_strings = on;
+SELECT pg_catalog.set_config('search_path', '', false);
+SET check_function_bodies = false;
+SET xmloption = content;
+SET client_min_messages = warning;
+
+--
+-- TOC entry 18 (class 2615 OID 139771)
+-- Name: target; Type: SCHEMA; Schema: -; Owner: postgres
+--
+
+CREATE SCHEMA target;
+
+
+ALTER SCHEMA target OWNER TO postgres;
+
+SET default_tablespace = '';
+
+CREATE EXTENSION btree_gist
+    SCHEMA target;
+
+--
+-- TOC entry 12250 (class 1259 OID 139938)
+-- Name: MView; Type: MATERIALIZED VIEW; Schema: target; Owner: postgres
+--
+
+CREATE MATERIALIZED VIEW target."MView" AS
+ SELECT 'tekst'::text AS text
+  WITH NO DATA;
+
+
+ALTER TABLE target."MView" OWNER TO postgres;
+
+--
+-- TOC entry 12259 (class 1259 OID 148971)
+-- Name: table_for_column; Type: TABLE; Schema: target; Owner: postgres
+--
+
+CREATE TABLE target.table_for_column (
+    col1 bigint,
+    col2 bigint,
+    col4 text
+);
+
+
+ALTER TABLE target.table_for_column OWNER TO postgres;
+
+--
+-- TOC entry 12268 (class 1259 OID 149089)
+-- Name: table_for_constraints; Type: TABLE; Schema: target; Owner: postgres
+--
+
+CREATE TABLE target.table_for_constraints (
+    col1 integer NOT NULL,
+    col2 text,
+    CONSTRAINT check_con CHECK ((col1 > 30))
+);
+
+
+ALTER TABLE target.table_for_constraints OWNER TO postgres;
+
+--
+-- TOC entry 61066 (class 0 OID 0)
+-- Dependencies: 12268
+-- Name: TABLE table_for_constraints; Type: COMMENT; Schema: target; Owner: postgres
+--
+
+COMMENT ON TABLE target.table_for_constraints IS 'comments';
+
+
+--
+-- TOC entry 61067 (class 0 OID 0)
+-- Dependencies: 12268
+-- Name: CONSTRAINT check_con ON table_for_constraints; Type: COMMENT; Schema: target; Owner: postgres
+--
+
+COMMENT ON CONSTRAINT check_con ON target.table_for_constraints IS 'coment';
+
+
+--
+-- TOC entry 12257 (class 1259 OID 148960)
+-- Name: table_for_del; Type: TABLE; Schema: target; Owner: postgres
+--
+
+CREATE TABLE target.table_for_del (
+);
+
+
+ALTER TABLE target.table_for_del OWNER TO postgres;
+
+--
+-- TOC entry 12271 (class 1259 OID 149172)
+-- Name: table_for_foreign_key; Type: TABLE; Schema: target; Owner: postgres
+--
+
+CREATE TABLE target.table_for_foreign_key (
+    col1 integer NOT NULL,
+    col2 "char",
+    col3 bigint
+);
+
+
+ALTER TABLE target.table_for_foreign_key OWNER TO postgres;
+
+--
+-- TOC entry 12263 (class 1259 OID 149013)
+-- Name: table_for_identical; Type: TABLE; Schema: target; Owner: postgres
+--
+
+CREATE TABLE target.table_for_identical (
+    col1 integer NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE target.table_for_identical OWNER TO postgres;
+
+--
+-- TOC entry 12261 (class 1259 OID 148986)
+-- Name: table_for_index; Type: TABLE; Schema: target; Owner: postgres
+--
+
+CREATE TABLE target.table_for_index (
+    col1 integer NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE target.table_for_index OWNER TO postgres;
+
+--
+-- TOC entry 12270 (class 1259 OID 149144)
+-- Name: table_for_primary_key; Type: TABLE; Schema: target; Owner: postgres
+--
+
+CREATE TABLE target.table_for_primary_key (
+    col1 integer NOT NULL,
+    col2 text NOT NULL
+);
+
+
+ALTER TABLE target.table_for_primary_key OWNER TO postgres;
+
+--
+-- TOC entry 12265 (class 1259 OID 149034)
+-- Name: table_for_rule; Type: TABLE; Schema: target; Owner: postgres
+--
+
+CREATE TABLE target.table_for_rule (
+    col1 bigint NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE target.table_for_rule OWNER TO postgres;
+
+--
+-- TOC entry 12267 (class 1259 OID 149066)
+-- Name: table_for_trigger; Type: TABLE; Schema: target; Owner: postgres
+--
+
+CREATE TABLE target.table_for_trigger (
+    col1 bigint NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE target.table_for_trigger OWNER TO postgres;
+
+
+--
+-- TOC entry 56906 (class 2606 OID 149097)
+-- Name: table_for_constraints Exclusion; Type: CONSTRAINT; Schema: target; Owner: postgres
+--
+
+ALTER TABLE ONLY target.table_for_constraints
+    ADD CONSTRAINT "Exclusion" EXCLUDE USING gist (col2 WITH <>) WITH (fillfactor='15') WHERE ((col1 > 1)) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- TOC entry 61068 (class 0 OID 0)
+-- Dependencies: 56906
+-- Name: CONSTRAINT "Exclusion" ON table_for_constraints; Type: COMMENT; Schema: target; Owner: postgres
+--
+
+COMMENT ON CONSTRAINT "Exclusion" ON target.table_for_constraints IS 'comments';
+
+
+--
+-- TOC entry 56910 (class 2606 OID 149176)
+-- Name: table_for_foreign_key table_for_foreign_key_pkey; Type: CONSTRAINT; Schema: target; Owner: postgres
+--
+
+ALTER TABLE ONLY target.table_for_foreign_key
+    ADD CONSTRAINT table_for_foreign_key_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56897 (class 2606 OID 148993)
+-- Name: table_for_index table_for_index_pkey; Type: CONSTRAINT; Schema: target; Owner: postgres
+--
+
+ALTER TABLE ONLY target.table_for_index
+    ADD CONSTRAINT table_for_index_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56908 (class 2606 OID 149151)
+-- Name: table_for_primary_key table_for_primary_key_pkey; Type: CONSTRAINT; Schema: target; Owner: postgres
+--
+
+ALTER TABLE ONLY target.table_for_primary_key
+    ADD CONSTRAINT table_for_primary_key_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56902 (class 2606 OID 149041)
+-- Name: table_for_rule table_for_rule_pkey; Type: CONSTRAINT; Schema: target; Owner: postgres
+--
+
+ALTER TABLE ONLY target.table_for_rule
+    ADD CONSTRAINT table_for_rule_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56900 (class 2606 OID 149020)
+-- Name: table_for_identical table_for_table_for_identical_pkey; Type: CONSTRAINT; Schema: target; Owner: postgres
+--
+
+ALTER TABLE ONLY target.table_for_identical
+    ADD CONSTRAINT table_for_table_for_identical_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56904 (class 2606 OID 149073)
+-- Name: table_for_trigger table_for_trigger_pkey; Type: CONSTRAINT; Schema: target; Owner: postgres
+--
+
+ALTER TABLE ONLY target.table_for_trigger
+    ADD CONSTRAINT table_for_trigger_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56893 (class 1259 OID 148994)
+-- Name: index1; Type: INDEX; Schema: target; Owner: postgres
+--
+
+CREATE INDEX index1 ON target.table_for_index USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 56894 (class 1259 OID 148995)
+-- Name: index2; Type: INDEX; Schema: target; Owner: postgres
+--
+
+CREATE INDEX index2 ON target.table_for_index USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 56898 (class 1259 OID 149021)
+-- Name: index_identical; Type: INDEX; Schema: target; Owner: postgres
+--
+
+CREATE INDEX index_identical ON target.table_for_identical USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 56895 (class 1259 OID 149212)
+-- Name: index_same; Type: INDEX; Schema: target; Owner: postgres
+--
+
+CREATE INDEX index_same ON target.table_for_index USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 56892 (class 1259 OID 139945)
+-- Name: mview_index; Type: INDEX; Schema: target; Owner: postgres
+--
+
+CREATE INDEX mview_index ON target."MView" USING btree (text text_pattern_ops);
+
+
+--
+-- TOC entry 61045 (class 2618 OID 149042)
+-- Name: table_for_rule rule1; Type: RULE; Schema: target; Owner: postgres
+--
+
+CREATE RULE rule1 AS
+    ON UPDATE TO target.table_for_rule DO INSTEAD NOTHING;
+
+
+--
+-- TOC entry 61069 (class 0 OID 0)
+-- Dependencies: 61045
+-- Name: RULE rule1 ON table_for_rule; Type: COMMENT; Schema: target; Owner: postgres
+--
+
+COMMENT ON RULE rule1 ON target.table_for_rule IS 'comments';
+
+
+--
+-- TOC entry 61046 (class 2618 OID 149043)
+-- Name: table_for_rule rule2; Type: RULE; Schema: target; Owner: postgres
+--
+
+CREATE RULE rule2 AS
+    ON UPDATE TO target.table_for_rule DO NOTHING;
+
+
+--
+-- TOC entry 61047 (class 2618 OID 149044)
+-- Name: table_for_rule rule3; Type: RULE; Schema: target; Owner: postgres
+--
+
+CREATE RULE rule3 AS
+    ON INSERT TO target.table_for_rule DO NOTHING;
+
+
+--
+-- TOC entry 61050 (class 0 OID 139938)
+-- Dependencies: 12250 61062
+-- Name: MView; Type: MATERIALIZED VIEW DATA; Schema: target; Owner: postgres
+--
+
+REFRESH MATERIALIZED VIEW target."MView";
diff --git a/web/pgadmin/tools/schema_diff/tests/ppas/10_plus/source.sql b/web/pgadmin/tools/schema_diff/tests/ppas/10_plus/source.sql
new file mode 100644
index 000000000..b60dbcd55
--- /dev/null
+++ b/web/pgadmin/tools/schema_diff/tests/ppas/10_plus/source.sql
@@ -0,0 +1,376 @@
+--
+-- PostgreSQL database dump
+--
+
+-- Dumped from database version 10.7
+-- Dumped by pg_dump version 12beta2
+
+-- Started on 2019-11-01 12:54:15 IST
+
+SET statement_timeout = 0;
+SET lock_timeout = 0;
+SET idle_in_transaction_session_timeout = 0;
+SET client_encoding = 'UTF8';
+SET standard_conforming_strings = on;
+SELECT pg_catalog.set_config('search_path', '', false);
+SET check_function_bodies = false;
+SET xmloption = content;
+SET client_min_messages = warning;
+SET row_security = off;
+
+--
+-- TOC entry 17 (class 2615 OID 139770)
+-- Name: source; Type: SCHEMA; Schema: -; Owner: enterprisedb
+--
+
+CREATE SCHEMA source;
+
+
+ALTER SCHEMA source OWNER TO enterprisedb;
+
+SET default_tablespace = '';
+
+
+CREATE EXTENSION btree_gist
+    SCHEMA source;
+
+--
+-- TOC entry 12272 (class 1259 OID 149205)
+-- Name: table_for_partition; Type: TABLE; Schema: source; Owner: enterprisedb
+--
+
+CREATE TABLE source.table_for_partition (
+    col1 bigint NOT NULL
+)
+PARTITION BY RANGE (col1);
+
+
+ALTER TABLE source.table_for_partition OWNER TO enterprisedb;
+
+--
+-- TOC entry 12273 (class 1259 OID 149208)
+-- Name: part1; Type: TABLE; Schema: source; Owner: enterprisedb
+--
+
+CREATE TABLE source.part1 (
+    col1 bigint NOT NULL
+);
+ALTER TABLE ONLY source.table_for_partition ATTACH PARTITION source.part1 FOR VALUES FROM ('1') TO ('23');
+
+
+ALTER TABLE source.part1 OWNER TO enterprisedb;
+
+--
+-- TOC entry 12274 (class 1259 OID 149213)
+-- Name: table_for_partition_1; Type: TABLE; Schema: source; Owner: enterprisedb
+--
+
+CREATE TABLE source.table_for_partition_1 (
+    col1 bigint
+)
+PARTITION BY RANGE (col1);
+
+
+ALTER TABLE source.table_for_partition_1 OWNER TO enterprisedb;
+
+--
+-- TOC entry 12275 (class 1259 OID 149216)
+-- Name: part3; Type: TABLE; Schema: source; Owner: enterprisedb
+--
+
+CREATE TABLE source.part3 (
+    col1 bigint
+);
+ALTER TABLE ONLY source.table_for_partition_1 ATTACH PARTITION source.part3 FOR VALUES FROM ('1') TO ('10');
+
+
+ALTER TABLE source.part3 OWNER TO enterprisedb;
+
+--
+-- TOC entry 12276 (class 1259 OID 149219)
+-- Name: part4; Type: TABLE; Schema: source; Owner: enterprisedb
+--
+
+CREATE TABLE source.part4 (
+    col1 bigint
+);
+ALTER TABLE ONLY source.table_for_partition_1 ATTACH PARTITION source.part4 FOR VALUES FROM ('11') TO ('20');
+
+
+ALTER TABLE source.part4 OWNER TO enterprisedb;
+
+--
+-- TOC entry 12258 (class 1259 OID 148963)
+-- Name: table_for_column; Type: TABLE; Schema: source; Owner: enterprisedb
+--
+
+CREATE TABLE source.table_for_column (
+    col1 bigint NOT NULL,
+    col2 text,
+    col3 text
+);
+
+
+ALTER TABLE source.table_for_column OWNER TO enterprisedb;
+
+--
+-- TOC entry 12256 (class 1259 OID 148895)
+-- Name: table_for_constraints; Type: TABLE; Schema: source; Owner: enterprisedb
+--
+
+CREATE TABLE source.table_for_constraints (
+    col1 integer NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE source.table_for_constraints OWNER TO enterprisedb;
+
+--
+-- TOC entry 61066 (class 0 OID 0)
+-- Dependencies: 12256
+-- Name: TABLE table_for_constraints; Type: COMMENT; Schema: source; Owner: enterprisedb
+--
+
+COMMENT ON TABLE source.table_for_constraints IS 'comments';
+
+
+--
+-- TOC entry 12262 (class 1259 OID 149004)
+-- Name: table_for_identical; Type: TABLE; Schema: source; Owner: enterprisedb
+--
+
+CREATE TABLE source.table_for_identical (
+    col1 integer NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE source.table_for_identical OWNER TO enterprisedb;
+
+--
+-- TOC entry 12260 (class 1259 OID 148977)
+-- Name: table_for_index; Type: TABLE; Schema: source; Owner: enterprisedb
+--
+
+CREATE TABLE source.table_for_index (
+    col1 integer NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE source.table_for_index OWNER TO enterprisedb;
+
+--
+-- TOC entry 12269 (class 1259 OID 149128)
+-- Name: table_for_primary_key; Type: TABLE; Schema: source; Owner: enterprisedb
+--
+
+CREATE TABLE source.table_for_primary_key (
+    col1 integer NOT NULL,
+    col2 text NOT NULL
+);
+
+
+ALTER TABLE source.table_for_primary_key OWNER TO enterprisedb;
+
+--
+-- TOC entry 12264 (class 1259 OID 149024)
+-- Name: table_for_rule; Type: TABLE; Schema: source; Owner: enterprisedb
+--
+
+CREATE TABLE source.table_for_rule (
+    col1 bigint NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE source.table_for_rule OWNER TO enterprisedb;
+
+--
+-- TOC entry 12266 (class 1259 OID 149048)
+-- Name: table_for_trigger; Type: TABLE; Schema: source; Owner: enterprisedb
+--
+
+CREATE TABLE source.table_for_trigger (
+    col1 bigint NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE source.table_for_trigger OWNER TO enterprisedb;
+
+--
+-- TOC entry 56893 (class 2606 OID 148904)
+-- Name: table_for_constraints Exclusion; Type: CONSTRAINT; Schema: source; Owner: enterprisedb
+--
+
+ALTER TABLE ONLY source.table_for_constraints
+    ADD CONSTRAINT "Exclusion" EXCLUDE USING gist (col2 WITH <>) WITH (fillfactor='12') WHERE ((col1 > 1)) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- TOC entry 61067 (class 0 OID 0)
+-- Dependencies: 56893
+-- Name: CONSTRAINT "Exclusion" ON table_for_constraints; Type: COMMENT; Schema: source; Owner: enterprisedb
+--
+
+COMMENT ON CONSTRAINT "Exclusion" ON source.table_for_constraints IS 'comments';
+
+
+--
+-- TOC entry 56891 (class 2606 OID 148911)
+-- Name: table_for_constraints check_con; Type: CHECK CONSTRAINT; Schema: source; Owner: enterprisedb
+--
+
+ALTER TABLE source.table_for_constraints
+    ADD CONSTRAINT check_con CHECK ((col1 > 10)) NOT VALID;
+
+
+--
+-- TOC entry 61068 (class 0 OID 0)
+-- Dependencies: 56891
+-- Name: CONSTRAINT check_con ON table_for_constraints; Type: COMMENT; Schema: source; Owner: enterprisedb
+--
+
+COMMENT ON CONSTRAINT check_con ON source.table_for_constraints IS 'coment';
+
+
+--
+-- TOC entry 56899 (class 2606 OID 148970)
+-- Name: table_for_column table_for_column_pkey; Type: CONSTRAINT; Schema: source; Owner: enterprisedb
+--
+
+ALTER TABLE ONLY source.table_for_column
+    ADD CONSTRAINT table_for_column_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56895 (class 2606 OID 148902)
+-- Name: table_for_constraints table_for_constraints_pkey; Type: CONSTRAINT; Schema: source; Owner: enterprisedb
+--
+
+ALTER TABLE ONLY source.table_for_constraints
+    ADD CONSTRAINT table_for_constraints_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56904 (class 2606 OID 148984)
+-- Name: table_for_index table_for_index_pkey; Type: CONSTRAINT; Schema: source; Owner: enterprisedb
+--
+
+ALTER TABLE ONLY source.table_for_index
+    ADD CONSTRAINT table_for_index_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56913 (class 2606 OID 149135)
+-- Name: table_for_primary_key table_for_primary_key_pkey; Type: CONSTRAINT; Schema: source; Owner: enterprisedb
+--
+
+ALTER TABLE ONLY source.table_for_primary_key
+    ADD CONSTRAINT table_for_primary_key_pkey PRIMARY KEY (col1, col2);
+
+
+--
+-- TOC entry 56909 (class 2606 OID 149031)
+-- Name: table_for_rule table_for_rule_pkey; Type: CONSTRAINT; Schema: source; Owner: enterprisedb
+--
+
+ALTER TABLE ONLY source.table_for_rule
+    ADD CONSTRAINT table_for_rule_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56907 (class 2606 OID 149011)
+-- Name: table_for_identical table_for_table_for_identical_pkey; Type: CONSTRAINT; Schema: source; Owner: enterprisedb
+--
+
+ALTER TABLE ONLY source.table_for_identical
+    ADD CONSTRAINT table_for_table_for_identical_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56911 (class 2606 OID 149055)
+-- Name: table_for_trigger table_for_trigger_pkey; Type: CONSTRAINT; Schema: source; Owner: enterprisedb
+--
+
+ALTER TABLE ONLY source.table_for_trigger
+    ADD CONSTRAINT table_for_trigger_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56897 (class 2606 OID 148913)
+-- Name: table_for_constraints unique; Type: CONSTRAINT; Schema: source; Owner: enterprisedb
+--
+
+ALTER TABLE ONLY source.table_for_constraints
+    ADD CONSTRAINT "unique" UNIQUE (col1);
+
+
+--
+-- TOC entry 61069 (class 0 OID 0)
+-- Dependencies: 56897
+-- Name: CONSTRAINT "unique" ON table_for_constraints; Type: COMMENT; Schema: source; Owner: enterprisedb
+--
+
+COMMENT ON CONSTRAINT "unique" ON source.table_for_constraints IS 'cmnt';
+
+
+--
+-- TOC entry 56900 (class 1259 OID 149023)
+-- Name: index1; Type: INDEX; Schema: source; Owner: enterprisedb
+--
+
+CREATE INDEX index1 ON source.table_for_index USING btree (col2 varchar_pattern_ops);
+
+
+--
+-- TOC entry 56905 (class 1259 OID 149012)
+-- Name: index_identical; Type: INDEX; Schema: source; Owner: enterprisedb
+--
+
+CREATE INDEX index_identical ON source.table_for_identical USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 56901 (class 1259 OID 149211)
+-- Name: index_same; Type: INDEX; Schema: source; Owner: enterprisedb
+--
+
+CREATE INDEX index_same ON source.table_for_index USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 56902 (class 1259 OID 149022)
+-- Name: index_source; Type: INDEX; Schema: source; Owner: enterprisedb
+--
+
+CREATE INDEX index_source ON source.table_for_index USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 61044 (class 2618 OID 149032)
+-- Name: table_for_rule rule1; Type: RULE; Schema: source; Owner: enterprisedb
+--
+
+CREATE RULE rule1 AS
+    ON UPDATE TO source.table_for_rule DO INSTEAD NOTHING;
+
+
+--
+-- TOC entry 61070 (class 0 OID 0)
+-- Dependencies: 61044
+-- Name: RULE rule1 ON table_for_rule; Type: COMMENT; Schema: source; Owner: enterprisedb
+--
+
+COMMENT ON RULE rule1 ON source.table_for_rule IS 'comments';
+
+
+--
+-- TOC entry 61045 (class 2618 OID 149033)
+-- Name: table_for_rule rule2; Type: RULE; Schema: source; Owner: enterprisedb
+--
+
+CREATE RULE rule2 AS
+    ON INSERT TO source.table_for_rule DO NOTHING;
diff --git a/web/pgadmin/tools/schema_diff/tests/ppas/10_plus/target.sql b/web/pgadmin/tools/schema_diff/tests/ppas/10_plus/target.sql
new file mode 100644
index 000000000..57ef05d6a
--- /dev/null
+++ b/web/pgadmin/tools/schema_diff/tests/ppas/10_plus/target.sql
@@ -0,0 +1,364 @@
+--
+-- PostgreSQL database dump
+--
+
+-- Dumped from database version 10.7
+-- Dumped by pg_dump version 12beta2
+
+-- Started on 2019-11-01 12:55:22 IST
+
+SET statement_timeout = 0;
+SET lock_timeout = 0;
+SET idle_in_transaction_session_timeout = 0;
+SET client_encoding = 'UTF8';
+SET standard_conforming_strings = on;
+SELECT pg_catalog.set_config('search_path', '', false);
+SET check_function_bodies = false;
+SET xmloption = content;
+SET client_min_messages = warning;
+SET row_security = off;
+
+--
+-- TOC entry 18 (class 2615 OID 139771)
+-- Name: target; Type: SCHEMA; Schema: -; Owner: enterprisedb
+--
+
+CREATE SCHEMA target;
+
+ALTER SCHEMA target OWNER TO enterprisedb;
+
+SET default_tablespace = '';
+
+CREATE EXTENSION btree_gist
+    SCHEMA target;
+
+--
+-- TOC entry 12250 (class 1259 OID 139938)
+-- Name: MView; Type: MATERIALIZED VIEW; Schema: target; Owner: enterprisedb
+--
+
+CREATE MATERIALIZED VIEW target."MView" AS
+ SELECT 'tekst'::text AS text
+  WITH NO DATA;
+
+
+ALTER TABLE target."MView" OWNER TO enterprisedb;
+
+--
+-- TOC entry 12277 (class 1259 OID 149234)
+-- Name: table_for_partition_1; Type: TABLE; Schema: target; Owner: enterprisedb
+--
+
+CREATE TABLE target.table_for_partition_1 (
+    col1 bigint
+)
+PARTITION BY RANGE (col1);
+
+
+ALTER TABLE target.table_for_partition_1 OWNER TO enterprisedb;
+
+--
+-- TOC entry 12278 (class 1259 OID 149237)
+-- Name: part3; Type: TABLE; Schema: target; Owner: enterprisedb
+--
+
+CREATE TABLE target.part3 (
+    col1 bigint
+);
+ALTER TABLE ONLY target.table_for_partition_1 ATTACH PARTITION target.part3 FOR VALUES FROM ('13') TO ('56');
+
+
+ALTER TABLE target.part3 OWNER TO enterprisedb;
+
+--
+-- TOC entry 12259 (class 1259 OID 148971)
+-- Name: table_for_column; Type: TABLE; Schema: target; Owner: enterprisedb
+--
+
+CREATE TABLE target.table_for_column (
+    col1 bigint,
+    col2 bigint,
+    col4 text
+);
+
+
+ALTER TABLE target.table_for_column OWNER TO enterprisedb;
+
+--
+-- TOC entry 12268 (class 1259 OID 149089)
+-- Name: table_for_constraints; Type: TABLE; Schema: target; Owner: enterprisedb
+--
+
+CREATE TABLE target.table_for_constraints (
+    col1 integer NOT NULL,
+    col2 text,
+    CONSTRAINT check_con CHECK ((col1 > 30))
+);
+
+
+ALTER TABLE target.table_for_constraints OWNER TO enterprisedb;
+
+--
+-- TOC entry 61066 (class 0 OID 0)
+-- Dependencies: 12268
+-- Name: TABLE table_for_constraints; Type: COMMENT; Schema: target; Owner: enterprisedb
+--
+
+COMMENT ON TABLE target.table_for_constraints IS 'comments';
+
+
+--
+-- TOC entry 61067 (class 0 OID 0)
+-- Dependencies: 12268
+-- Name: CONSTRAINT check_con ON table_for_constraints; Type: COMMENT; Schema: target; Owner: enterprisedb
+--
+
+COMMENT ON CONSTRAINT check_con ON target.table_for_constraints IS 'coment';
+
+
+--
+-- TOC entry 12257 (class 1259 OID 148960)
+-- Name: table_for_del; Type: TABLE; Schema: target; Owner: enterprisedb
+--
+
+CREATE TABLE target.table_for_del (
+);
+
+
+ALTER TABLE target.table_for_del OWNER TO enterprisedb;
+
+--
+-- TOC entry 12271 (class 1259 OID 149172)
+-- Name: table_for_foreign_key; Type: TABLE; Schema: target; Owner: enterprisedb
+--
+
+CREATE TABLE target.table_for_foreign_key (
+    col1 integer NOT NULL,
+    col2 "char",
+    col3 bigint
+);
+
+
+ALTER TABLE target.table_for_foreign_key OWNER TO enterprisedb;
+
+--
+-- TOC entry 12263 (class 1259 OID 149013)
+-- Name: table_for_identical; Type: TABLE; Schema: target; Owner: enterprisedb
+--
+
+CREATE TABLE target.table_for_identical (
+    col1 integer NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE target.table_for_identical OWNER TO enterprisedb;
+
+--
+-- TOC entry 12261 (class 1259 OID 148986)
+-- Name: table_for_index; Type: TABLE; Schema: target; Owner: enterprisedb
+--
+
+CREATE TABLE target.table_for_index (
+    col1 integer NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE target.table_for_index OWNER TO enterprisedb;
+
+--
+-- TOC entry 12270 (class 1259 OID 149144)
+-- Name: table_for_primary_key; Type: TABLE; Schema: target; Owner: enterprisedb
+--
+
+CREATE TABLE target.table_for_primary_key (
+    col1 integer NOT NULL,
+    col2 text NOT NULL
+);
+
+
+ALTER TABLE target.table_for_primary_key OWNER TO enterprisedb;
+
+--
+-- TOC entry 12265 (class 1259 OID 149034)
+-- Name: table_for_rule; Type: TABLE; Schema: target; Owner: enterprisedb
+--
+
+CREATE TABLE target.table_for_rule (
+    col1 bigint NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE target.table_for_rule OWNER TO enterprisedb;
+
+--
+-- TOC entry 12267 (class 1259 OID 149066)
+-- Name: table_for_trigger; Type: TABLE; Schema: target; Owner: enterprisedb
+--
+
+CREATE TABLE target.table_for_trigger (
+    col1 bigint NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE target.table_for_trigger OWNER TO enterprisedb;
+
+
+--
+-- TOC entry 56906 (class 2606 OID 149097)
+-- Name: table_for_constraints Exclusion; Type: CONSTRAINT; Schema: target; Owner: enterprisedb
+--
+
+ALTER TABLE ONLY target.table_for_constraints
+    ADD CONSTRAINT "Exclusion" EXCLUDE USING gist (col2 WITH <>) WITH (fillfactor='15') WHERE ((col1 > 1)) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- TOC entry 61068 (class 0 OID 0)
+-- Dependencies: 56906
+-- Name: CONSTRAINT "Exclusion" ON table_for_constraints; Type: COMMENT; Schema: target; Owner: enterprisedb
+--
+
+COMMENT ON CONSTRAINT "Exclusion" ON target.table_for_constraints IS 'comments';
+
+
+--
+-- TOC entry 56910 (class 2606 OID 149176)
+-- Name: table_for_foreign_key table_for_foreign_key_pkey; Type: CONSTRAINT; Schema: target; Owner: enterprisedb
+--
+
+ALTER TABLE ONLY target.table_for_foreign_key
+    ADD CONSTRAINT table_for_foreign_key_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56897 (class 2606 OID 148993)
+-- Name: table_for_index table_for_index_pkey; Type: CONSTRAINT; Schema: target; Owner: enterprisedb
+--
+
+ALTER TABLE ONLY target.table_for_index
+    ADD CONSTRAINT table_for_index_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56908 (class 2606 OID 149151)
+-- Name: table_for_primary_key table_for_primary_key_pkey; Type: CONSTRAINT; Schema: target; Owner: enterprisedb
+--
+
+ALTER TABLE ONLY target.table_for_primary_key
+    ADD CONSTRAINT table_for_primary_key_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56902 (class 2606 OID 149041)
+-- Name: table_for_rule table_for_rule_pkey; Type: CONSTRAINT; Schema: target; Owner: enterprisedb
+--
+
+ALTER TABLE ONLY target.table_for_rule
+    ADD CONSTRAINT table_for_rule_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56900 (class 2606 OID 149020)
+-- Name: table_for_identical table_for_table_for_identical_pkey; Type: CONSTRAINT; Schema: target; Owner: enterprisedb
+--
+
+ALTER TABLE ONLY target.table_for_identical
+    ADD CONSTRAINT table_for_table_for_identical_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56904 (class 2606 OID 149073)
+-- Name: table_for_trigger table_for_trigger_pkey; Type: CONSTRAINT; Schema: target; Owner: enterprisedb
+--
+
+ALTER TABLE ONLY target.table_for_trigger
+    ADD CONSTRAINT table_for_trigger_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56893 (class 1259 OID 148994)
+-- Name: index1; Type: INDEX; Schema: target; Owner: enterprisedb
+--
+
+CREATE INDEX index1 ON target.table_for_index USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 56894 (class 1259 OID 148995)
+-- Name: index2; Type: INDEX; Schema: target; Owner: enterprisedb
+--
+
+CREATE INDEX index2 ON target.table_for_index USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 56898 (class 1259 OID 149021)
+-- Name: index_identical; Type: INDEX; Schema: target; Owner: enterprisedb
+--
+
+CREATE INDEX index_identical ON target.table_for_identical USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 56895 (class 1259 OID 149212)
+-- Name: index_same; Type: INDEX; Schema: target; Owner: enterprisedb
+--
+
+CREATE INDEX index_same ON target.table_for_index USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 56892 (class 1259 OID 139945)
+-- Name: mview_index; Type: INDEX; Schema: target; Owner: enterprisedb
+--
+
+CREATE INDEX mview_index ON target."MView" USING btree (text text_pattern_ops);
+
+
+--
+-- TOC entry 61045 (class 2618 OID 149042)
+-- Name: table_for_rule rule1; Type: RULE; Schema: target; Owner: enterprisedb
+--
+
+CREATE RULE rule1 AS
+    ON UPDATE TO target.table_for_rule DO INSTEAD NOTHING;
+
+
+--
+-- TOC entry 61069 (class 0 OID 0)
+-- Dependencies: 61045
+-- Name: RULE rule1 ON table_for_rule; Type: COMMENT; Schema: target; Owner: enterprisedb
+--
+
+COMMENT ON RULE rule1 ON target.table_for_rule IS 'comments';
+
+
+--
+-- TOC entry 61046 (class 2618 OID 149043)
+-- Name: table_for_rule rule2; Type: RULE; Schema: target; Owner: enterprisedb
+--
+
+CREATE RULE rule2 AS
+    ON UPDATE TO target.table_for_rule DO NOTHING;
+
+
+--
+-- TOC entry 61047 (class 2618 OID 149044)
+-- Name: table_for_rule rule3; Type: RULE; Schema: target; Owner: enterprisedb
+--
+
+CREATE RULE rule3 AS
+    ON INSERT TO target.table_for_rule DO NOTHING;
+
+
+--
+-- TOC entry 61050 (class 0 OID 139938)
+-- Dependencies: 12250 61062
+-- Name: MView; Type: MATERIALIZED VIEW DATA; Schema: target; Owner: enterprisedb
+--
+
+REFRESH MATERIALIZED VIEW target."MView";
diff --git a/web/pgadmin/tools/schema_diff/tests/ppas/9.2_plus/source.sql b/web/pgadmin/tools/schema_diff/tests/ppas/9.2_plus/source.sql
new file mode 100644
index 000000000..67ec216d6
--- /dev/null
+++ b/web/pgadmin/tools/schema_diff/tests/ppas/9.2_plus/source.sql
@@ -0,0 +1,311 @@
+--
+-- PostgreSQL database dump
+--
+
+-- Dumped from database version 10.7
+-- Dumped by pg_dump version 12beta2
+
+-- Started on 2019-11-01 12:54:15 IST
+
+SET statement_timeout = 0;
+SET lock_timeout = 0;
+SET client_encoding = 'UTF8';
+SET standard_conforming_strings = on;
+SELECT pg_catalog.set_config('search_path', '', false);
+SET check_function_bodies = false;
+SET xmloption = content;
+SET client_min_messages = warning;
+
+--
+-- TOC entry 17 (class 2615 OID 139770)
+-- Name: source; Type: SCHEMA; Schema: -; Owner: enterprisedb
+--
+
+CREATE SCHEMA source;
+
+
+ALTER SCHEMA source OWNER TO enterprisedb;
+
+SET default_tablespace = '';
+
+
+CREATE EXTENSION btree_gist
+    SCHEMA source;
+
+
+--
+-- TOC entry 12258 (class 1259 OID 148963)
+-- Name: table_for_column; Type: TABLE; Schema: source; Owner: enterprisedb
+--
+
+CREATE TABLE source.table_for_column (
+    col1 bigint NOT NULL,
+    col2 text,
+    col3 text
+);
+
+
+ALTER TABLE source.table_for_column OWNER TO enterprisedb;
+
+--
+-- TOC entry 12256 (class 1259 OID 148895)
+-- Name: table_for_constraints; Type: TABLE; Schema: source; Owner: enterprisedb
+--
+
+CREATE TABLE source.table_for_constraints (
+    col1 integer NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE source.table_for_constraints OWNER TO enterprisedb;
+
+--
+-- TOC entry 61066 (class 0 OID 0)
+-- Dependencies: 12256
+-- Name: TABLE table_for_constraints; Type: COMMENT; Schema: source; Owner: enterprisedb
+--
+
+COMMENT ON TABLE source.table_for_constraints IS 'comments';
+
+
+--
+-- TOC entry 12262 (class 1259 OID 149004)
+-- Name: table_for_identical; Type: TABLE; Schema: source; Owner: enterprisedb;
+--
+
+CREATE TABLE source.table_for_identical (
+    col1 integer NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE source.table_for_identical OWNER TO enterprisedb;;
+
+--
+-- TOC entry 12260 (class 1259 OID 148977)
+-- Name: table_for_index; Type: TABLE; Schema: source; Owner: enterprisedb
+--
+
+CREATE TABLE source.table_for_index (
+    col1 integer NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE source.table_for_index OWNER TO enterprisedb;
+
+--
+-- TOC entry 12269 (class 1259 OID 149128)
+-- Name: table_for_primary_key; Type: TABLE; Schema: source; Owner: enterprisedb
+--
+
+CREATE TABLE source.table_for_primary_key (
+    col1 integer NOT NULL,
+    col2 text NOT NULL
+);
+
+
+ALTER TABLE source.table_for_primary_key OWNER TO enterprisedb;
+
+--
+-- TOC entry 12264 (class 1259 OID 149024)
+-- Name: table_for_rule; Type: TABLE; Schema: source; Owner: enterprisedb
+--
+
+CREATE TABLE source.table_for_rule (
+    col1 bigint NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE source.table_for_rule OWNER TO enterprisedb;
+
+--
+-- TOC entry 12266 (class 1259 OID 149048)
+-- Name: table_for_trigger; Type: TABLE; Schema: source; Owner: enterprisedb
+--
+
+CREATE TABLE source.table_for_trigger (
+    col1 bigint NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE source.table_for_trigger OWNER TO enterprisedb;
+
+--
+-- TOC entry 56893 (class 2606 OID 148904)
+-- Name: table_for_constraints Exclusion; Type: CONSTRAINT; Schema: source; Owner: enterprisedb
+--
+
+ALTER TABLE ONLY source.table_for_constraints
+    ADD CONSTRAINT "Exclusion" EXCLUDE USING gist (col2 WITH <>) WITH (fillfactor='12') WHERE ((col1 > 1)) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- TOC entry 61067 (class 0 OID 0)
+-- Dependencies: 56893
+-- Name: CONSTRAINT "Exclusion" ON table_for_constraints; Type: COMMENT; Schema: source; Owner: enterprisedb
+--
+
+COMMENT ON CONSTRAINT "Exclusion" ON source.table_for_constraints IS 'comments';
+
+
+--
+-- TOC entry 56891 (class 2606 OID 148911)
+-- Name: table_for_constraints check_con; Type: CHECK CONSTRAINT; Schema: source; Owner: enterprisedb
+--
+
+ALTER TABLE source.table_for_constraints
+    ADD CONSTRAINT check_con CHECK ((col1 > 10)) NOT VALID;
+
+
+--
+-- TOC entry 61068 (class 0 OID 0)
+-- Dependencies: 56891
+-- Name: CONSTRAINT check_con ON table_for_constraints; Type: COMMENT; Schema: source; Owner: enterprisedb
+--
+
+COMMENT ON CONSTRAINT check_con ON source.table_for_constraints IS 'coment';
+
+
+--
+-- TOC entry 56899 (class 2606 OID 148970)
+-- Name: table_for_column table_for_column_pkey; Type: CONSTRAINT; Schema: source; Owner: enterprisedb
+--
+
+ALTER TABLE ONLY source.table_for_column
+    ADD CONSTRAINT table_for_column_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56895 (class 2606 OID 148902)
+-- Name: table_for_constraints table_for_constraints_pkey; Type: CONSTRAINT; Schema: source; Owner: enterprisedb
+--
+
+ALTER TABLE ONLY source.table_for_constraints
+    ADD CONSTRAINT table_for_constraints_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56904 (class 2606 OID 148984)
+-- Name: table_for_index table_for_index_pkey; Type: CONSTRAINT; Schema: source; Owner: enterprisedb
+--
+
+ALTER TABLE ONLY source.table_for_index
+    ADD CONSTRAINT table_for_index_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56913 (class 2606 OID 149135)
+-- Name: table_for_primary_key table_for_primary_key_pkey; Type: CONSTRAINT; Schema: source; Owner: enterprisedb
+--
+
+ALTER TABLE ONLY source.table_for_primary_key
+    ADD CONSTRAINT table_for_primary_key_pkey PRIMARY KEY (col1, col2);
+
+
+--
+-- TOC entry 56909 (class 2606 OID 149031)
+-- Name: table_for_rule table_for_rule_pkey; Type: CONSTRAINT; Schema: source; Owner: enterprisedb
+--
+
+ALTER TABLE ONLY source.table_for_rule
+    ADD CONSTRAINT table_for_rule_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56907 (class 2606 OID 149011)
+-- Name: table_for_identical table_for_table_for_identical_pkey; Type: CONSTRAINT; Schema: source; Owner: enterprisedb;
+--
+
+ALTER TABLE ONLY source.table_for_identical
+    ADD CONSTRAINT table_for_table_for_identical_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56911 (class 2606 OID 149055)
+-- Name: table_for_trigger table_for_trigger_pkey; Type: CONSTRAINT; Schema: source; Owner: enterprisedb
+--
+
+ALTER TABLE ONLY source.table_for_trigger
+    ADD CONSTRAINT table_for_trigger_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56897 (class 2606 OID 148913)
+-- Name: table_for_constraints unique; Type: CONSTRAINT; Schema: source; Owner: enterprisedb
+--
+
+ALTER TABLE ONLY source.table_for_constraints
+    ADD CONSTRAINT "unique" UNIQUE (col1);
+
+
+--
+-- TOC entry 61069 (class 0 OID 0)
+-- Dependencies: 56897
+-- Name: CONSTRAINT "unique" ON table_for_constraints; Type: COMMENT; Schema: source; Owner: enterprisedb
+--
+
+COMMENT ON CONSTRAINT "unique" ON source.table_for_constraints IS 'cmnt';
+
+
+--
+-- TOC entry 56900 (class 1259 OID 149023)
+-- Name: index1; Type: INDEX; Schema: source; Owner: enterprisedb
+--
+
+CREATE INDEX index1 ON source.table_for_index USING btree (col2 varchar_pattern_ops);
+
+
+--
+-- TOC entry 56905 (class 1259 OID 149012)
+-- Name: index_identical; Type: INDEX; Schema: source; Owner: enterprisedb;
+--
+
+CREATE INDEX index_identical ON source.table_for_identical USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 56901 (class 1259 OID 149211)
+-- Name: index_same; Type: INDEX; Schema: source; Owner: enterprisedb
+--
+
+CREATE INDEX index_same ON source.table_for_index USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 56902 (class 1259 OID 149022)
+-- Name: index_source; Type: INDEX; Schema: source; Owner: enterprisedb
+--
+
+CREATE INDEX index_source ON source.table_for_index USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 61044 (class 2618 OID 149032)
+-- Name: table_for_rule rule1; Type: RULE; Schema: source; Owner: enterprisedb
+--
+
+CREATE RULE rule1 AS
+    ON UPDATE TO source.table_for_rule DO INSTEAD NOTHING;
+
+
+--
+-- TOC entry 61070 (class 0 OID 0)
+-- Dependencies: 61044
+-- Name: RULE rule1 ON table_for_rule; Type: COMMENT; Schema: source; Owner: enterprisedb
+--
+
+COMMENT ON RULE rule1 ON source.table_for_rule IS 'comments';
+
+
+--
+-- TOC entry 61045 (class 2618 OID 149033)
+-- Name: table_for_rule rule2; Type: RULE; Schema: source; Owner: enterprisedb
+--
+
+CREATE RULE rule2 AS
+    ON INSERT TO source.table_for_rule DO NOTHING;
+
diff --git a/web/pgadmin/tools/schema_diff/tests/ppas/9.2_plus/target.sql b/web/pgadmin/tools/schema_diff/tests/ppas/9.2_plus/target.sql
new file mode 100644
index 000000000..f64765224
--- /dev/null
+++ b/web/pgadmin/tools/schema_diff/tests/ppas/9.2_plus/target.sql
@@ -0,0 +1,337 @@
+--
+-- PostgreSQL database dump
+--
+
+-- Dumped from database version 10.7
+-- Dumped by pg_dump version 12beta2
+
+-- Started on 2019-11-01 12:55:22 IST
+
+SET statement_timeout = 0;
+SET lock_timeout = 0;
+SET client_encoding = 'UTF8';
+SET standard_conforming_strings = on;
+SELECT pg_catalog.set_config('search_path', '', false);
+SET check_function_bodies = false;
+SET xmloption = content;
+SET client_min_messages = warning;
+
+--
+-- TOC entry 18 (class 2615 OID 139771)
+-- Name: target; Type: SCHEMA; Schema: -; Owner: enterprisedb
+--
+
+CREATE SCHEMA target;
+
+
+ALTER SCHEMA target OWNER TO enterprisedb;
+
+SET default_tablespace = '';
+
+CREATE EXTENSION btree_gist
+    SCHEMA target;
+
+--
+-- TOC entry 12250 (class 1259 OID 139938)
+-- Name: MView; Type: MATERIALIZED VIEW; Schema: target; Owner: enterprisedb
+--
+
+CREATE MATERIALIZED VIEW target."MView" AS
+ SELECT 'tekst'::text AS text
+  WITH NO DATA;
+
+
+ALTER TABLE target."MView" OWNER TO enterprisedb;
+
+--
+-- TOC entry 12259 (class 1259 OID 148971)
+-- Name: table_for_column; Type: TABLE; Schema: target; Owner: enterprisedb
+--
+
+CREATE TABLE target.table_for_column (
+    col1 bigint,
+    col2 bigint,
+    col4 text
+);
+
+
+ALTER TABLE target.table_for_column OWNER TO enterprisedb;
+
+--
+-- TOC entry 12268 (class 1259 OID 149089)
+-- Name: table_for_constraints; Type: TABLE; Schema: target; Owner: enterprisedb
+--
+
+CREATE TABLE target.table_for_constraints (
+    col1 integer NOT NULL,
+    col2 text,
+    CONSTRAINT check_con CHECK ((col1 > 30))
+);
+
+
+ALTER TABLE target.table_for_constraints OWNER TO enterprisedb;
+
+--
+-- TOC entry 61066 (class 0 OID 0)
+-- Dependencies: 12268
+-- Name: TABLE table_for_constraints; Type: COMMENT; Schema: target; Owner: enterprisedb
+--
+
+COMMENT ON TABLE target.table_for_constraints IS 'comments';
+
+
+--
+-- TOC entry 61067 (class 0 OID 0)
+-- Dependencies: 12268
+-- Name: CONSTRAINT check_con ON table_for_constraints; Type: COMMENT; Schema: target; Owner: enterprisedb
+--
+
+COMMENT ON CONSTRAINT check_con ON target.table_for_constraints IS 'coment';
+
+
+--
+-- TOC entry 12257 (class 1259 OID 148960)
+-- Name: table_for_del; Type: TABLE; Schema: target; Owner: enterprisedb
+--
+
+CREATE TABLE target.table_for_del (
+);
+
+
+ALTER TABLE target.table_for_del OWNER TO enterprisedb;
+
+--
+-- TOC entry 12271 (class 1259 OID 149172)
+-- Name: table_for_foreign_key; Type: TABLE; Schema: target; Owner: enterprisedb
+--
+
+CREATE TABLE target.table_for_foreign_key (
+    col1 integer NOT NULL,
+    col2 "char",
+    col3 bigint
+);
+
+
+ALTER TABLE target.table_for_foreign_key OWNER TO enterprisedb;
+
+--
+-- TOC entry 12263 (class 1259 OID 149013)
+-- Name: table_for_identical; Type: TABLE; Schema: target; Owner: enterprisedb
+--
+
+CREATE TABLE target.table_for_identical (
+    col1 integer NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE target.table_for_identical OWNER TO enterprisedb;
+
+--
+-- TOC entry 12261 (class 1259 OID 148986)
+-- Name: table_for_index; Type: TABLE; Schema: target; Owner: enterprisedb
+--
+
+CREATE TABLE target.table_for_index (
+    col1 integer NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE target.table_for_index OWNER TO enterprisedb;
+
+--
+-- TOC entry 12270 (class 1259 OID 149144)
+-- Name: table_for_primary_key; Type: TABLE; Schema: target; Owner: enterprisedb
+--
+
+CREATE TABLE target.table_for_primary_key (
+    col1 integer NOT NULL,
+    col2 text NOT NULL
+);
+
+
+ALTER TABLE target.table_for_primary_key OWNER TO enterprisedb;
+
+--
+-- TOC entry 12265 (class 1259 OID 149034)
+-- Name: table_for_rule; Type: TABLE; Schema: target; Owner: enterprisedb
+--
+
+CREATE TABLE target.table_for_rule (
+    col1 bigint NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE target.table_for_rule OWNER TO enterprisedb;
+
+--
+-- TOC entry 12267 (class 1259 OID 149066)
+-- Name: table_for_trigger; Type: TABLE; Schema: target; Owner: enterprisedb
+--
+
+CREATE TABLE target.table_for_trigger (
+    col1 bigint NOT NULL,
+    col2 text
+);
+
+
+ALTER TABLE target.table_for_trigger OWNER TO enterprisedb;
+
+
+--
+-- TOC entry 56906 (class 2606 OID 149097)
+-- Name: table_for_constraints Exclusion; Type: CONSTRAINT; Schema: target; Owner: enterprisedb
+--
+
+ALTER TABLE ONLY target.table_for_constraints
+    ADD CONSTRAINT "Exclusion" EXCLUDE USING gist (col2 WITH <>) WITH (fillfactor='15') WHERE ((col1 > 1)) DEFERRABLE INITIALLY DEFERRED;
+
+
+--
+-- TOC entry 61068 (class 0 OID 0)
+-- Dependencies: 56906
+-- Name: CONSTRAINT "Exclusion" ON table_for_constraints; Type: COMMENT; Schema: target; Owner: enterprisedb
+--
+
+COMMENT ON CONSTRAINT "Exclusion" ON target.table_for_constraints IS 'comments';
+
+
+--
+-- TOC entry 56910 (class 2606 OID 149176)
+-- Name: table_for_foreign_key table_for_foreign_key_pkey; Type: CONSTRAINT; Schema: target; Owner: enterprisedb
+--
+
+ALTER TABLE ONLY target.table_for_foreign_key
+    ADD CONSTRAINT table_for_foreign_key_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56897 (class 2606 OID 148993)
+-- Name: table_for_index table_for_index_pkey; Type: CONSTRAINT; Schema: target; Owner: enterprisedb
+--
+
+ALTER TABLE ONLY target.table_for_index
+    ADD CONSTRAINT table_for_index_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56908 (class 2606 OID 149151)
+-- Name: table_for_primary_key table_for_primary_key_pkey; Type: CONSTRAINT; Schema: target; Owner: enterprisedb
+--
+
+ALTER TABLE ONLY target.table_for_primary_key
+    ADD CONSTRAINT table_for_primary_key_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56902 (class 2606 OID 149041)
+-- Name: table_for_rule table_for_rule_pkey; Type: CONSTRAINT; Schema: target; Owner: enterprisedb
+--
+
+ALTER TABLE ONLY target.table_for_rule
+    ADD CONSTRAINT table_for_rule_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56900 (class 2606 OID 149020)
+-- Name: table_for_identical table_for_table_for_identical_pkey; Type: CONSTRAINT; Schema: target; Owner: enterprisedb
+--
+
+ALTER TABLE ONLY target.table_for_identical
+    ADD CONSTRAINT table_for_table_for_identical_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56904 (class 2606 OID 149073)
+-- Name: table_for_trigger table_for_trigger_pkey; Type: CONSTRAINT; Schema: target; Owner: enterprisedb
+--
+
+ALTER TABLE ONLY target.table_for_trigger
+    ADD CONSTRAINT table_for_trigger_pkey PRIMARY KEY (col1);
+
+
+--
+-- TOC entry 56893 (class 1259 OID 148994)
+-- Name: index1; Type: INDEX; Schema: target; Owner: enterprisedb
+--
+
+CREATE INDEX index1 ON target.table_for_index USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 56894 (class 1259 OID 148995)
+-- Name: index2; Type: INDEX; Schema: target; Owner: enterprisedb
+--
+
+CREATE INDEX index2 ON target.table_for_index USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 56898 (class 1259 OID 149021)
+-- Name: index_identical; Type: INDEX; Schema: target; Owner: enterprisedb
+--
+
+CREATE INDEX index_identical ON target.table_for_identical USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 56895 (class 1259 OID 149212)
+-- Name: index_same; Type: INDEX; Schema: target; Owner: enterprisedb
+--
+
+CREATE INDEX index_same ON target.table_for_index USING btree (col2 text_pattern_ops);
+
+
+--
+-- TOC entry 56892 (class 1259 OID 139945)
+-- Name: mview_index; Type: INDEX; Schema: target; Owner: enterprisedb
+--
+
+CREATE INDEX mview_index ON target."MView" USING btree (text text_pattern_ops);
+
+
+--
+-- TOC entry 61045 (class 2618 OID 149042)
+-- Name: table_for_rule rule1; Type: RULE; Schema: target; Owner: enterprisedb
+--
+
+CREATE RULE rule1 AS
+    ON UPDATE TO target.table_for_rule DO INSTEAD NOTHING;
+
+
+--
+-- TOC entry 61069 (class 0 OID 0)
+-- Dependencies: 61045
+-- Name: RULE rule1 ON table_for_rule; Type: COMMENT; Schema: target; Owner: enterprisedb
+--
+
+COMMENT ON RULE rule1 ON target.table_for_rule IS 'comments';
+
+
+--
+-- TOC entry 61046 (class 2618 OID 149043)
+-- Name: table_for_rule rule2; Type: RULE; Schema: target; Owner: enterprisedb
+--
+
+CREATE RULE rule2 AS
+    ON UPDATE TO target.table_for_rule DO NOTHING;
+
+
+--
+-- TOC entry 61047 (class 2618 OID 149044)
+-- Name: table_for_rule rule3; Type: RULE; Schema: target; Owner: enterprisedb
+--
+
+CREATE RULE rule3 AS
+    ON INSERT TO target.table_for_rule DO NOTHING;
+
+
+--
+-- TOC entry 61050 (class 0 OID 139938)
+-- Dependencies: 12250 61062
+-- Name: MView; Type: MATERIALIZED VIEW DATA; Schema: target; Owner: enterprisedb
+--
+
+REFRESH MATERIALIZED VIEW target."MView";
diff --git a/web/pgadmin/tools/schema_diff/tests/test_schema_diff_comp.py b/web/pgadmin/tools/schema_diff/tests/test_schema_diff_comp.py
new file mode 100644
index 000000000..3e790bc06
--- /dev/null
+++ b/web/pgadmin/tools/schema_diff/tests/test_schema_diff_comp.py
@@ -0,0 +1,204 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2019, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+import uuid
+import json
+import os
+import random
+
+from pgadmin.utils import server_utils as server_utils
+from pgadmin.utils.route import BaseTestGenerator
+from regression import parent_node_dict
+from regression.python_test_utils import test_utils as utils
+from .utils import create_table, create_schema, restore_schema
+from pgadmin.browser.server_groups.servers.databases.tests import utils as \
+    database_utils
+from pgadmin.utils.versioned_template_loader import \
+    get_version_mapping_directories
+
+
+class SchemaDiffTestCase(BaseTestGenerator):
+    """ This class will test the schema diff. """
+    scenarios = [
+        # Fetching default URL for database node.
+        ('Schema diff comparison', dict(
+            url='schema_diff/compare/{0}/{1}/{2}/{3}/{4}/{5}/{6}'))
+    ]
+
+    def setUp(self):
+        self.src_database = "db_schema_diff_src_%s" % str(uuid.uuid4())[1:8]
+        self.tar_database = "db_schema_diff_tar_%s" % str(uuid.uuid4())[1:8]
+
+        self.src_db_id = utils.create_database(self.server, self.src_database)
+        self.tar_db_id = utils.create_database(self.server, self.tar_database)
+
+        self.server = parent_node_dict["server"][-1]["server"]
+        self.server_id = parent_node_dict["server"][-1]["server_id"]
+        self.nodes = ['table', 'function', 'procedure', 'view', 'mview']
+        self.restore_backup()
+
+    def restore_backup(self):
+        self.sql_folder = self.get_sql_folder()
+
+        if self.sql_folder is None:
+            raise FileNotFoundError('Schema diff folder does not exists')
+
+        src_sql_path = os.path.join(self.sql_folder, 'source.sql')
+        tar_sql_path = os.path.join(self.sql_folder, 'target.sql')
+
+        if not os.path.exists(src_sql_path):
+            raise FileNotFoundError(
+                '{} file does not exists'.format(src_sql_path))
+
+        if not os.path.exists(tar_sql_path):
+            raise FileNotFoundError(
+                '{} file does not exists'.format(tar_sql_path))
+
+        self.src_schema_id = restore_schema(self.server, self.src_database,
+                                            'source', src_sql_path)
+        self.tar_schema_id = restore_schema(self.server, self.tar_database,
+                                            'target', tar_sql_path)
+
+    def get_sql_folder(self):
+        """
+        This function will get the appropriate test folder based on
+        server version and their existence.
+
+        :param module_path: Path of the module to be tested.
+        :return:
+        """
+        # Join the application path, module path and tests folder
+        tests_folder_path = os.path.dirname(os.path.abspath(__file__))
+
+        # A folder name matching the Server Type (pg, ppas) takes priority so
+        # check whether that exists or not. If so, than check the version
+        # folder in it, else look directly in the 'tests' folder.
+        absolute_path = os.path.join(tests_folder_path, self.server['type'])
+        if not os.path.exists(absolute_path):
+            absolute_path = tests_folder_path
+
+        # Iterate the version mapping directories.
+        for version_mapping in get_version_mapping_directories(
+                self.server['type']):
+            if version_mapping['number'] > \
+                    self.server_information['server_version']:
+                continue
+
+            complete_path = os.path.join(absolute_path,
+                                         version_mapping['name'])
+
+            if os.path.exists(complete_path):
+                return complete_path
+
+        return None
+
+    def compare(self):
+        comp_url = self.url.format(self.trans_id, self.server_id,
+                                   self.src_db_id,
+                                   self.src_schema_id,
+                                   self.server_id,
+                                   self.tar_db_id,
+                                   self.tar_schema_id
+                                   )
+
+        response = self.tester.get(comp_url)
+
+        self.assertEquals(response.status_code, 200)
+        return json.loads(response.data.decode('utf-8'))
+
+    def runTest(self):
+        """ This function will test the schema diff."""
+
+        response = self.tester.get("schema_diff/initialize")
+        self.assertEquals(response.status_code, 200)
+        response_data = json.loads(response.data.decode('utf-8'))
+        self.trans_id = response_data['data']['schemaDiffTransId']
+
+        url = 'schema_diff/server/connect/{}'.format(self.server_id)
+        data = {'password': self.server['db_password']}
+        response = self.tester.post(url,
+                                    data=json.dumps(data),
+                                    content_type='html/json'
+                                    )
+        response = self.tester.post(
+            'schema_diff/database/connect/{0}/{1}'.format(
+                self.server_id,
+                self.src_db_id))
+        response = self.tester.post(
+            'schema_diff/database/connect/{0}/{1}'.format(
+                self.server_id,
+                self.tar_db_id))
+
+        response_data = self.compare()
+
+        diff_file = os.path.join(self.sql_folder, 'diff_{0}.sql'.format(
+            str(random.randint(1, 99999))))
+        file_obj = open(diff_file, 'a')
+
+        for diff in response_data['data']:
+            if diff['type'] in self.nodes:
+                src_obj_oid = tar_obj_oid = None
+                if diff['status'] == 'Source Only' or\
+                        diff['status'] == 'Target Only':
+                    src_obj_oid = tar_obj_oid = diff['oid']
+                elif diff['status'] == 'Different':
+                    src_obj_oid = diff['source_oid']
+                    tar_obj_oid = diff['target_oid']
+
+                if src_obj_oid is not None:
+                    url = 'schema_diff/ddl_compare/{0}/{1}/{2}/{3}/{4}/{5}/' \
+                          '{6}/{7}/{8}/{9}/{10}/'.format(self.trans_id,
+                                                         self.server_id,
+                                                         self.src_db_id,
+                                                         self.src_schema_id,
+                                                         self.server_id,
+                                                         self.tar_db_id,
+                                                         self.tar_schema_id,
+                                                         src_obj_oid,
+                                                         tar_obj_oid,
+                                                         diff['type'],
+                                                         diff['status']
+                                                         )
+
+                    response = self.tester.get(url)
+
+                    self.assertEquals(response.status_code, 200)
+                    response_data = json.loads(response.data.decode('utf-8'))
+                    file_obj.write(response_data['diff_ddl'])
+
+        file_obj.close()
+        try:
+            restore_schema(self.server, self.tar_database, 'target',
+                           diff_file)
+
+            os.remove(diff_file)
+
+            response_data = self.compare()
+            for diff in response_data['data']:
+                if diff['type'] in self.nodes:
+                    self.assertEquals(diff['status'], 'Identical')
+        except Exception as e:
+            os.remove(diff_file)
+
+    def tearDown(self):
+        """This function drop the added database"""
+        connection = utils.get_db_connection(self.server['db'],
+                                             self.server['username'],
+                                             self.server['db_password'],
+                                             self.server['host'],
+                                             self.server['port'],
+                                             self.server['sslmode'])
+        utils.drop_database(connection, self.src_database)
+        connection = utils.get_db_connection(self.server['db'],
+                                             self.server['username'],
+                                             self.server['db_password'],
+                                             self.server['host'],
+                                             self.server['port'],
+                                             self.server['sslmode'])
+        utils.drop_database(connection, self.tar_database)
diff --git a/web/pgadmin/tools/schema_diff/tests/utils.py b/web/pgadmin/tools/schema_diff/tests/utils.py
new file mode 100644
index 000000000..ee513e490
--- /dev/null
+++ b/web/pgadmin/tools/schema_diff/tests/utils.py
@@ -0,0 +1,103 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2019, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+import sys
+import traceback
+
+from regression.python_test_utils import test_utils as utils
+from pgadmin.browser.server_groups.servers.databases.schemas.tests import \
+    utils as schema_utils
+
+
+def restore_schema(server, db_name, schema_name, sql_path):
+    connection = utils.get_db_connection(db_name,
+                                         server['username'],
+                                         server['db_password'],
+                                         server['host'],
+                                         server['port'],
+                                         server['sslmode']
+                                         )
+
+    old_isolation_level = connection.isolation_level
+    connection.set_isolation_level(0)
+    pg_cursor = connection.cursor()
+
+    sql = ''
+    with open(sql_path, 'r') as content_file:
+        sql = content_file.read()
+    pg_cursor.execute(sql)
+    connection.set_isolation_level(old_isolation_level)
+    connection.commit()
+
+    SQL = """SELECT
+    nsp.oid
+FROM
+    pg_namespace nsp
+    WHERE nsp.nspname = '{0}'""".format(schema_name)
+
+    pg_cursor.execute(SQL)
+    schema = pg_cursor.fetchone()
+    schema_id = None
+    if schema:
+        schema_id = schema[0]
+    connection.close()
+    return schema_id
+
+
+def create_schema(server, db_name, schema_name):
+    connection = utils.get_db_connection(db_name,
+                                         server['username'],
+                                         server['db_password'],
+                                         server['host'],
+                                         server['port'],
+                                         server['sslmode']
+                                         )
+    return schema_utils.create_schema(connection, schema_name)
+
+
+def create_table(server, db_name, schema_id, table_name, query):
+    """
+    This function creates a table under provided schema.
+    :param server: server details
+    :type server: dict
+    :param db_name: database name
+    :type db_name: str
+    :param schema_id: schema oid
+    :type schema_name: int
+    :param table_name: table name
+    :type table_name: str
+    :return table_id: table id
+    :rtype: int
+    """
+    try:
+        connection = utils.get_db_connection(db_name,
+                                             server['username'],
+                                             server['db_password'],
+                                             server['host'],
+                                             server['port'],
+                                             server['sslmode'])
+        old_isolation_level = connection.isolation_level
+        connection.set_isolation_level(0)
+        pg_cursor = connection.cursor()
+        pg_cursor.execute(query)
+        connection.set_isolation_level(old_isolation_level)
+        connection.commit()
+        # Get 'oid' from newly created table
+        pg_cursor.execute("SELECT oid FROM pg_class WHERE relname='{0}'"
+                          " AND relnamespace = {1}".format(table_name,
+                                                           schema_id))
+        table = pg_cursor.fetchone()
+        table_id = ''
+        if table:
+            table_id = table[0]
+        connection.close()
+        return table_id
+    except Exception:
+        traceback.print_exc(file=sys.stderr)
+        raise
diff --git a/web/pgadmin/tools/sqleditor/static/js/sqleditor.js b/web/pgadmin/tools/sqleditor/static/js/sqleditor.js
index 3e3554e8d..b0b8e7f4b 100644
--- a/web/pgadmin/tools/sqleditor/static/js/sqleditor.js
+++ b/web/pgadmin/tools/sqleditor/static/js/sqleditor.js
@@ -84,6 +84,8 @@ define('tools.querytool', [
       this.handler.preferences = this.preferences;
       this.connIntervalId = null;
       this.layout = opts.layout;
+      this.set_server_version(opts.server_ver);
+      this.trigger('pgadmin-sqleditor:view:initialised');
     },
 
     // Bind all the events
@@ -2312,6 +2314,12 @@ define('tools.querytool', [
         }
       },
 
+      set_value_to_editor: function(query) {
+        if (this.gridView && this.gridView.query_tool_obj && !_.isUndefined(query)) {
+          this.gridView.query_tool_obj.setValue(query);
+        }
+      },
+
       init_events: function() {
         var self = this;
         // Listen to the file manager button events
diff --git a/web/pgadmin/tools/sqleditor/templates/sqleditor/sql/default/primary_keys.sql b/web/pgadmin/tools/sqleditor/templates/sqleditor/sql/default/primary_keys.sql
index a96c928f6..d1e398579 100644
--- a/web/pgadmin/tools/sqleditor/templates/sqleditor/sql/default/primary_keys.sql
+++ b/web/pgadmin/tools/sqleditor/templates/sqleditor/sql/default/primary_keys.sql
@@ -4,5 +4,5 @@ SELECT at.attname, at.attnum, ty.typname
 FROM pg_attribute at LEFT JOIN pg_type ty ON (ty.oid = at.atttypid)
 WHERE attrelid={{obj_id}}::oid AND attnum = ANY (
     (SELECT con.conkey FROM pg_class rel LEFT OUTER JOIN pg_constraint con ON con.conrelid=rel.oid
-    AND con.contype='p' WHERE rel.relkind IN ('r','s','t') AND rel.oid = {{obj_id}}::oid)::oid[])
+    AND con.contype='p' WHERE rel.relkind IN ('r','s','t') AND rel.oid = ({{obj_id}})::oid)::oid[])
 {% endif %}
diff --git a/web/pgadmin/tools/sqleditor/utils/get_column_types.py b/web/pgadmin/tools/sqleditor/utils/get_column_types.py
index 99bcb9fa8..74b2e2f60 100644
--- a/web/pgadmin/tools/sqleditor/utils/get_column_types.py
+++ b/web/pgadmin/tools/sqleditor/utils/get_column_types.py
@@ -35,12 +35,13 @@ def get_columns_types(is_query_tool, columns_info, table_oid, conn, has_oids):
         column_types[col['name']] = col_type
 
         if not is_query_tool:
-            col_type['not_null'] = col['not_null'] = \
-                rset['rows'][key]['not_null']
+            if key in rset['rows']:
+                col_type['not_null'] = col['not_null'] = \
+                    rset['rows'][key]['not_null']
 
-            col_type['has_default_val'] = \
-                col['has_default_val'] = \
-                rset['rows'][key]['has_default_val']
+                col_type['has_default_val'] = \
+                    col['has_default_val'] = \
+                    rset['rows'][key]['has_default_val']
 
         else:
             for row in rset['rows']:
diff --git a/web/pgadmin/utils/csrf.py b/web/pgadmin/utils/csrf.py
index dfeb3a6a9..02c2dc00f 100644
--- a/web/pgadmin/utils/csrf.py
+++ b/web/pgadmin/utils/csrf.py
@@ -34,6 +34,8 @@ class _PGCSRFProtect(CSRFProtect):
             'pgadmin.tools.datagrid.panel',
             'pgadmin.tools.debugger.initialize_target',
             'pgadmin.tools.debugger.direct_new',
+            'pgadmin.tools.schema_diff.panel',
+            'pgadmin.tools.schema_diff.ddl_compare',
         ]
 
         for exempt in exempt_views:
diff --git a/web/webpack.config.js b/web/webpack.config.js
index a6749a5ed..230172cf0 100644
--- a/web/webpack.config.js
+++ b/web/webpack.config.js
@@ -356,6 +356,7 @@ module.exports = [{
     slickgrid: sourceDir + '/bundle/slickgrid.js',
     sqleditor: './pgadmin/tools/sqleditor/static/js/sqleditor.js',
     debugger_direct: './pgadmin/tools/debugger/static/js/direct.js',
+    schema_diff: './pgadmin/tools/schema_diff/static/js/schema_diff_hook.js',
     file_utils: './pgadmin/misc/file_manager/static/js/utility.js',
     'pgadmin.style': pgadminCssStyles,
     pgadmin: pgadminScssStyles,
@@ -492,7 +493,8 @@ module.exports = [{
         ',pgadmin.tools.import_export' +
         ',pgadmin.tools.debugger.controller' +
         ',pgadmin.tools.debugger.direct' +
-        ',pgadmin.node.pga_job',
+        ',pgadmin.node.pga_job' +
+        ',pgadmin.tools.schema_diff',
       },
     }, {
       test: require.resolve('snapsvg'),
diff --git a/web/webpack.shim.js b/web/webpack.shim.js
index 2e2b7ed41..daa4c8e99 100644
--- a/web/webpack.shim.js
+++ b/web/webpack.shim.js
@@ -278,6 +278,8 @@ var webpackShimConfig = {
     'pgadmin.tools.import_export': path.join(__dirname, './pgadmin/tools/import_export/static/js/import_export'),
     'pgadmin.tools.maintenance': path.join(__dirname, './pgadmin/tools/maintenance/static/js/maintenance'),
     'pgadmin.tools.restore': path.join(__dirname, './pgadmin/tools/restore/static/js/restore'),
+    'pgadmin.tools.schema_diff': path.join(__dirname, './pgadmin/tools/schema_diff/static/js/schema_diff'),
+    'pgadmin.tools.schema_diff_ui': path.join(__dirname, './pgadmin/tools/schema_diff/static/js/schema_diff_ui'),
     'pgadmin.tools.user_management': path.join(__dirname, './pgadmin/tools/user_management/static/js/user_management'),
     'pgadmin.user_management.current_user': '/user_management/current_user',
     'slick.pgadmin.editors': path.join(__dirname, './pgadmin/tools/../static/js/slickgrid/editors'),
