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
new file mode 100644
index 0000000..408660b
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/__init__.py
@@ -0,0 +1,2809 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+""" Implements Table Node """
+
+import json
+import re
+from flask import render_template, make_response, request, jsonify
+from flask.ext.babel import gettext
+from pgadmin.utils.ajax import make_json_response, \
+    make_response as ajax_response, internal_server_error
+from pgadmin.browser.utils import PGChildNodeView
+from pgadmin.browser.server_groups.servers.databases.schemas.utils \
+    import SchemaChildModule, DataTypeReader, VacuumSettings, \
+    trigger_definition, parse_rule_definition
+import pgadmin.browser.server_groups.servers.databases as database
+from pgadmin.utils.ajax import precondition_required
+from pgadmin.utils.driver import get_driver
+from config import PG_DEFAULT_DRIVER
+from pgadmin.browser.server_groups.servers.utils import parse_priv_from_db, \
+    parse_priv_to_db
+from functools import wraps
+
+
+class TableModule(SchemaChildModule):
+    """
+     class TableModule(SchemaChildModule)
+
+        A module class for Table node derived from SchemaChildModule.
+
+    Methods:
+    -------
+    * __init__(*args, **kwargs)
+      - Method is used to initialize the Table and it's base module.
+
+    * get_nodes(gid, sid, did, scid, tid)
+      - Method is used to generate the browser collection node.
+
+    * node_inode()
+      - Method is overridden from its base class to make the node as leaf node.
+
+    * script_load()
+      - Load the module script for schema, when any of the server node is
+        initialized.
+    """
+    NODE_TYPE = 'table'
+    COLLECTION_LABEL = gettext("Tables")
+
+    def __init__(self, *args, **kwargs):
+        """
+        Method is used to initialize the TableModule and it's base module.
+
+        Args:
+            *args:
+            **kwargs:
+        """
+        super(TableModule, self).__init__(*args, **kwargs)
+        self.max_ver = None
+        self.min_ver = None
+
+    def get_nodes(self, gid, sid, did, scid):
+        """
+        Generate the collection node
+        """
+        yield self.generate_browser_collection_node(scid)
+
+    @property
+    def script_load(self):
+        """
+        Load the module script for database, when any of the database node is
+        initialized.
+        """
+        return database.DatabaseModule.NODE_TYPE
+
+
+blueprint = TableModule(__name__)
+
+
+class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
+    """
+    This class is responsible for generating routes for Table node
+
+    Methods:
+    -------
+    * __init__(**kwargs)
+      - Method is used to initialize the TableView and it's base view.
+
+    * module_js()
+      - This property defines (if javascript) exists for this node.
+        Override this property for your own logic
+
+    * check_precondition()
+      - This function will behave as a decorator which will checks
+        database connection before running view, it will also attaches
+        manager,conn & template_path properties to self
+
+    * list()
+      - This function is used to list all the Table nodes within that
+      collection.
+
+    * nodes()
+      - This function will used to create all the child node within that
+        collection, Here it will create all the Table node.
+
+    * properties(gid, sid, did, scid, tid)
+      - This function will show the properties of the selected Table node
+
+    * create(gid, sid, did, scid)
+      - This function will create the new Table object
+
+    * update(gid, sid, did, scid, tid)
+      - This function will update the data for the selected Table node
+
+    * delete(gid, sid, scid, tid):
+      - This function will drop the Table object
+
+    * truncate(gid, sid, scid, tid):
+      - This function will truncate table object
+
+    * set_trigger(gid, sid, scid, tid):
+      - This function will enable/disable trigger(s) on table object
+
+    * reset(gid, sid, scid, tid):
+      - This function will reset table object statistics
+
+    * msql(gid, sid, did, scid, tid)
+      - This function is used to return modified SQL for the selected
+        Table node
+
+    * get_sql(data, scid, tid)
+      - This function will generate sql from model data
+
+    * sql(gid, sid, did, scid, tid):
+      - This function will generate sql to show it in sql pane for the
+        selected Table node.
+
+    * dependency(gid, sid, did, scid, tid):
+      - This function will generate dependency list show it in dependency
+        pane for the selected Table node.
+
+    * dependent(gid, sid, did, scid, tid):
+      - This function will generate dependent list to show it in dependent
+        pane for the selected node.
+
+    * _formatter(data, tid)
+      - It will return formatted output of query result
+        as per client model format
+
+    * get_types(self, gid, sid, did, scid)
+      - This function will return list of types available for columns node
+        via AJAX response
+
+    * get_oftype(self, gid, sid, did, scid, tid)
+      - This function will return list of types available for table node
+        via AJAX response
+
+    * get_inherits(self, gid, sid, did, scid, tid)
+      - This function will return list of tables availablefor inheritance
+        via AJAX response
+
+    * get_relations(self, gid, sid, did, scid, tid)
+      - This function will return list of tables available for like/relation
+        via AJAX response
+
+    * get_columns(gid, sid, did, scid, foid=None):
+      - Returns the Table Columns.
+
+    * get_table_vacuum(gid, sid, did, scid=None, tid=None):
+      - Fetch the default values for table auto-vacuum
+
+    * get_toast_table_vacuum(gid, sid, did, scid=None, tid=None)
+      - Fetch the default values for toast table auto-vacuum
+
+    * _columns_formatter(tid, data):
+      - It will return formatted output of query result
+        as per client model format for column node
+
+    * _index_constraints_formatter(self, tid, data):
+      - It will return formatted output of query result
+        as per client model format for index constraint node
+
+    * _cltype_formatter(self, type):
+      - We need to remove [] from type and append it
+        after length/precision so we will set flag for
+        sql template
+
+    * _parse_format_columns(self, data, mode=None):
+       - This function will parse and return formatted list of columns
+         added by user
+
+    * get_index_constraint_sql(self, tid, data):
+      - This function will generate modified sql for index constraints
+        (Primary Key & Unique)
+
+    * select_sql(gid, sid, did, scid, foid):
+      - Returns sql for Script
+
+    * insert_sql(gid, sid, did, scid, foid):
+      - Returns sql for Script
+
+    * update_sql(gid, sid, did, scid, foid):
+      - Returns sql for Script
+
+    * delete_sql(gid, sid, did, scid, foid):
+      - Returns sql for Script
+"""
+
+    node_type = blueprint.node_type
+
+    parent_ids = [
+            {'type': 'int', 'id': 'gid'},
+            {'type': 'int', 'id': 'sid'},
+            {'type': 'int', 'id': 'did'},
+            {'type': 'int', 'id': 'scid'}
+            ]
+    ids = [
+            {'type': 'int', 'id': 'tid'}
+            ]
+
+    operations = dict({
+        'obj': [
+            {'get': 'properties', 'delete': 'delete', 'put': 'update'},
+            {'get': 'list', 'post': 'create'}
+        ],
+        'delete': [{'delete': 'delete'}],
+        'children': [{'get': 'children'}],
+        'nodes': [{'get': 'node'}, {'get': 'nodes'}],
+        'sql': [{'get': 'sql'}],
+        'msql': [{'get': 'msql'}, {'get': 'msql'}],
+        'stats': [{'get': 'statistics'}],
+        'dependency': [{'get': 'dependencies'}],
+        'dependent': [{'get': 'dependents'}],
+        'module.js': [{}, {}, {'get': 'module_js'}],
+        'get_oftype': [{'get': 'get_oftype'}, {'get': 'get_oftype'}],
+        'get_inherits': [{'get': 'get_inherits'}, {'get': 'get_inherits'}],
+        'get_relations': [{'get': 'get_relations'}, {'get': 'get_relations'}],
+        'truncate': [{'put': 'truncate'}],
+        'reset': [{'delete': 'reset'}],
+        'set_trigger': [{'put': 'enable_disable_triggers'}],
+        'get_types': [{'get': 'types'}, {'get': 'types'}],
+        'get_columns': [{'get': 'get_columns'}, {'get': 'get_columns'}],
+        'get_table_vacuum': [{}, {'get': 'get_table_vacuum'}],
+        'get_toast_table_vacuum': [{}, {'get': 'get_toast_table_vacuum'}],
+        'all_tables': [{}, {'get': 'get_all_tables'}],
+        'get_access_methods': [{}, {'get': 'get_access_methods'}],
+        'get_oper_class': [{}, {'get': 'get_oper_class'}],
+        'get_operator': [{}, {'get': 'get_operator'}],
+        'select_sql': [{'get': 'select_sql'}],
+        'insert_sql': [{'get': 'insert_sql'}],
+        'update_sql': [{'get': 'update_sql'}],
+        'delete_sql': [{'get': 'delete_sql'}]
+
+    })
+
+    def check_precondition(f):
+        """
+        This function will behave as a decorator which will checks
+        database connection before running view, it will also attaches
+        manager,conn & template_path properties to self
+        """
+        @wraps(f)
+        def wrap(*args, **kwargs):
+            # Here args[0] will hold self & kwargs will hold gid,sid,did
+            self = args[0]
+            driver = get_driver(PG_DEFAULT_DRIVER)
+            self.manager = driver.connection_manager(kwargs['sid'])
+            self.conn = self.manager.connection(did=kwargs['did'])
+            self.qtIdent = driver.qtIdent
+            # We need datlastsysoid to check if current table is system table
+            self.datlastsysoid = self.manager.db_info[kwargs['did']]['datlastsysoid']
+
+            # If DB not connected then return error to browser
+            if not self.conn.connected():
+                return precondition_required(
+                    gettext(
+                            "Connection to the server has been lost!"
+                    )
+                )
+
+            # We need datlastsysoid to check if current index is system index
+            self.datlastsysoid = self.manager.db_info[kwargs['did']]['datlastsysoid']
+
+            # we will set template path for sql scripts
+            ver = self.manager.version
+            # Template for Column node
+            if ver >= 90500:
+                self.template_path = 'table/sql/9.5_plus'
+            else:
+                self.template_path = 'table/sql/9.1_plus'
+
+            # Template for Column ,check constraint and exclusion constraint node
+            if ver >= 90200:
+                self.column_template_path = 'column/sql/9.2_plus'
+                self.check_constraint_template_path = 'check_constraint/sql/9.2_plus'
+                self.exclusion_constraint_template_path = 'exclusion_constraint/sql/9.2_plus'
+            else:
+                self.column_template_path = 'column/sql/9.1_plus'
+                self.check_constraint_template_path = 'check_constraint/sql/9.1_plus'
+                self.exclusion_constraint_template_path = 'exclusion_constraint/sql/9.1_plus'
+
+            # Template for PK & Unique constraint node
+            self.index_constraint_template_path = 'index_constraint/sql'
+
+            # Template for foreign key constraint node
+            self.foreign_key_template_path = 'foreign_key/sql'
+
+            # Template for index node
+            self.index_template_path = 'index/sql/9.1_plus'
+
+            # Template for trigger node
+            self.trigger_template_path = 'trigger/sql/9.1_plus'
+
+            # Template for rules node
+            self.rules_template_path = 'rules/sql'
+
+            # Supported ACL for table
+            self.acl = ['a', 'r', 'w', 'd', 'D', 'x', 't']
+
+            # Supported ACL for columns
+            self.column_acl = ['a', 'r', 'w', 'x']
+
+            return f(*args, **kwargs)
+
+        return wrap
+
+    @check_precondition
+    def list(self, gid, sid, did, scid):
+        """
+        This function is used to list all the table nodes within that collection.
+
+        Args:
+            gid: Server group ID
+            sid: Server ID
+            did: Database ID
+            scid: Schema ID
+
+        Returns:
+            JSON of available table nodes
+        """
+        SQL = render_template("/".join([self.template_path,
+                                        'properties.sql']),
+                              scid=scid, datlastsysoid=self.datlastsysoid)
+        status, res = self.conn.execute_dict(SQL)
+
+        if not status:
+            return internal_server_error(errormsg=res)
+        return ajax_response(
+                response=res['rows'],
+                status=200
+                )
+
+    @check_precondition
+    def nodes(self, gid, sid, did, scid):
+        """
+        This function is used to list all the table nodes within that collection.
+
+        Args:
+            gid: Server group ID
+            sid: Server ID
+            did: Database ID
+            scid: Schema ID
+
+        Returns:
+            JSON of available table nodes
+        """
+        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=rset)
+
+        for row in rset['rows']:
+            res.append(
+                    self.blueprint.generate_browser_node(
+                        row['oid'],
+                        scid,
+                        row['name'],
+                        icon="icon-table",
+                        tigger_count=row['triggercount'],
+                        has_enable_triggers=row['has_enable_triggers']
+                    ))
+
+        return make_json_response(
+                data=res,
+                status=200
+                )
+
+    @check_precondition
+    def get_all_tables(self, gid, sid, did, scid, tid=None):
+        """
+        Args:
+            gid: Server Group Id
+            sid: Server Id
+            did: Database Id
+            scid: Schema Id
+            tid: Table Id
+
+        Returns:
+            Returns the lits of tables required for constraints.
+        """
+        try:
+            SQL = render_template("/".join([self.template_path,
+                                            'get_tables_for_constraints.sql']),
+                                  show_sysobj=self.blueprint.show_system_objects)
+
+            status, res = self.conn.execute_dict(SQL)
+
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            return make_json_response(
+                data=res['rows'],
+                status=200
+            )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def get_table_vacuum(self, gid, sid, did, scid=None, tid=None):
+        """
+        Fetch the default values for table auto-vacuum
+        fields, return an array of
+          - label
+          - name
+          - setting
+        values
+        """
+        res = self.get_vacuum_table_settings(self.conn)
+        return ajax_response(
+            response=res['rows'],
+            status=200
+            )
+
+    @check_precondition
+    def get_toast_table_vacuum(self, gid, sid, did, scid=None, tid=None):
+        """
+        Fetch the default values for toast table auto-vacuum
+        fields, return an array of
+          - label
+          - name
+          - setting
+        values
+        """
+        res = self.get_vacuum_toast_settings(self.conn)
+        return ajax_response(
+            response=res['rows'],
+            status=200
+            )
+
+    @check_precondition
+    def get_access_methods(self, gid, sid, did, scid, tid=None):
+        """
+        This function returns access methods.
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          exid: Exclusion constraint ID
+
+        Returns:
+
+        """
+        res = [{'label': '', 'value': ''}]
+        sql = render_template(
+            "/".join([self.exclusion_constraint_template_path,
+                      'get_access_methods.sql']))
+        status, rest = self.conn.execute_2darray(sql)
+
+        if not status:
+            return internal_server_error(errormsg=rest)
+
+        for row in rest['rows']:
+            res.append(
+                {'label': row['amname'], 'value': row['amname']}
+            )
+        return make_json_response(
+                data=res,
+                status=200
+                )
+
+    @check_precondition
+    def get_oper_class(self, gid, sid, did, scid, tid=None):
+        """
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          exid: Exclusion constraint ID
+
+        Returns:
+
+        """
+        data = request.args if request.args else None
+        try:
+            if data and 'indextype' in data:
+                SQL = render_template(
+                    "/".join([self.exclusion_constraint_template_path,
+                              'get_oper_class.sql']),
+                    indextype=data['indextype'])
+
+                status, res = self.conn.execute_2darray(SQL)
+
+                if not status:
+                    return internal_server_error(errormsg=res)
+                result = []
+                for row in res['rows']:
+                    result.append([row['opcname'], row['opcname']])
+                return make_json_response(
+                    data=result,
+                    status=200
+                    )
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def get_operator(self, gid, sid, did, scid, tid=None):
+        """
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          exid: Exclusion constraint ID
+
+        Returns:
+
+        """
+        data = request.args if request.args else None
+        try:
+            if data and 'col_type' in data:
+                SQL = render_template(
+                    "/".join([self.exclusion_constraint_template_path,
+                              'get_operator.sql']),
+                    type=data['col_type'],
+                    show_sysobj=self.blueprint.show_system_objects)
+
+                status, res = self.conn.execute_2darray(SQL)
+
+                if not status:
+                    return internal_server_error(errormsg=res)
+                result = []
+                for row in res['rows']:
+                    result.append([row['oprname'], row['oprname']])
+                return make_json_response(
+                    data=result,
+                    status=200
+                    )
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    def _columns_formatter(self, tid, data):
+        """
+        Args:
+            tid: Table OID
+            data: dict of query result
+
+        Returns:
+            It will return formatted output of query result
+            as per client model format for column node
+        """
+        for column in data['columns']:
+
+            # We need to format variables according to client js collection
+            if 'attoptions' in column and column['attoptions'] is not None:
+                spcoptions = []
+                for spcoption in column['attoptions']:
+                    k, v = spcoption.split('=')
+                    spcoptions.append({'name': k, 'value': v})
+
+                column['attoptions'] = spcoptions
+
+            # Need to format security labels according to client js collection
+            if 'seclabels' in column and column['seclabels'] is not None:
+                seclabels = []
+                for seclbls in column['seclabels']:
+                    k, v = seclbls.split('=')
+                    seclabels.append({'provider': k, 'label': v})
+
+                column['seclabels'] = seclabels
+
+            if 'attnum' in column and column['attnum'] is not None and \
+                    column['attnum'] > 0:
+                # We need to parse & convert ACL coming from database to json format
+                SQL = render_template("/".join([self.column_template_path, 'acl.sql']),
+                                      tid=tid, clid=column['attnum'])
+                status, acl = self.conn.execute_dict(SQL)
+
+                if not status:
+                    return internal_server_error(errormsg=acl)
+
+                # We will set get privileges from acl sql so we don't need
+                # it from properties sql
+                column['attacl'] = []
+
+                for row in acl['rows']:
+                    priv = parse_priv_from_db(row)
+                    column.setdefault(row['deftype'], []).append(priv)
+
+                # we are receiving request when in edit mode
+                # we will send filtered types related to current type
+                present_type = column['cltype']
+
+                type_id = column['atttypid']
+
+                fulltype = self.get_full_type(
+                    column['typnspname'], column['typname'],
+                    column['isdup'], column['attndims'], column['atttypmod']
+                )
+
+                import re
+                # If we have length & precision both
+                matchObj = re.search(r'(\d+),(\d+)', fulltype)
+                if matchObj:
+                    column['attlen'] = matchObj.group(1)
+                    column['attprecision'] = matchObj.group(2)
+                else:
+                    # If we have length only
+                    matchObj = re.search(r'(\d+)', fulltype)
+                    if matchObj:
+                        column['attlen'] = matchObj.group(1)
+                        column['attprecision'] = None
+                    else:
+                        column['attlen'] = None
+                        column['attprecision'] = None
+
+                SQL = render_template("/".join([self.column_template_path,
+                                                'is_referenced.sql']),
+                                      tid=tid, clid=column['attnum'])
+
+                status, is_reference = self.conn.execute_scalar(SQL)
+
+                edit_types_list = list()
+                # We will need present type in edit mode
+                edit_types_list.append(present_type)
+
+                if int(is_reference) == 0:
+                    SQL = render_template("/".join([self.column_template_path,
+                                                    'edit_mode_types.sql']),
+                                          type_id=type_id)
+                    status, rset = self.conn.execute_2darray(SQL)
+
+                    for row in rset['rows']:
+                        edit_types_list.append(row['typname'])
+                else:
+                    edit_types_list.append(present_type)
+
+                column['edit_types'] = edit_types_list
+
+                # Manual Data type formatting
+                # If data type has () with them then we need to remove them
+                # eg bit(1) because we need to match the name with combobox
+                isArray = False
+                if column['cltype'].endswith('[]'):
+                    isArray = True
+                    column['cltype'] = column['cltype'].rstrip('[]')
+
+                idx = column['cltype'].find('(')
+                if idx and column['cltype'].endswith(')'):
+                    column['cltype'] = column['cltype'][:idx]
+
+                if isArray:
+                    column['cltype'] += "[]"
+
+                if 'indkey' in column:
+                    # Current column
+                    attnum = str(column['attnum'])
+
+                    # Single/List of primary key column(s)
+                    indkey = str(column['indkey'])
+
+                    # We will check if column is in primary column(s)
+                    if attnum in indkey.split(" "):
+                        column['is_primary_key'] = True
+                    else:
+                        column['is_primary_key'] = False
+
+        return data
+
+    def _index_constraints_formatter(self, tid, data):
+        """
+        Args:
+            tid: Table OID
+            data: dict of query result
+
+        Returns:
+            It will return formatted output of query result
+            as per client model format for index constraint node
+        """
+
+        # We will fetch all the index constraints for the table
+        index_constraints = {
+            'p': 'primary_key', 'u': 'unique_constraint'
+        }
+
+        for ctype in index_constraints.keys():
+            data[index_constraints[ctype]] = []
+
+            sql = render_template("/".join([self.index_constraint_template_path,
+                                            'properties.sql']),
+                                  tid=tid,
+                                  constraint_type=ctype)
+            status, res = self.conn.execute_dict(sql)
+
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            for row in res['rows']:
+                result = row
+                sql = render_template(
+                    "/".join([self.index_constraint_template_path,
+                              'get_constraint_cols.sql']),
+                    cid=row['oid'],
+                    colcnt=row['indnatts'])
+                status, res = self.conn.execute_dict(sql)
+
+                if not status:
+                    return internal_server_error(errormsg=res)
+
+                columns = []
+                for r in res['rows']:
+                    columns.append({"column":   r['column'].strip('"')})
+
+                result['columns'] = columns
+
+                # If not exists then create list and/or append into
+                # existing list [ Adding into main data dict]
+                data.setdefault(index_constraints[ctype], []).append(result)
+
+        return data
+
+    def _foreign_key_formatter(self, tid, data):
+        """
+        Args:
+            tid: Table OID
+            data: dict of query result
+
+        Returns:
+            It will return formatted output of query result
+            as per client model format for foreign key constraint node
+        """
+
+        # We will fetch all the index constraints for the table
+        sql = render_template("/".join([self.foreign_key_template_path,
+                                        'properties.sql']),
+                                  tid=tid)
+
+        status, result = self.conn.execute_dict(sql)
+
+        if not status:
+            return internal_server_error(errormsg=result)
+
+        for fk in result['rows']:
+
+            sql = render_template("/".join([self.foreign_key_template_path,
+                                        'get_constraint_cols.sql']),
+                              tid=tid,
+                              keys=zip(fk['confkey'], fk['conkey']),
+                              confrelid=fk['confrelid'])
+
+            status, res = self.conn.execute_dict(sql)
+
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            columns = []
+            cols = []
+            for row in res['rows']:
+                columns.append({"local_column": row['conattname'],
+                                "references": fk['confrelid'],
+                                "referenced": row['confattname']})
+                cols.append(row['conattname'])
+
+            fk['columns'] = columns
+
+            SQL = render_template("/".join([self.foreign_key_template_path,
+                                            'get_parent.sql']),
+                                  tid=fk['columns'][0]['references'])
+
+            status, rset = self.conn.execute_2darray(SQL)
+            if not status:
+                return internal_server_error(errormsg=rset)
+
+            fk['remote_schema'] = rset['rows'][0]['schema']
+            fk['remote_table'] = rset['rows'][0]['table']
+
+            coveringindex = self.search_coveringindex(tid, cols)
+
+            fk['coveringindex'] = coveringindex
+            if coveringindex:
+                fk['autoindex'] = True
+                fk['hasindex'] = True
+            else:
+                fk['autoindex'] = False
+                fk['hasindex'] = False
+            # If not exists then create list and/or append into
+            # existing list [ Adding into main data dict]
+            data.setdefault('foreign_key', []).append(fk)
+
+        return data
+
+    def _check_constraint_formatter(self, tid, data):
+        """
+        Args:
+            tid: Table OID
+            data: dict of query result
+
+        Returns:
+            It will return formatted output of query result
+            as per client model format for check constraint node
+        """
+
+        # We will fetch all the index constraints for the table
+        SQL = render_template("/".join([self.check_constraint_template_path,
+                                        'properties.sql']),
+                              tid=tid)
+
+        status, res = self.conn.execute_dict(SQL)
+
+        if not status:
+            return internal_server_error(errormsg=res)
+        # If not exists then create list and/or append into
+        # existing list [ Adding into main data dict]
+
+        data['check_constraint'] = res['rows']
+
+        return data
+
+    def _exclusion_constraint_formatter(self, tid, data):
+        """
+        Args:
+            tid: Table OID
+            data: dict of query result
+
+        Returns:
+            It will return formatted output of query result
+            as per client model format for exclusion constraint node
+        """
+
+        # We will fetch all the index constraints for the table
+        sql = render_template("/".join([self.exclusion_constraint_template_path,
+                                        'properties.sql']),
+                              tid=tid)
+
+        status, result = self.conn.execute_dict(sql)
+
+        if not status:
+            return internal_server_error(errormsg=result)
+
+        for ex in result['rows']:
+
+            sql = render_template("/".join([self.exclusion_constraint_template_path,
+                                            'get_constraint_cols.sql']),
+                                  cid=ex['oid'],
+                                  colcnt=ex['indnatts'])
+
+            status, res = self.conn.execute_dict(sql)
+
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            columns = []
+            for row in res['rows']:
+                if row['options'] & 1:
+                    order = False
+                    nulls_order = True if (row['options'] & 2) else False
+                else:
+                    order = True
+                    nulls_order = True if (row['options'] & 2) else False
+
+                columns.append({"column": row['coldef'].strip('"'),
+                                "oper_class": row['opcname'],
+                                "order": order,
+                                "nulls_order": nulls_order,
+                                "operator": row['oprname'],
+                                "col_type": row['datatype']
+                                })
+
+            ex['columns'] = columns
+            # If not exists then create list and/or append into
+            # existing list [ Adding into main data dict]
+            data.setdefault('exclude_constraint', []).append(ex)
+
+        return data
+
+    def search_coveringindex(self, tid, cols):
+        """
+
+        Args:
+          tid: Table id
+          cols: column list
+
+        Returns:
+
+        """
+
+        cols = set(cols)
+        SQL = render_template("/".join([self.foreign_key_template_path,
+                                        'get_constraints.sql']),
+                              tid=tid)
+        status, constraints = self.conn.execute_dict(SQL)
+
+        if not status:
+            raise Exception(constraints)
+
+        for costrnt in constraints['rows']:
+
+            sql = render_template(
+                "/".join([self.foreign_key_template_path, 'get_cols.sql']),
+                cid=costrnt['oid'],
+                colcnt=costrnt['indnatts'])
+            status, rest = self.conn.execute_dict(sql)
+
+            if not status:
+                return internal_server_error(errormsg=rest)
+
+            indexcols = set()
+            for r in rest['rows']:
+                indexcols.add(r['column'].strip('"'))
+
+            if len(cols - indexcols) == len(indexcols - cols) == 0:
+                return costrnt["idxname"]
+
+        return None
+
+    def _formatter(self, scid, tid, data):
+        """
+        Args:
+            data: dict of query result
+            scid: schema oid
+            tid: table oid
+
+        Returns:
+            It will return formatted output of query result
+            as per client model format
+        """
+        # Need to format security labels according to client js collection
+        if 'seclabels' in data and data['seclabels'] is not None:
+            seclabels = []
+            for seclbls in data['seclabels']:
+                k, v = seclbls.split('=')
+                seclabels.append({'provider': k, 'label': v})
+
+            data['seclabels'] = seclabels
+
+        # We need to parse & convert ACL coming from database to json format
+        SQL = render_template("/".join([self.template_path, 'acl.sql']),
+                              tid=tid, scid=scid)
+        status, acl = self.conn.execute_dict(SQL)
+        if not status:
+            return internal_server_error(errormsg=acl)
+
+        # We will set get privileges from acl sql so we don't need
+        # it from properties sql
+        for row in acl['rows']:
+            priv = parse_priv_from_db(row)
+            if row['deftype'] in data:
+                data[row['deftype']].append(priv)
+            else:
+                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')
+
+        # Fetch columns for the table logic
+        #
+        # 1) Check if of_type and inherited tables are present?
+        # 2) If yes then Fetch all the columns for of_type and inherited tables
+        # 3) Add columns in columns collection
+        # 4) Find all the columns for tables and filter out columns which are
+        #   not inherited from any table & format them one by one
+
+        # Get of_type table columns and add it into columns dict
+        if data['typname']:
+            SQL = render_template("/".join([self.template_path,
+                                            'get_columns_for_table.sql']),
+                                  tname=data['typname'])
+
+            status, res = self.conn.execute_dict(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+            data['columns'] = res['rows']
+
+        # Get inherited table(s) columns and add it into columns dict
+        elif data['coll_inherits'] and len(data['coll_inherits']) > 0:
+            columns = []
+            # Return all tables which can be inherited & do not show
+            # system columns
+            SQL = render_template("/".join([self.template_path, 'get_inherits.sql']),
+                                  show_system_objects=False
+                                  )
+            status, rset = self.conn.execute_2darray(SQL)
+            if not status:
+                return internal_server_error(errormsg=rset)
+
+            for row in rset['rows']:
+                if row['inherits'] in data['coll_inherits']:
+                    # Fetch columns using inherited table OID
+                    SQL = render_template("/".join([self.template_path,
+                                                    'get_columns_for_table.sql']),
+                                          tid=row['oid'])
+                    status, res = self.conn.execute_dict(SQL)
+                    if not status:
+                        return internal_server_error(errormsg=res)
+                    columns.extend(res['rows'][:])
+            data['columns'] = columns
+
+        # We will fetch all the columns for the table using
+        # columns properties.sql, so we need to set template path
+        SQL = render_template("/".join([self.column_template_path,
+                                        'properties.sql']),
+                              tid=tid,
+                              show_sys_objects=False
+                              )
+
+        status, res = self.conn.execute_dict(SQL)
+        if not status:
+            return internal_server_error(errormsg=res)
+        all_columns = res['rows']
+
+        # Filter inherited columns from all columns
+        if 'columns' in data and len(data['columns']) > 0 \
+            and len(all_columns) > 0:
+            columns = []
+            for row in data['columns']:
+                for i, col in enumerate(all_columns):
+                    # If both name are same then remove it
+                    # as it is inherited from other table
+                    if col['name'] == row['name']:
+                        # Remove same column from all_columns as
+                        # already have it columns collection
+                        del all_columns[i]
+
+            # If any column is added then update columns collection
+            if len(all_columns) > 0:
+                data['columns'] += all_columns
+        # If no inherited columns found then add all columns
+        elif len(all_columns) > 0:
+            data['columns'] = all_columns
+
+        if 'columns' in data and len(data['columns']) > 0:
+            data = self._columns_formatter(tid, data)
+
+        # Here we will add constraint in our output
+        data = self._index_constraints_formatter(tid, data)
+        data = self._foreign_key_formatter(tid, data)
+        data = self._check_constraint_formatter(tid, data)
+        data = self._exclusion_constraint_formatter(tid, data)
+
+        return data
+
+    @check_precondition
+    def properties(self, gid, sid, did, scid, tid):
+        """
+        This function will show the properties of the selected table node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did:  Database ID
+            scid: Schema ID
+            scid: Schema ID
+            tid: Table ID
+
+        Returns:
+            JSON of selected table node
+        """
+
+        SQL = render_template("/".join([self.template_path,
+                                        'properties.sql']),
+                              scid=scid, tid=tid,
+                              datlastsysoid=self.datlastsysoid)
+        status, res = self.conn.execute_dict(SQL)
+        if not status:
+            return internal_server_error(errormsg=res)
+        data = res['rows'][0]
+
+        data['vacuum_settings_str'] = ""
+
+        if data['table_vacuum_settings_str'] is not None:
+            data['vacuum_settings_str'] += data[
+                'table_vacuum_settings_str'].replace(',', '\n')
+
+        if data['toast_table_vacuum_settings_str'] is not None:
+            data['vacuum_settings_str'] += '\n' + '\n'.join(
+                    ['toast_' + setting for setting in data[
+                        'toast_table_vacuum_settings_str'
+                    ].split(',')]
+                )
+        data['vacuum_settings_str'] = data[
+            'vacuum_settings_str'
+        ].replace("=", " = ")
+
+        data = self._formatter(scid, tid, data)
+
+        return ajax_response(
+                response=data,
+                status=200
+                )
+
+    @check_precondition
+    def types(self, gid, sid, did, scid, tid=None, clid=None):
+        """
+        Returns:
+            This function will return list of types available for column node
+            for node-ajax-control
+        """
+        condition = render_template("/".join([self.template_path,
+                                              'get_types_where_condition.sql']),
+                                    show_system_objects=self.blueprint.show_system_objects)
+
+        status, types = self.get_types(self.conn, condition)
+
+        if not status:
+            return internal_server_error(errormsg=types)
+
+        return make_json_response(
+            data=types,
+            status=200
+        )
+
+    @check_precondition
+    def get_columns(self, gid, sid, did, scid, tid=None):
+        """
+        Returns the Table Columns.
+
+        Args:
+            gid: Server Group Id
+            sid: Server Id
+            did: Database Id
+            scid: Schema Id
+            tid: Table Id
+
+        Returns:
+              JSON Array with below parameters.
+              name: Column Name
+              ctype: Column Data Type
+              inherited_from: Parent Table from which the related column
+                              is inheritted.
+        """
+        res = []
+        data = request.args if request.args else None
+        try:
+            if data and 'tid' in data:
+                SQL = render_template("/".join([self.template_path,
+                                                'get_columns_for_table.sql']),
+                                      tid=data['tid'])
+            elif data and 'tname' in data:
+                SQL = render_template("/".join([self.template_path,
+                                                'get_columns_for_table.sql']),
+                                      tname=data['tname'])
+
+            if SQL:
+                status, res = self.conn.execute_dict(SQL)
+                if not status:
+                    return internal_server_error(errormsg=res)
+                res = res['rows']
+
+            return make_json_response(
+                data=res,
+                status=200
+            )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def get_oftype(self, gid, sid, did, scid, tid=None):
+        """
+        Returns:
+            This function will return list of types available for table node
+            for node-ajax-control
+        """
+        res = [{'label': '', 'value': ''}]
+        try:
+            SQL = render_template("/".join([self.template_path,
+                                            'get_oftype.sql']), scid=scid)
+            status, rset = self.conn.execute_2darray(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+            for row in rset['rows']:
+                res.append(
+                            {'label': row['typname'], 'value': row['typname'],
+                             'tid': row['oid']
+                             }
+                        )
+            return make_json_response(
+                    data=res,
+                    status=200
+                    )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def get_inherits(self, gid, sid, did, scid, tid=None):
+        """
+        Returns:
+            This function will return list of tables available for inheritance
+            while creating new table
+        """
+        try:
+            res = []
+            SQL = render_template("/".join([self.template_path, 'get_inherits.sql']),
+                                  show_system_objects=self.blueprint.show_system_objects
+                                  )
+            status, rset = self.conn.execute_2darray(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+            for row in rset['rows']:
+                res.append(
+                            {'label': row['inherits'], 'value': row['inherits'],
+                             'tid': row['oid']
+                             }
+                        )
+            return make_json_response(
+                    data=res,
+                    status=200
+                    )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def get_relations(self, gid, sid, did, scid, tid=None):
+        """
+        Returns:
+            This function will return list of tables available for like/relation
+            combobox while creating new table
+        """
+        res = [{'label': '', 'value': ''}]
+        try:
+            SQL = render_template("/".join([self.template_path, 'get_relations.sql']))
+            status, rset = self.conn.execute_2darray(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+            for row in rset['rows']:
+                res.append(
+                            {'label': row['like_relation'], 'value': row['like_relation']}
+                        )
+            return make_json_response(
+                    data=res,
+                    status=200
+                    )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    def _cltype_formatter(self, type):
+        """
+
+        Args:
+            data: Type string
+
+        Returns:
+            We need to remove [] from type and append it
+            after length/precision so we will set flag for
+            sql template
+        """
+        if '[]' in type:
+            type = type.replace('[]', '')
+            self.hasSqrBracket = True
+        else:
+            self.hasSqrBracket = False
+
+        return type
+
+    def _parse_format_columns(self, data, mode=None):
+        """
+        data:
+            Data coming from client side
+
+        Returns:
+            This function will parse and return formatted list of columns
+            added by user
+        """
+        columns = data['columns']
+        # 'EDIT' mode
+        if mode is not None:
+            for action in ['added', 'changed']:
+                if action in columns:
+                    final_columns = []
+                    for c in columns[action]:
+                        if 'inheritedfrom' not in c:
+                            final_columns.append(c)
+
+                    for c in final_columns:
+                        if 'attacl' in c:
+                            c['attacl'] = parse_priv_to_db(c['attacl'], self.column_acl)
+
+                        # check type for '[]' in it
+                        c['cltype'] = self._cltype_formatter(c['cltype'])
+                        c['hasSqrBracket'] = self.hasSqrBracket
+
+                    data['columns'][action] = final_columns
+        else:
+            # We need to exclude all the columns which are inherited from other tables
+            # 'CREATE' mode
+            final_columns = []
+
+            for c in columns:
+                if 'inheritedfrom' not in c:
+                    final_columns.append(c)
+
+            # Now we have all lis of columns which we need
+            # to include in our create definition, Let's format them
+            for c in final_columns:
+                if 'attacl' in c:
+                    c['attacl'] = parse_priv_to_db(c['attacl'], self.column_acl)
+
+                # check type for '[]' in it
+                c['cltype'] = self._cltype_formatter(c['cltype'])
+                c['hasSqrBracket'] = self.hasSqrBracket
+
+            data['columns'] = final_columns
+
+        return data
+
+    @check_precondition
+    def create(self, gid, sid, did, scid):
+        """
+        This function will creates new the table object
+
+         Args:
+           gid: Server Group ID
+           sid: Server ID
+           did: Database ID
+           scid: Schema ID
+        """
+        data = request.form if request.form else json.loads(request.data.decode())
+
+        for k, v in data.items():
+            try:
+                data[k] = json.loads(v)
+            except (ValueError, TypeError):
+                data[k] = v
+
+        required_args = [
+            'name'
+        ]
+
+        for arg in required_args:
+            if arg not in data:
+                return make_json_response(
+                    status=410,
+                    success=0,
+                    errormsg=gettext(
+                        "Couldn't find the required parameter (%s)." % arg
+                    )
+                )
+
+        # Parse privilege data coming from client according to database format
+        if 'relacl' in data:
+            data['relacl'] = parse_priv_to_db(data['relacl'], self.acl)
+
+        # Parse & format columns
+        data = self._parse_format_columns(data)
+
+        # 'coll_inherits' is Array but it comes as string from browser
+        # We will convert it again to list
+        if 'coll_inherits' in data and \
+                isinstance(data['coll_inherits'], str):
+            data['coll_inherits'] = json.loads(data['coll_inherits'])
+
+        if 'foreign_key' in data:
+            for c in data['foreign_key']:
+                SQL = render_template("/".join([self.foreign_key_template_path,
+                                                'get_parent.sql']),
+                                      tid=c['columns'][0]['references'])
+                status, rset = self.conn.execute_2darray(SQL)
+                if not status:
+                    return internal_server_error(errormsg=rset)
+
+                c['remote_schema'] = rset['rows'][0]['schema']
+                c['remote_table'] = rset['rows'][0]['table']
+
+        try:
+            SQL = render_template("/".join([self.template_path,
+                                            'create.sql']),
+                                  data=data, conn=self.conn)
+            status, res = self.conn.execute_scalar(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            # we need oid to to add object in tree at browser
+            SQL = render_template("/".join([self.template_path,
+                                            'get_oid.sql']), scid=scid, data=data)
+            status, tid = self.conn.execute_scalar(SQL)
+            if not status:
+                return internal_server_error(errormsg=tid)
+
+            return jsonify(
+                node=self.blueprint.generate_browser_node(
+                    tid,
+                    scid,
+                    data['name'],
+                    icon="icon-table"
+                )
+            )
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def update(self, gid, sid, did, scid, tid):
+        """
+        This function will update an existing table object
+
+         Args:
+           gid: Server Group ID
+           sid: Server ID
+           did: Database ID
+           scid: Schema ID
+           tid: Table ID
+        """
+        data = request.form if request.form else json.loads(
+            request.data.decode()
+        )
+
+        for k, v in data.items():
+            try:
+                data[k] = json.loads(v)
+            except (ValueError, TypeError):
+                data[k] = v
+
+        try:
+            SQL = self.get_sql(scid, tid, data)
+
+            if SQL and SQL.strip('\n') and SQL.strip(' '):
+                status, res = self.conn.execute_scalar(SQL)
+                if not status:
+                    return internal_server_error(errormsg=res)
+
+                return make_json_response(
+                    success=1,
+                    info="Table updated",
+                    data={
+                        'id': tid,
+                        'scid': scid,
+                        'did': did
+                    }
+                )
+            else:
+                return make_json_response(
+                    success=1,
+                    info="Nothing to update",
+                    data={
+                        'id': tid,
+                        'scid': scid,
+                        'did': did
+                    }
+                )
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def delete(self, gid, sid, did, scid, tid):
+        """
+        This function will deletes the table object
+
+         Args:
+           gid: Server Group ID
+           sid: Server ID
+           did: Database ID
+           scid: Schema ID
+           tid: Table ID
+        """
+        # Below will decide if it's simple drop or drop with cascade call
+        if self.cmd == 'delete':
+            # This is a cascade operation
+            cascade = True
+        else:
+            cascade = False
+
+        try:
+            SQL = render_template("/".join([self.template_path,
+                                            'properties.sql']),
+                                  scid=scid, tid=tid,
+                                  datlastsysoid=self.datlastsysoid)
+            status, res = self.conn.execute_dict(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+            data = res['rows'][0]
+
+            SQL = render_template("/".join([self.template_path,
+                                            'delete.sql']),
+                                  data=data, cascade=cascade,
+                                  conn=self.conn)
+            status, res = self.conn.execute_scalar(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            return make_json_response(
+                success=1,
+                info=gettext("Table dropped"),
+                data={
+                    'id': tid,
+                    'scid': scid
+                }
+            )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def truncate(self, gid, sid, did, scid, tid):
+        """
+        This function will truncate the table object
+
+         Args:
+           gid: Server Group ID
+           sid: Server ID
+           did: Database ID
+           scid: Schema ID
+           tid: Table ID
+        """
+        # Below will decide if it's simple drop or drop with cascade call
+        data = request.form if request.form else json.loads(request.data.decode())
+        # Convert str 'true' to boolean type
+        is_cascade = json.loads(data['cascade'])
+
+        try:
+            SQL = render_template("/".join([self.template_path,
+                                            'properties.sql']),
+                                  scid=scid, tid=tid,
+                                  datlastsysoid=self.datlastsysoid)
+            status, res = self.conn.execute_dict(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+            data = res['rows'][0]
+
+            SQL = render_template("/".join([self.template_path,
+                                            'truncate.sql']),
+                                  data=data, cascade=is_cascade)
+            status, res = self.conn.execute_scalar(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            return make_json_response(
+                success=1,
+                info=gettext("Table truncated"),
+                data={
+                    'id': tid,
+                    'scid': scid
+                }
+            )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def enable_disable_triggers(self, gid, sid, did, scid, tid):
+        """
+        This function will enable/disable trigger(s) on the table object
+
+         Args:
+           gid: Server Group ID
+           sid: Server ID
+           did: Database ID
+           scid: Schema ID
+           tid: Table ID
+        """
+        # Below will decide if it's simple drop or drop with cascade call
+        data = request.form if request.form else json.loads(request.data.decode())
+        # Convert str 'true' to boolean type
+        is_enable = json.loads(data['enable'])
+
+        try:
+            SQL = render_template("/".join([self.template_path,
+                                            'properties.sql']),
+                                  scid=scid, tid=tid,
+                                  datlastsysoid=self.datlastsysoid)
+            status, res = self.conn.execute_dict(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+            data = res['rows'][0]
+            # TODO://
+            # Find SQL which can enable all or disable all triggers
+            SQL = render_template("/".join([self.template_path,
+                                            'enable_disable_trigger.sql']),
+                                  data=data, is_enable_trigger=is_enable)
+            status, res = self.conn.execute_scalar(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            return make_json_response(
+                success=1,
+                info=gettext("Trigger(s) has been enabled") if is_enable
+                else gettext("Trigger(s) has been disabled"),
+                data={
+                    'id': tid,
+                    'scid': scid
+                }
+            )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def reset(self, gid, sid, did, scid, tid):
+        """
+        This function will reset statistics of table
+
+         Args:
+           gid: Server Group ID
+           sid: Server ID
+           did: Database ID
+           scid: Schema ID
+           tid: Table ID
+        """
+        try:
+            SQL = render_template("/".join([self.template_path,
+                                            'reset_stats.sql']),
+                                  tid=tid)
+            status, res = self.conn.execute_scalar(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            return make_json_response(
+                success=1,
+                info=gettext("Table statistics has been reset"),
+                data={
+                    'id': tid,
+                    'scid': scid
+                }
+            )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def msql(self, gid, sid, did, scid, tid=None):
+        """
+        This function will create modified sql for table object
+
+         Args:
+           gid: Server Group ID
+           sid: Server ID
+           did: Database ID
+           scid: Schema ID
+           tid: Table ID
+        """
+        data = dict()
+        for k, v in request.args.items():
+            try:
+                data[k] = json.loads(v)
+            except (ValueError, TypeError):
+                data[k] = v
+
+        try:
+            SQL = self.get_sql(scid, tid, data)
+            SQL = re.sub('\n{2,}', '\n', SQL)
+            SQL = SQL.strip('\n')
+            return make_json_response(
+                data=SQL,
+                status=200
+            )
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    def get_index_constraint_sql(self, tid, data):
+        """
+         Args:
+           tid: Table ID
+           data: data dict coming from the client
+
+        Returns:
+        This function will generate modified sql for index constraints
+        (Primary Key & Unique)
+        """
+        sql = []
+        # We will fetch all the index constraints for the table
+        index_constraints = {
+            'p': 'primary_key', 'u': 'unique_constraint'
+        }
+
+        for ctype in index_constraints.keys():
+            # Check if constraint is in data
+            # If yes then we need to check for add/change/delete
+            if index_constraints[ctype] in data:
+                constraint = data[index_constraints[ctype]]
+                # If constraint(s) is/are deleted
+                if 'deleted' in constraint:
+                    for c in constraint['deleted']:
+                        c['schema'] = data['schema']
+                        c['table'] = data['name']
+
+                        # Sql for drop
+                        sql.append(
+                            render_template("/".join(
+                            [self.index_constraint_template_path,
+                             'delete.sql']),
+                                data=c, conn=self.conn).strip('\n')
+                        )
+
+                if 'changed' in constraint:
+                    for c in constraint['changed']:
+                        c['schema'] = data['schema']
+                        c['table'] = data['name']
+
+                        properties_sql = render_template("/".join(
+                            [self.index_constraint_template_path, 'properties.sql']),
+                            tid=tid, cid=c['oid'], constraint_type=ctype)
+                        status, res = self.conn.execute_dict(properties_sql)
+                        if not status:
+                            return internal_server_error(errormsg=res)
+
+                        old_data = res['rows'][0]
+                        # Sql to update object
+                        sql.append(
+                            render_template("/".join([
+                                self.index_constraint_template_path,
+                                'update.sql']), data=c, o_data=old_data,
+                                conn=self.conn).strip('\n')
+                        )
+
+                if 'added' in constraint:
+                    for c in constraint['added']:
+                        c['schema'] = data['schema']
+                        c['table'] = data['name']
+
+                        # Sql to add object
+                        if self.validate_constrains(index_constraints[ctype], c):
+                            sql.append(
+                                render_template(
+                                    "/".join([self.index_constraint_template_path,
+                                              'create.sql']),
+                                    data=c, conn=self.conn,
+                                    constraint_name='PRIMARY KEY'
+                                    if ctype == 'p' else 'UNIQUE'
+                                    ).strip('\n')
+                            )
+                            # sql to update comments
+                            sql.append(
+                                render_template(
+                                    "/".join([self.index_constraint_template_path,
+                                              'alter.sql']),
+                                    data=c, conn=self.conn
+                                    ).strip('\n')
+                            )
+                        else:
+                            sql.append(
+                                gettext(
+                                    '-- incomplete definition for {0} constraint'.format(index_constraints[ctype])
+                                )
+                            )
+        if len(sql) > 0:
+            # Join all the sql(s) as single string
+            return '\n\n'.join(sql)
+        else:
+            return None
+
+    def get_foreign_key_sql(self, tid, data):
+        """
+         Args:
+           tid: Table ID
+           data: data dict coming from the client
+
+        Returns:
+        This function will generate modified sql for foreign key
+        """
+        sql = []
+        # Check if constraint is in data
+        # If yes then we need to check for add/change/delete
+        if 'foreign_key' in data:
+            constraint = data['foreign_key']
+            # If constraint(s) is/are deleted
+            if 'deleted' in constraint:
+                for c in constraint['deleted']:
+                    c['schema'] = data['schema']
+                    c['table'] = data['name']
+
+                    # Sql for drop
+                    sql.append(
+                        render_template("/".join(
+                        [self.foreign_key_template_path,
+                         'delete.sql']),
+                            data=c, conn=self.conn).strip('\n')
+                    )
+
+            if 'changed' in constraint:
+                for c in constraint['changed']:
+                    c['schema'] = data['schema']
+                    c['table'] = data['name']
+
+                    properties_sql = render_template("/".join(
+                        [self.foreign_key_template_path, 'properties.sql']),
+                        tid=tid, cid=c['oid'])
+                    status, res = self.conn.execute_dict(properties_sql)
+                    if not status:
+                        return internal_server_error(errormsg=res)
+
+                    old_data = res['rows'][0]
+                    # Sql to update object
+                    sql.append(
+                        render_template("/".join([
+                            self.foreign_key_template_path,
+                            'update.sql']), data=c, o_data=old_data,
+                            conn=self.conn).strip('\n')
+                    )
+
+                    if not self.validate_constrains('foreign_key', c):
+                        sql.append(
+                            gettext(
+                                '-- incomplete definition for foreign_key constraint'
+                            )
+                        )
+                        return '\n\n'.join(sql)
+
+                    cols = []
+                    for col in c['columns']:
+                        cols.append(col['local_column'])
+
+                    coveringindex = self.search_coveringindex(tid, cols)
+
+                    if coveringindex is None and 'autoindex' in c and c['autoindex'] and\
+                        ('coveringindex' in c and
+                             c['coveringindex'] != ''):
+                        sql.append(render_template(
+                            "/".join([self.foreign_key_template_path, 'create_index.sql']),
+                            data=c, conn=self.conn).strip('\n')
+                        )
+
+            if 'added' in constraint:
+                for c in constraint['added']:
+                    c['schema'] = data['schema']
+                    c['table'] = data['name']
+
+                    # Sql to add object
+                    # Columns
+
+                    if not self.validate_constrains('foreign_key', c):
+                        sql.append(
+                            gettext(
+                                '-- incomplete definition for foreign_key constraint'
+                            )
+                        )
+                        return '\n\n'.join(sql)
+
+                    SQL = render_template("/".join([self.foreign_key_template_path,
+                                                    'get_parent.sql']),
+                                          tid=c['columns'][0]['references'])
+                    status, rset = self.conn.execute_2darray(SQL)
+                    if not status:
+                        return internal_server_error(errormsg=rset)
+
+                    c['remote_schema'] = rset['rows'][0]['schema']
+                    c['remote_table'] = rset['rows'][0]['table']
+
+                    sql.append(
+                        render_template(
+                            "/".join([self.foreign_key_template_path,
+                                      'create.sql']),
+                            data=c, conn=self.conn
+                            ).strip('\n')
+                    )
+                    # sql to update comments
+                    sql.append(
+                        render_template(
+                            "/".join([self.foreign_key_template_path,
+                                      'alter.sql']),
+                            data=c, conn=self.conn
+                            ).strip('\n')
+                    )
+
+                    if c['autoindex']:
+                        sql.append(
+                            render_template(
+                                "/".join([self.foreign_key_template_path,
+                                          'create_index.sql']),
+                                data=c, conn=self.conn).strip('\n')
+                        )
+
+        if len(sql) > 0:
+            # Join all the sql(s) as single string
+            return '\n\n'.join(sql)
+        else:
+            return None
+
+    def get_check_constraint_sql(self, tid, data):
+        """
+         Args:
+           tid: Table ID
+           data: data dict coming from the client
+
+        Returns:
+          This function will generate modified sql for check constraint
+        """
+        sql = []
+        # Check if constraint is in data
+        # If yes then we need to check for add/change/delete
+        if 'check_constraint' in data:
+            constraint = data['check_constraint']
+            # If constraint(s) is/are deleted
+            if 'deleted' in constraint:
+                for c in constraint['deleted']:
+                    c['schema'] = data['schema']
+                    c['table'] = data['name']
+
+                    # Sql for drop
+                    sql.append(
+                        render_template("/".join(
+                            [self.check_constraint_template_path,
+                             'delete.sql']),
+                            data=c, conn=self.conn).strip('\n')
+                    )
+
+            if 'changed' in constraint:
+                for c in constraint['changed']:
+                    c['schema'] = data['schema']
+                    c['table'] = data['name']
+
+                    properties_sql = render_template("/".join(
+                        [self.check_constraint_template_path, 'properties.sql']),
+                        tid=tid, cid=c['oid'])
+                    status, res = self.conn.execute_dict(properties_sql)
+                    if not status:
+                        return internal_server_error(errormsg=res)
+
+                    old_data = res['rows'][0]
+                    # Sql to update object
+                    sql.append(
+                        render_template("/".join([
+                            self.check_constraint_template_path,
+                            'update.sql']), data=c, o_data=old_data,
+                            conn=self.conn).strip('\n')
+                    )
+
+            if 'added' in constraint:
+                for c in constraint['added']:
+                    c['schema'] = data['schema']
+                    c['table'] = data['name']
+
+                    if not self.validate_constrains('check_constraint', c):
+                        sql.append(
+                            gettext(
+                                '-- incomplete definition for check_constraint'
+                            )
+                        )
+                        return '\n\n'.join(sql)
+
+                    sql.append(
+                        render_template(
+                            "/".join([self.check_constraint_template_path,
+                                      'create.sql']),
+                            data=c, conn=self.conn
+                            ).strip('\n')
+                    )
+                    # sql to update comments
+                    sql.append(
+                        render_template(
+                            "/".join([self.check_constraint_template_path,
+                                      'alter.sql']),
+                            data=c, conn=self.conn
+                            ).strip('\n')
+                    )
+
+        if len(sql) > 0:
+            # Join all the sql(s) as single string
+            return '\n\n'.join(sql)
+        else:
+            return None
+
+    def get_exclusion_constraint_sql(self, tid, data):
+        """
+         Args:
+           tid: Table ID
+           data: data dict coming from the client
+
+        Returns:
+          This function will generate modified sql for exclusion constraint
+        """
+        sql = []
+        # Check if constraint is in data
+        # If yes then we need to check for add/change/delete
+        if 'exclude_constraint' in data:
+            constraint = data['exclude_constraint']
+            # If constraint(s) is/are deleted
+            if 'deleted' in constraint:
+                for c in constraint['deleted']:
+                    c['schema'] = data['schema']
+                    c['table'] = data['name']
+
+                    # Sql for drop
+                    sql.append(
+                        render_template("/".join(
+                            [self.exclusion_constraint_template_path,
+                             'delete.sql']),
+                            data=c, conn=self.conn).strip('\n')
+                    )
+
+            if 'changed' in constraint:
+                for c in constraint['changed']:
+                    c['schema'] = data['schema']
+                    c['table'] = data['name']
+
+                    properties_sql = render_template("/".join(
+                        [self.exclusion_constraint_template_path, 'properties.sql']),
+                        tid=tid, cid=c['oid'])
+                    status, res = self.conn.execute_dict(properties_sql)
+                    if not status:
+                        return internal_server_error(errormsg=res)
+
+                    old_data = res['rows'][0]
+                    # Sql to update object
+                    sql.append(
+                        render_template("/".join([
+                            self.exclusion_constraint_template_path,
+                            'update.sql']), data=c, o_data=old_data,
+                            conn=self.conn).strip('\n')
+                    )
+
+            if 'added' in constraint:
+                for c in constraint['added']:
+                    c['schema'] = data['schema']
+                    c['table'] = data['name']
+
+                    if not self.validate_constrains('exclude_constraint', c):
+                        sql.append(
+                            gettext(
+                                '-- incomplete definition for exclusion_constraint'
+                            )
+                        )
+                        return '\n\n'.join(sql)
+
+                    sql.append(
+                        render_template(
+                            "/".join([self.exclusion_constraint_template_path,
+                                      'create.sql']),
+                            data=c, conn=self.conn
+                            ).strip('\n')
+                    )
+                    # sql to update comments
+                    sql.append(
+                        render_template(
+                            "/".join([self.exclusion_constraint_template_path,
+                                      'alter.sql']),
+                            data=c, conn=self.conn
+                            ).strip('\n')
+                    )
+
+        if len(sql) > 0:
+            # Join all the sql(s) as single string
+            return '\n\n'.join(sql)
+        else:
+            return None
+
+    def get_sql(self, scid, tid, data):
+        """
+        This function will generate create/update sql from model data
+        coming from client
+        """
+        if tid is not None:
+            SQL = render_template("/".join([self.template_path,
+                                            'properties.sql']),
+                                  scid=scid, tid=tid,
+                                  datlastsysoid=self.datlastsysoid)
+            status, res = self.conn.execute_dict(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            old_data = res['rows'][0]
+            old_data = self._formatter(scid, tid, old_data)
+
+            # We will convert privileges coming from client required
+            if 'relacl' in data:
+                for mode in ['added', 'changed', 'deleted']:
+                    if mode in data['relacl']:
+                        data['relacl'][mode] = parse_priv_to_db(
+                            data['relacl'][mode], self.acl
+                        )
+
+            # If name if not present
+            if 'name' not in data:
+                data['name'] = old_data['name']
+            # If name if not present
+            if 'schema' not in data:
+                data['schema'] = old_data['schema']
+
+            # Filter out new tables from list, we will send complete list
+            # and not newly added tables in the list from client
+            # so we will filter new tables here
+            if 'coll_inherits' in data:
+                p_len = len(old_data['coll_inherits'])
+                c_len = len(data['coll_inherits'])
+                # If table(s) added
+                if c_len > p_len:
+                    data['coll_inherits_added'] = list(
+                        set(data['coll_inherits']) - set(old_data['coll_inherits'])
+                    )
+                # If table(s)removed
+                elif c_len < p_len:
+                    data['coll_inherits_removed'] = list(
+                        set(old_data['coll_inherits']) - set(data['coll_inherits'])
+                    )
+                # Safe side verification,In case it happens..
+                # If user removes and adds same number of table
+                # eg removed one table and added one new table
+                elif c_len == p_len:
+                    data['coll_inherits_added'] = list(
+                        set(data['coll_inherits']) - set(old_data['coll_inherits'])
+                    )
+                    data['coll_inherits_removed'] = list(
+                        set(old_data['coll_inherits']) - set(data['coll_inherits'])
+                    )
+
+            SQL = render_template("/".join([self.template_path, 'update.sql']),
+                                  o_data=old_data, data=data, conn=self.conn)
+            # Removes training new lines
+            SQL = SQL.strip('\n') + '\n\n'
+
+            # Parse/Format columns & create sql
+            if 'columns' in data:
+                # Parse the data coming from client
+                data = self._parse_format_columns(data, mode='edit')
+
+                columns = data['columns']
+                column_sql = '\n'
+
+                # If column(s) is/are deleted
+                if 'deleted' in columns:
+                    for c in columns['deleted']:
+                        c['schema'] = data['schema']
+                        c['table'] = data['name']
+                        # Sql for drop column
+                        if 'inheritedfrom' not in c:
+                            column_sql += render_template("/".join(
+                                [self.column_template_path, 'delete.sql']),
+                                data=c, conn=self.conn).strip('\n') + '\n\n'
+
+                # If column(s) is/are changed
+                # Here we will be needing previous properties of column
+                # so that we can compare & update it
+                if 'changed' in columns:
+                    for c in columns['changed']:
+                        c['schema'] = data['schema']
+                        c['table'] = data['name']
+                        if 'attacl' in c:
+                            c['attacl'] = parse_priv_to_db(c['attacl'],
+                                                           self.column_acl)
+
+                        properties_sql = render_template("/".join([self.column_template_path,
+                                            'properties.sql']),
+                                            tid=tid,
+                                            clid=c['attnum'],
+                                            show_sys_objects=self.blueprint.show_system_objects
+                                            )
+
+                        status, res = self.conn.execute_dict(properties_sql)
+                        if not status:
+                            return internal_server_error(errormsg=res)
+                        old_data = res['rows'][0]
+
+                        old_data['cltype'] = self._cltype_formatter(old_data['cltype'])
+                        old_data['hasSqrBracket'] = self.hasSqrBracket
+
+                        # Sql for alter column
+                        if 'inheritedfrom' not in c:
+                            column_sql += render_template("/".join(
+                                [self.column_template_path, 'update.sql']),
+                                data=c, o_data=old_data, conn=self.conn).strip('\n') + '\n\n'
+
+                # If column(s) is/are added
+                if 'added' in columns:
+                    for c in columns['added']:
+                        c['schema'] = data['schema']
+                        c['table'] = data['name']
+                        # Sql for create column
+                        if 'attacl' in c:
+                            c['attacl'] = parse_priv_to_db(c['attacl'],
+                                                           self.column_acl)
+                        if 'inheritedfrom' not in c:
+                            column_sql += render_template("/".join(
+                                [self.column_template_path, 'create.sql']),
+                                data=c, conn=self.conn).strip('\n') + '\n\n'
+
+                # Combine all the SQL together
+                SQL += column_sql.strip('\n')
+
+            # Check if index constraints are added/changed/deleted
+            index_constraint_sql = self.get_index_constraint_sql(tid, data)
+            # If we have index constraint sql then ad it in main sql
+            if index_constraint_sql is not None:
+                SQL += '\n' + index_constraint_sql
+
+            # Check if foreign key(s) is/are added/changed/deleted
+            foreign_key_sql = self.get_foreign_key_sql(tid, data)
+            # If we have foreign key sql then ad it in main sql
+            if foreign_key_sql is not None:
+                SQL += '\n' + foreign_key_sql
+
+            # Check if check constraint(s) is/are added/changed/deleted
+            check_constraint_sql = self.get_check_constraint_sql(tid, data)
+            # If we have check constraint sql then ad it in main sql
+            if check_constraint_sql is not None:
+                SQL += '\n' + check_constraint_sql
+
+            # Check if exclusion constraint(s) is/are added/changed/deleted
+            exclusion_constraint_sql = self.get_exclusion_constraint_sql(tid, data)
+            # If we have check constraint sql then ad it in main sql
+            if exclusion_constraint_sql is not None:
+                SQL += '\n' + exclusion_constraint_sql
+
+        else:
+            required_args = [
+                'name'
+            ]
+
+            for arg in required_args:
+                if arg not in data:
+                    return gettext('-- incomplete definition')
+
+            # validate constraint data.
+            for key in ['primary_key', 'unique_constraint',
+                        'foreign_key', 'check_constraint',
+                        'exclude_constraint']:
+                if key in data and len(data[key]) > 0:
+                    for constraint in data[key]:
+                        if not self.validate_constrains(key, constraint):
+                            return gettext('-- incomplete definition for {0}'.format(key))
+
+            # We will convert privileges coming from client required
+            # in server side format
+            if 'relacl' in data:
+                data['relacl'] = parse_priv_to_db(data['relacl'], self.acl)
+
+            # Parse & format columns
+            data = self._parse_format_columns(data)
+
+            if 'foreign_key' in data:
+                for c in data['foreign_key']:
+                    SQL = render_template("/".join([self.foreign_key_template_path,
+                                                    'get_parent.sql']),
+                                          tid=c['columns'][0]['references'])
+                    status, rset = self.conn.execute_2darray(SQL)
+                    if not status:
+                        return internal_server_error(errormsg=rset)
+
+                    c['remote_schema'] = rset['rows'][0]['schema']
+                    c['remote_table'] = rset['rows'][0]['table']
+
+            # If the request for new object which do not have did
+            SQL = render_template("/".join([self.template_path, 'create.sql']),
+                                  data=data, conn=self.conn)
+        SQL = re.sub('\n{2,}', '\n', SQL)
+        SQL = SQL.strip('\n')
+
+        return SQL
+
+    def validate_constrains(self, key, data):
+
+        if key == 'primary_key' or key == 'unique_constraint':
+            if 'columns' in data and len(data['columns']) > 0:
+                return True
+            else:
+                return False
+        elif key == 'foreign_key':
+            for arg in ['columns']:
+                if arg not in data:
+                    return False
+                elif isinstance(data[arg], list) and len(data[arg]) < 1:
+                    return False
+
+            if data['autoindex'] and ('coveringindex' not in data or
+                                      data['coveringindex'] == ''):
+                return False
+
+            return True
+
+        elif key == 'check_constraint':
+            for arg in ['consrc']:
+                if arg not in data or data[arg] == '':
+                    return False
+            return True
+
+        elif key == 'exclude_constraint':
+            pass
+
+        return True
+
+    @check_precondition
+    def dependents(self, gid, sid, did, scid, tid):
+        """
+        This function get the dependents and return ajax response
+        for the table node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            scid: Schema ID
+            tid: Table ID
+        """
+        # Specific condition for column which we need to append
+        where = "WHERE dep.refobjid={0}::OID".format(tid)
+
+        dependents_result = self.get_dependents(
+            self.conn, tid
+        )
+
+        # Specific sql to run againt column to fetch dependents
+        SQL = render_template("/".join([self.template_path,
+                                        'depend.sql']), where=where)
+
+        status, res = self.conn.execute_dict(SQL)
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        for row in res['rows']:
+            ref_name = row['refname']
+            if ref_name is None:
+                continue
+
+            dep_type = ''
+            dep_str = row['deptype']
+            if dep_str == 'a':
+                dep_type = 'auto'
+            elif dep_str == 'n':
+                dep_type = 'normal'
+            elif dep_str == 'i':
+                dep_type = 'internal'
+
+            dependents_result.append({'type': 'sequence', 'name': ref_name, 'field': dep_type})
+
+        return ajax_response(
+                response=dependents_result,
+                status=200
+                )
+
+    @check_precondition
+    def dependencies(self, gid, sid, did, scid, tid):
+        """
+        This function get the dependencies and return ajax response
+        for the table node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            scid: Schema ID
+            tid: Table ID
+
+        """
+        dependencies_result = self.get_dependencies(
+            self.conn, tid
+        )
+
+        return ajax_response(
+                response=dependencies_result,
+                status=200
+                )
+
+    @check_precondition
+    def sql(self, gid, sid, did, scid, tid):
+        """
+        This function will creates reverse engineered sql for
+        the table object
+
+         Args:
+           gid: Server Group ID
+           sid: Server ID
+           did: Database ID
+           scid: Schema ID
+           tid: Table ID
+        """
+        main_sql = []
+
+        """
+        #####################################
+        # 1) Reverse engineered sql for TABLE
+        #####################################
+        """
+        SQL = render_template("/".join([self.template_path,
+                                        'properties.sql']),
+                              scid=scid, tid=tid,
+                              datlastsysoid=self.datlastsysoid)
+        status, res = self.conn.execute_dict(SQL)
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        data = res['rows'][0]
+
+        # Table & Schema declaration so that we can use them in child nodes
+        schema = data['schema']
+        table = data['name']
+
+        data = self._formatter(scid, tid, data)
+
+        # Now we have all lis of columns which we need
+        # to include in our create definition, Let's format them
+        if 'columns' in data:
+            for c in data['columns']:
+                if 'attacl' in c:
+                    c['attacl'] = parse_priv_to_db(c['attacl'], self.column_acl)
+
+                # check type for '[]' in it
+                c['cltype'] = self._cltype_formatter(c['cltype'])
+                c['hasSqrBracket'] = self.hasSqrBracket
+
+        sql_header = "-- Table: {0}\n\n-- ".format(self.qtIdent(self.conn,
+                                                                data['schema'],
+                                                                data['name']))
+        sql_header += render_template("/".join([self.template_path,
+                                                'delete.sql']),
+                                      data=data, conn=self.conn)
+
+        sql_header = sql_header.strip('\n')
+        sql_header += '\n'
+
+        # Add into main sql
+        main_sql.append(sql_header)
+
+        # Parse privilege data
+        if 'relacl' in data:
+            data['relacl'] = parse_priv_to_db(data['relacl'], self.acl)
+
+        # If the request for new object which do not have did
+        table_sql = render_template("/".join([self.template_path,
+                                              'create.sql']),
+                                    data=data, conn=self.conn)
+
+        # Add into main sql
+        table_sql = re.sub('\n{2,}', '\n\n', table_sql)
+        main_sql.append(table_sql.strip('\n'))
+
+        """
+        ######################################
+        # 2) Reverse engineered sql for INDEX
+        ######################################
+        """
+
+        SQL = render_template("/".join([self.index_template_path,
+                                        'nodes.sql']), tid=tid)
+        status, rset = self.conn.execute_2darray(SQL)
+        if not status:
+            return internal_server_error(errormsg=rset)
+
+        for row in rset['rows']:
+
+            SQL = render_template("/".join([self.index_template_path,
+                                            'properties.sql']),
+                                  tid=tid, idx=row['oid'],
+                                  datlastsysoid=self.datlastsysoid)
+
+            status, res = self.conn.execute_dict(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            data = dict(res['rows'][0])
+            # Adding parent into data dict, will be using it while creating sql
+            data['schema'] = schema
+            data['table'] = table
+            # We also need to fecth columns of index
+            SQL = render_template("/".join([self.index_template_path,
+                                            'column_details.sql']),
+                                  idx=row['oid'])
+            status, rset = self.conn.execute_2darray(SQL)
+            if not status:
+                return internal_server_error(errormsg=rset)
+
+            # 'attdef' comes with quotes from query so we need to strip them
+            # 'options' we need true/false to render switch ASC(false)/DESC(true)
+            columns = []
+            cols = []
+            for row in rset['rows']:
+                # We need all data as collection for ColumnsModel
+                cols_data = {
+                    'colname': row['attdef'].strip('"'),
+                    'collspcname': row['collnspname'],
+                    'op_class': row['opcname'],
+                }
+                if row['options'][0] == 'DESC':
+                    cols_data['sort_order'] = True
+                columns.append(cols_data)
+
+                # We need same data as string to display in properties window
+                # If multiple column then separate it by colon
+                cols_str = row['attdef']
+                if row['collnspname']:
+                    cols_str += ' COLLATE ' + row['collnspname']
+                if row['opcname']:
+                    cols_str += ' ' + row['opcname']
+                if row['options'][0] == 'DESC':
+                    cols_str += ' DESC'
+                cols.append(cols_str)
+
+            # Push as collection
+            data['columns'] = columns
+            # Push as string
+            data['cols'] = ', '.join(cols)
+
+            sql_header = "\n-- Index: {0}\n\n-- ".format(data['name'])
+            sql_header += render_template("/".join([self.index_template_path,
+                                                    'delete.sql']),
+                                          data=data, conn=self.conn)
+
+            index_sql = render_template("/".join([self.index_template_path,
+                                                  'create.sql']),
+                                        data=data, conn=self.conn)
+            index_sql += "\n"
+            index_sql += render_template("/".join([self.index_template_path,
+                                                   'alter.sql']),
+                                         data=data, conn=self.conn)
+
+            # Add into main sql
+            index_sql = re.sub('\n{2,}', '\n\n', index_sql)
+            main_sql.append(sql_header + '\n\n' + index_sql.strip('\n'))
+
+        """
+        ########################################
+        # 3) Reverse engineered sql for TRIGGERS
+        ########################################
+        """
+        SQL = render_template("/".join([self.trigger_template_path,
+                                        'nodes.sql']), tid=tid)
+        status, rset = self.conn.execute_2darray(SQL)
+        if not status:
+            return internal_server_error(errormsg=rset)
+
+        for row in rset['rows']:
+            trigger_sql = ''
+
+            SQL = render_template("/".join([self.trigger_template_path,
+                                            'properties.sql']),
+                                  tid=tid, trid=row['oid'],
+                                  datlastsysoid=self.datlastsysoid)
+
+            status, res = self.conn.execute_dict(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            data = dict(res['rows'][0])
+            # Adding parent into data dict, will be using it while creating sql
+            data['schema'] = schema
+            data['table'] = table
+
+            if data['tgnargs'] > 1:
+                # We know that trigger has more than 1 arguments, let's join them
+                data['tgargs'] = ', '.join(data['tgargs'])
+
+            if len(data['tgattr']) > 1:
+                columns = ', '.join(data['tgattr'].split(' '))
+
+                SQL = render_template("/".join([self.trigger_template_path,
+                                                'get_columns.sql']),
+                                      tid=tid, clist=columns)
+
+                status, rset = self.conn.execute_2darray(SQL)
+                if not status:
+                    return internal_server_error(errormsg=rset)
+                # 'tgattr' contains list of columns from table used in trigger
+                columns = []
+
+                for row in rset['rows']:
+                    columns.append({'column': row['name']})
+
+                data['columns'] = columns
+
+            data = trigger_definition(data)
+
+            sql_header = "\n-- Trigger: {0}\n\n-- ".format(data['name'])
+            sql_header += render_template("/".join([self.trigger_template_path,
+                                                    'delete.sql']),
+                                          data=data, conn=self.conn)
+
+            # If the request for new object which do not have did
+            trigger_sql = render_template("/".join([self.trigger_template_path,
+                                                    'create.sql']),
+                                          data=data, conn=self.conn)
+
+            trigger_sql = sql_header + '\n\n' + trigger_sql.strip('\n')
+
+            # If trigger is disabled then add sql code for the same
+            if not data['is_enable_trigger']:
+                trigger_sql += '\n\n'
+                trigger_sql += render_template("/".join([
+                    self.trigger_template_path,
+                    'enable_disable_trigger.sql']),
+                    data=data, conn=self.conn)
+
+            # Add into main sql
+            trigger_sql = re.sub('\n{2,}', '\n\n', trigger_sql)
+            main_sql.append(trigger_sql)
+
+        """
+        #####################################
+        # 4) Reverse engineered sql for RULES
+        #####################################
+        """
+
+        SQL = render_template("/".join(
+          [self.rules_template_path, 'properties.sql']), tid=tid)
+
+        status, rset = self.conn.execute_2darray(SQL)
+        if not status:
+            return internal_server_error(errormsg=rset)
+
+        for row in rset['rows']:
+            rules_sql = '\n'
+            SQL = render_template("/".join(
+                [self.rules_template_path, 'properties.sql']
+              ), rid=row['oid'], datlastsysoid=self.datlastsysoid)
+
+            status, res = self.conn.execute_dict(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            res_data = parse_rule_definition(res)
+            rules_sql += render_template("/".join(
+                [self.rules_template_path, 'create.sql']),
+                data=res_data, display_comments=True)
+
+            # Add into main sql
+            rules_sql = re.sub('\n{2,}', '\n\n', rules_sql)
+            main_sql.append(rules_sql)
+
+        sql = '\n'.join(main_sql)
+
+        return ajax_response(response=sql.strip('\n'))
+
+    @check_precondition
+    def select_sql(self, gid, sid, did, scid, tid):
+        """
+        SELECT script sql for the object
+
+        Args:
+            gid: Server Group Id
+            sid: Server Id
+            did: Database Id
+            scid: Schema Id
+            tid: Table Id
+
+        Returns:
+            SELECT Script sql for the object
+        """
+        SQL = render_template("/".join([self.template_path,
+                                        'properties.sql']),
+                              scid=scid, tid=tid,
+                              datlastsysoid=self.datlastsysoid)
+        status, res = self.conn.execute_dict(SQL)
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        data = res['rows'][0]
+        data = self._formatter(scid, tid, data)
+
+        columns = []
+
+        # Now we have all list of columns which we need
+        if 'columns' in data:
+            for c in data['columns']:
+                columns.append(self.qtIdent(self.conn, c['attname']))
+
+        if len(columns) > 0:
+            columns = ", ".join(columns)
+        else:
+            columns = '*'
+
+        sql = "SELECT {0}\n\tFROM {1};".format(
+            columns,
+            self.qtIdent(self.conn, data['schema'], data['name'])
+        )
+        return ajax_response(response=sql)
+
+    @check_precondition
+    def insert_sql(self, gid, sid, did, scid, tid):
+        """
+        INSERT script sql for the object
+
+        Args:
+            gid: Server Group Id
+            sid: Server Id
+            did: Database Id
+            scid: Schema Id
+            tid: Table Id
+
+        Returns:
+            INSERT Script sql for the object
+        """
+        SQL = render_template("/".join([self.template_path,
+                                        'properties.sql']),
+                              scid=scid, tid=tid,
+                              datlastsysoid=self.datlastsysoid)
+        status, res = self.conn.execute_dict(SQL)
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        data = res['rows'][0]
+        data = self._formatter(scid, tid, data)
+
+        columns = []
+        values = []
+
+        # Now we have all list of columns which we need
+        if 'columns' in data:
+            for c in data['columns']:
+                columns.append(self.qtIdent(self.conn, c['attname']))
+                values.append('?')
+
+        if len(columns) > 0:
+            columns = ", ".join(columns)
+            values = ", ".join(values)
+            sql = "INSERT INTO {0}(\n\t{1})\n\tVALUES ({2});".format(
+                self.qtIdent(self.conn, data['schema'], data['name']),
+                columns, values
+            )
+        else:
+            sql = gettext('-- Please create column(s) first...')
+
+        return ajax_response(response=sql)
+
+    @check_precondition
+    def update_sql(self, gid, sid, did, scid, tid):
+        """
+        UPDATE script sql for the object
+
+        Args:
+            gid: Server Group Id
+            sid: Server Id
+            did: Database Id
+            scid: Schema Id
+            tid: Table Id
+
+        Returns:
+            UPDATE Script sql for the object
+        """
+        SQL = render_template("/".join([self.template_path,
+                                        'properties.sql']),
+                              scid=scid, tid=tid,
+                              datlastsysoid=self.datlastsysoid)
+        status, res = self.conn.execute_dict(SQL)
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        data = res['rows'][0]
+        data = self._formatter(scid, tid, data)
+
+        columns = []
+
+        # Now we have all list of columns which we need
+        if 'columns' in data:
+            for c in data['columns']:
+                columns.append(self.qtIdent(self.conn, c['attname']))
+
+        if len(columns) > 0:
+            if len(columns) == 1:
+                columns = columns[0]
+                columns += "=?"
+            else:
+                columns = "=?, ".join(columns)
+
+            sql = "UPDATE {0}\n\tSET {1}\n\tWHERE <condition>;".format(
+                self.qtIdent(self.conn, data['schema'], data['name']),
+                columns
+            )
+        else:
+            sql = gettext('-- Please create column(s) first...')
+
+        return ajax_response(response=sql)
+
+    @check_precondition
+    def delete_sql(self, gid, sid, did, scid, tid):
+        """
+        DELETE script sql for the object
+
+        Args:
+            gid: Server Group Id
+            sid: Server Id
+            did: Database Id
+            scid: Schema Id
+            tid: Table Id
+
+        Returns:
+            DELETE Script sql for the object
+        """
+        SQL = render_template("/".join([self.template_path,
+                                        'properties.sql']),
+                              scid=scid, tid=tid,
+                              datlastsysoid=self.datlastsysoid)
+        status, res = self.conn.execute_dict(SQL)
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        data = res['rows'][0]
+
+        sql = "DELETE FROM {0}\n\tWHERE <condition>;".format(
+            self.qtIdent(self.conn, data['schema'], data['name'])
+        )
+
+        return ajax_response(response=sql)
+
+
+TableView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/__init__.py
new file mode 100644
index 0000000..5bcb456
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/__init__.py
@@ -0,0 +1,906 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+""" Implements Column Node """
+
+from flask import render_template, make_response, request, jsonify
+from flask.ext.babel import gettext
+from pgadmin.utils.ajax import make_json_response, \
+    make_response as ajax_response, internal_server_error
+from pgadmin.browser.utils import PGChildNodeView
+from pgadmin.browser.server_groups.servers.databases.schemas.utils \
+    import DataTypeReader
+from pgadmin.browser.collection import CollectionNodeModule
+import pgadmin.browser.server_groups.servers.databases as database
+from pgadmin.utils.ajax import precondition_required
+from pgadmin.utils.driver import get_driver
+from config import PG_DEFAULT_DRIVER
+from pgadmin.browser.server_groups.servers.utils import parse_priv_from_db, \
+    parse_priv_to_db
+from functools import wraps
+import json
+
+
+class ColumnsModule(CollectionNodeModule):
+    """
+     class ColumnsModule(CollectionNodeModule)
+
+        A module class for Column node derived from CollectionNodeModule.
+
+    Methods:
+    -------
+    * __init__(*args, **kwargs)
+      - Method is used to initialize the Column and it's base module.
+
+    * get_nodes(gid, sid, did, scid, tid)
+      - Method is used to generate the browser collection node.
+
+    * node_inode()
+      - Method is overridden from its base class to make the node as leaf node.
+
+    * script_load()
+      - Load the module script for schema, when any of the server node is
+        initialized.
+    """
+
+    NODE_TYPE = 'column'
+    COLLECTION_LABEL = gettext("Columns")
+
+    def __init__(self, *args, **kwargs):
+        """
+        Method is used to initialize the ColumnModule and it's base module.
+
+        Args:
+            *args:
+            **kwargs:
+        """
+        self.min_ver = None
+        self.max_ver = None
+        super(ColumnsModule, self).__init__(*args, **kwargs)
+
+    def get_nodes(self, gid, sid, did, scid, **kwargs):
+        """
+        Generate the collection node
+        """
+        assert('tid' in kwargs or 'vid' in kwargs)
+        yield self.generate_browser_collection_node(
+            kwargs['tid'] if 'tid' in kwargs else kwargs['vid']
+        )
+
+    @property
+    def script_load(self):
+        """
+        Load the module script for server, when any of the server-group node is
+        initialized.
+        """
+        return database.DatabaseModule.NODE_TYPE
+
+    @property
+    def node_inode(self):
+        """
+        Load the module node as a leaf node
+        """
+        return False
+
+
+blueprint = ColumnsModule(__name__)
+
+
+class ColumnsView(PGChildNodeView, DataTypeReader):
+    """
+    This class is responsible for generating routes for Column node
+
+    Methods:
+    -------
+    * __init__(**kwargs)
+      - Method is used to initialize the ColumnView and it's base view.
+
+    * module_js()
+      - This property defines (if javascript) exists for this node.
+        Override this property for your own logic
+
+    * check_precondition()
+      - This function will behave as a decorator which will checks
+        database connection before running view, it will also attaches
+        manager,conn & template_path properties to self
+
+    * list()
+      - This function is used to list all the Column nodes within that
+      collection.
+
+    * nodes()
+      - This function will used to create all the child node within that
+        collection, Here it will create all the Column node.
+
+    * properties(gid, sid, did, scid, tid, clid)
+      - This function will show the properties of the selected Column node
+
+    * create(gid, sid, did, scid, tid)
+      - This function will create the new Column object
+
+    * update(gid, sid, did, scid, tid, clid)
+      - This function will update the data for the selected Column node
+
+    * delete(self, gid, sid, scid, tid, clid):
+      - This function will drop the Column object
+
+    * msql(gid, sid, did, scid, tid, clid)
+      - This function is used to return modified SQL for the selected
+        Column node
+
+    * get_sql(data, scid, tid)
+      - This function will generate sql from model data
+
+    * sql(gid, sid, did, scid):
+      - This function will generate sql to show it in sql pane for the
+        selected Column node.
+
+    * dependency(gid, sid, did, scid):
+      - This function will generate dependency list show it in dependency
+        pane for the selected Column node.
+
+    * dependent(gid, sid, did, scid):
+      - This function will generate dependent list to show it in dependent
+        pane for the selected Column node.
+    """
+
+    node_type = blueprint.node_type
+
+    parent_ids = [
+            {'type': 'int', 'id': 'gid'},
+            {'type': 'int', 'id': 'sid'},
+            {'type': 'int', 'id': 'did'},
+            {'type': 'int', 'id': 'scid'},
+            {'type': 'int', 'id': 'tid'}
+            ]
+    ids = [
+            # Here we specify type as any because table
+            # are also has '-' in them if they are system table
+            {'type': 'string', 'id': 'clid'}
+            ]
+
+    operations = dict({
+        'obj': [
+            {'get': 'properties', 'delete': 'delete', 'put': 'update'},
+            {'get': 'list', 'post': 'create'}
+        ],
+        'children': [{'get': 'children'}],
+        'nodes': [{'get': 'node'}, {'get': 'nodes'}],
+        'sql': [{'get': 'sql'}],
+        'msql': [{'get': 'msql'}, {'get': 'msql'}],
+        'stats': [{'get': 'statistics'}],
+        'dependency': [{'get': 'dependencies'}],
+        'dependent': [{'get': 'dependents'}],
+        'module.js': [{}, {}, {'get': 'module_js'}],
+    })
+
+    def check_precondition(f):
+        """
+        This function will behave as a decorator which will checks
+        database connection before running view, it will also attaches
+        manager,conn & template_path properties to self
+        """
+        @wraps(f)
+        def wrap(*args, **kwargs):
+            # Here args[0] will hold self & kwargs will hold gid,sid,did
+            self = args[0]
+            driver = get_driver(PG_DEFAULT_DRIVER)
+            self.manager = driver.connection_manager(
+                kwargs['sid']
+            )
+            self.conn = self.manager.connection(did=kwargs['did'])
+            self.qtIdent = driver.qtIdent
+            # If DB not connected then return error to browser
+            if not self.conn.connected():
+                return precondition_required(
+                    gettext(
+                            "Connection to the server has been lost!"
+                    )
+                )
+
+            ver = self.manager.version
+            # we will set template path for sql scripts
+            if ver >= 90200:
+                self.template_path = 'column/sql/9.2_plus'
+            else:
+                self.template_path = 'column/sql/9.1_plus'
+            # Allowed ACL for column 'Select/Update/Insert/References'
+            self.acl = ['a', 'r', 'w', 'x']
+
+            # We need parent's name eg table name and schema name
+            SQL = render_template("/".join([self.template_path,
+                                            'get_parent.sql']),
+                                  tid=kwargs['tid'])
+            status, rset = self.conn.execute_2darray(SQL)
+            if not status:
+                return internal_server_error(errormsg=rset)
+
+            for row in rset['rows']:
+                self.schema = row['schema']
+                self.table = row['table']
+
+            return f(*args, **kwargs)
+
+        return wrap
+
+    @check_precondition
+    def list(self, gid, sid, did, scid, tid):
+        """
+        This function is used to list all the schema nodes within that collection.
+
+        Args:
+            gid: Server group ID
+            sid: Server ID
+            did: Database ID
+            scid: Schema ID
+            tid: Table ID
+
+        Returns:
+            JSON of available column nodes
+        """
+
+        SQL = render_template("/".join([self.template_path,
+                                        'properties.sql']), tid=tid,
+                              show_sys_objects=self.blueprint.show_system_objects)
+        status, res = self.conn.execute_dict(SQL)
+
+        if not status:
+            return internal_server_error(errormsg=res)
+        return ajax_response(
+                response=res['rows'],
+                status=200
+                )
+
+    @check_precondition
+    def nodes(self, gid, sid, did, scid, tid):
+        """
+        This function will used to create all the child node within that collection.
+        Here it will create all the schema node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            scid: Schema ID
+            tid: Table ID
+
+        Returns:
+            JSON of available schema child nodes
+        """
+        res = []
+        SQL = render_template("/".join([self.template_path,
+                                        'nodes.sql']), tid=tid,
+                              show_sys_objects=self.blueprint.show_system_objects)
+        status, rset = self.conn.execute_2darray(SQL)
+        if not status:
+            return internal_server_error(errormsg=rset)
+
+        for row in rset['rows']:
+            res.append(
+                self.blueprint.generate_browser_node(
+                    row['oid'],
+                    tid,
+                    row['name'],
+                    icon="icon-column",
+                    datatype=row['datatype']  # We need datatype somewhere in
+            ))                                # exclusion constraint.
+
+        return make_json_response(
+                data=res,
+                status=200
+                )
+
+    def _formatter(self, scid, tid, clid, data):
+        """
+        Args:
+             scid: schema oid
+             tid: table oid
+             clid: position of column in table
+             data: dict of query result
+
+        Returns:
+            It will return formatted output of collections
+        """
+        # To check if column is primary key
+        if 'attnum' in data and 'indkey' in data:
+            # Current column
+            attnum = str(data['attnum'])
+
+            # Single/List of primary key column(s)
+            indkey = str(data['indkey'])
+
+            # We will check if column is in primary column(s)
+            if attnum in indkey.split(" "):
+                data['is_pk'] = True
+            else:
+                data['is_pk'] = False
+
+        # Find length & precision of column data type
+        fulltype = self.get_full_type(
+            data['typnspname'], data['typname'],
+            data['isdup'], data['attndims'], data['atttypmod']
+        )
+
+        import re
+        # If we have length & precision both
+        matchObj = re.search(r'(\d+),(\d+)', fulltype)
+        if matchObj:
+            data['attlen'] = matchObj.group(1)
+            data['attprecision'] = matchObj.group(2)
+        else:
+            # If we have length only
+            matchObj = re.search(r'(\d+)', fulltype)
+            if matchObj:
+                data['attlen'] = matchObj.group(1)
+                data['attprecision'] = None
+            else:
+                data['attlen'] = None
+                data['attprecision'] = None
+
+        # We need to fetch inherited tables for each table
+        SQL = render_template("/".join([self.template_path,
+                                        'get_inherited_tables.sql']),
+                              tid=tid)
+        status, inh_res = self.conn.execute_dict(SQL)
+        if not status:
+            return internal_server_error(errormsg=inh_res)
+        for row in inh_res['rows']:
+            if row['attrname'] == data['name']:
+                data['is_inherited'] = True
+                data['tbls_inherited'] = row['inhrelname']
+
+        # We need to format variables according to client js collection
+        if 'attoptions' in data and data['attoptions'] is not None:
+            spcoptions = []
+            for spcoption in data['attoptions']:
+                k, v = spcoption.split('=')
+                spcoptions.append({'name': k, 'value': v})
+
+            data['attoptions'] = spcoptions
+
+        # Need to format security labels according to client js collection
+        if 'seclabels' in data and data['seclabels'] is not None:
+            seclabels = []
+            for seclbls in data['seclabels']:
+                k, v = seclbls.split('=')
+                seclabels.append({'provider': k, 'label': v})
+
+            data['seclabels'] = seclabels
+
+        # We need to parse & convert ACL coming from database to json format
+        SQL = render_template("/".join([self.template_path, 'acl.sql']),
+                              tid=tid, clid=clid)
+        status, acl = self.conn.execute_dict(SQL)
+
+        if not status:
+            return internal_server_error(errormsg=acl)
+
+        # We will set get privileges from acl sql so we don't need
+        # it from properties sql
+        data['attacl'] = []
+
+        for row in acl['rows']:
+            priv = parse_priv_from_db(row)
+            data.setdefault(row['deftype'], []).append(priv)
+
+        # we are receiving request when in edit mode
+        # we will send filtered types related to current type
+        present_type = data['cltype']
+        type_id = data['atttypid']
+
+        SQL = render_template("/".join([self.template_path,
+                                        'is_referenced.sql']),
+                              tid=tid, clid=clid)
+
+        status, is_reference = self.conn.execute_scalar(SQL)
+
+        edit_types_list = list()
+        # We will need present type in edit mode
+        edit_types_list.append(present_type)
+
+        if int(is_reference) == 0:
+            SQL = render_template("/".join([self.template_path,
+                                            'edit_mode_types.sql']),
+                                  type_id=type_id)
+            status, rset = self.conn.execute_2darray(SQL)
+
+            for row in rset['rows']:
+                edit_types_list.append(row['typname'])
+        else:
+            edit_types_list.append(present_type)
+
+        data['edit_types'] = edit_types_list
+
+        # Manual Data type formatting
+        # If data type has () with them then we need to remove them
+        # eg bit(1) because we need to match the name with combobox
+        isArray = False
+        if data['cltype'].endswith('[]'):
+            isArray = True
+            data['cltype'] = data['cltype'].rstrip('[]')
+
+        idx = data['cltype'].find('(')
+        if idx and data['cltype'].endswith(')'):
+            data['cltype'] = data['cltype'][:idx]
+
+        if isArray:
+            data['cltype'] += "[]"
+
+        return data
+
+    @check_precondition
+    def properties(self, gid, sid, did, scid, tid, clid):
+        """
+        This function will show the properties of the selected schema node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did:  Database ID
+            scid: Schema ID
+            scid: Schema ID
+            tid: Table ID
+            clid: Column ID
+
+        Returns:
+            JSON of selected schema node
+        """
+
+        SQL = render_template("/".join([self.template_path,
+                                        'properties.sql']), tid=tid, clid=clid
+                              , show_sys_objects=self.blueprint.show_system_objects)
+
+        status, res = self.conn.execute_dict(SQL)
+
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        # Making copy of output for future use
+        data = dict(res['rows'][0])
+        data = self._formatter(scid, tid, clid, data)
+
+        return ajax_response(
+                response=data,
+                status=200
+                )
+
+    def _cltype_formatter(self, type):
+        """
+
+        Args:
+            data: Type string
+
+        Returns:
+            We need to remove [] from type and append it
+            after length/precision so we will set flag for
+            sql template
+        """
+        if '[]' in type:
+            type = type.replace('[]', '')
+            self.hasSqrBracket = True
+        else:
+            self.hasSqrBracket = False
+
+        return type
+
+    @check_precondition
+    def create(self, gid, sid, did, scid, tid):
+        """
+        This function will creates new the schema object
+
+         Args:
+           gid: Server Group ID
+           sid: Server ID
+           did: Database ID
+           scid: Schema ID
+           tid: Table ID
+        """
+        data = request.form if request.form else json.loads(
+            request.data.decode()
+        )
+
+        for k, v in data.items():
+            try:
+                data[k] = json.loads(v)
+            except (ValueError, TypeError):
+                data[k] = v
+
+        required_args = {
+            'name': 'Name',
+            'cltype': 'Type'
+        }
+
+        for arg in required_args:
+            if arg not in data:
+                return make_json_response(
+                    status=410,
+                    success=0,
+                    errormsg=gettext(
+                        "Couldn't find the required parameter (%s)." %
+                        required_args[arg]
+                    )
+                )
+
+        # Parse privilege data coming from client according to database format
+        if 'attacl' in data:
+            data['attacl'] = parse_priv_to_db(data['attacl'], self.acl)
+
+        # Adding parent into data dict, will be using it while creating sql
+        data['schema'] = self.schema
+        data['table'] = self.table
+
+        # check type for '[]' in it
+        data['cltype'] = self._cltype_formatter(data['cltype'])
+        data['hasSqrBracket'] = self.hasSqrBracket
+
+        try:
+            SQL = render_template("/".join([self.template_path,
+                                            'create.sql']),
+                                  data=data, conn=self.conn)
+            status, res = self.conn.execute_scalar(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            # we need oid to to add object in tree at browser
+            SQL = render_template("/".join([self.template_path,
+                                            'get_position.sql']),
+                                  tid=tid, data=data)
+            status, clid = self.conn.execute_scalar(SQL)
+            if not status:
+                return internal_server_error(errormsg=tid)
+
+            return jsonify(
+                node=self.blueprint.generate_browser_node(
+                    clid,
+                    scid,
+                    data['name'],
+                    icon="icon-column"
+                )
+            )
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def delete(self, gid, sid, did, scid, tid, clid):
+        """
+        This function will updates existing the schema object
+
+         Args:
+           gid: Server Group ID
+           sid: Server ID
+           did: Database ID
+           scid: Schema ID
+           tid: Table ID
+           clid: Column ID
+        """
+        # We will first fetch the column name for current request
+        # so that we create template for dropping column
+        try:
+
+            SQL = render_template("/".join([self.template_path,
+                                            'properties.sql']), tid=tid, clid=clid
+                                  , show_sys_objects=self.blueprint.show_system_objects)
+
+            status, res = self.conn.execute_dict(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            data = dict(res['rows'][0])
+            # We will add table & schema as well
+            data['schema'] = self.schema
+            data['table'] = self.table
+
+            SQL = render_template("/".join([self.template_path,
+                                            'delete.sql']),
+                                  data=data, conn=self.conn)
+            status, res = self.conn.execute_scalar(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            return make_json_response(
+                success=1,
+                info=gettext("Column is dropped"),
+                data={
+                    'id': clid,
+                    'tid': tid
+                }
+            )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def update(self, gid, sid, did, scid, tid, clid):
+        """
+        This function will updates existing the schema object
+
+         Args:
+           gid: Server Group ID
+           sid: Server ID
+           did: Database ID
+           scid: Schema ID
+           tid: Table ID
+           clid: Column ID
+        """
+        data = request.form if request.form else json.loads(request.data.decode())
+
+        # Adding parent into data dict, will be using it while creating sql
+        data['schema'] = self.schema
+        data['table'] = self.table
+
+        # check type for '[]' in it
+        if 'cltype' in data:
+            data['cltype'] = self._cltype_formatter(data['cltype'])
+            data['hasSqrBracket'] = self.hasSqrBracket
+
+        try:
+            SQL = self.get_sql(scid, tid, clid, data)
+            if SQL and SQL.strip('\n') and SQL.strip(' '):
+                status, res = self.conn.execute_scalar(SQL)
+                if not status:
+                    return internal_server_error(errormsg=res)
+
+                return make_json_response(
+                    success=1,
+                    info="Column updated",
+                    data={
+                        'id': clid,
+                        'tid': tid,
+                        'scid': scid
+                    }
+                )
+            else:
+                return make_json_response(
+                    success=1,
+                    info="Nothing to update",
+                    data={
+                        'id': clid,
+                        'tid': tid,
+                        'scid': scid
+                    }
+                )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+
+    @check_precondition
+    def msql(self, gid, sid, did, scid, tid, clid=None):
+        """
+        This function will generates modified sql for schema object
+
+         Args:
+           gid: Server Group ID
+           sid: Server ID
+           did: Database ID
+           scid: Schema ID
+           tid: Table ID
+           clid: Column ID (When working with existing column)
+        """
+        data = dict()
+        for k, v in request.args.items():
+            try:
+                data[k] = json.loads(v)
+            except ValueError:
+                data[k] = v
+
+        # Adding parent into data dict, will be using it while creating sql
+        data['schema'] = self.schema
+        data['table'] = self.table
+
+        # check type for '[]' in it
+        if 'cltype' in data:
+            data['cltype'] = self._cltype_formatter(data['cltype'])
+            data['hasSqrBracket'] = self.hasSqrBracket
+
+        try:
+            SQL = self.get_sql(scid, tid, clid, data)
+
+            if SQL and SQL.strip('\n') and SQL.strip(' '):
+                return make_json_response(
+                        data=SQL,
+                        status=200
+                        )
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    def get_sql(self, scid, tid, clid, data):
+        """
+        This function will genrate sql from model data
+        """
+        if clid is not None:
+            SQL = render_template("/".join([self.template_path,
+                                            'properties.sql']), tid=tid, clid=clid
+                                  , show_sys_objects=self.blueprint.show_system_objects)
+
+            status, res = self.conn.execute_dict(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            old_data = dict(res['rows'][0])
+            # We will add table & schema as well
+            old_data = self._formatter(scid, tid, clid, old_data)
+
+            # If name is not present in data then
+            # we will fetch it from old data, we also need schema & table name
+            if 'name' not in data:
+                data['name'] = old_data['name']
+
+            # Convert acl coming from client in db parsing format
+            key = 'attacl'
+            if key in data and data[key] is not None:
+                if 'added' in data[key]:
+                    data[key]['added'] = parse_priv_to_db(
+                      data[key]['added'], self.acl
+                    )
+                if 'changed' in data[key]:
+                    data[key]['changed'] = parse_priv_to_db(
+                      data[key]['changed'], self.acl
+                    )
+                if 'deleted' in data[key]:
+                    data[key]['deleted'] = parse_priv_to_db(
+                      data[key]['deleted'], self.acl
+                    )
+
+            SQL = render_template(
+                "/".join([self.template_path, 'update.sql']),
+                data=data, o_data=old_data, conn=self.conn
+                )
+        else:
+            required_args = [
+                'name',
+                'cltype'
+            ]
+
+            for arg in required_args:
+                if arg not in data:
+                    return gettext('-- incomplete definition')
+
+            # We will convert privileges coming from client required
+            # in server side format
+            if 'attacl' in data:
+                data['attacl'] = parse_priv_to_db(data['attacl'],
+                                                  self.acl)
+            # If the request for new object which do not have did
+            SQL = render_template("/".join([self.template_path, 'create.sql']),
+                                  data=data, conn=self.conn)
+        return SQL
+
+    @check_precondition
+    def sql(self, gid, sid, did, scid, tid, clid):
+        """
+        This function will generates reverse engineered sql for schema object
+
+         Args:
+           gid: Server Group ID
+           sid: Server ID
+           did: Database ID
+           scid: Schema ID
+           tid: Table ID
+           clid: Column ID
+        """
+        try:
+            SQL = render_template("/".join([self.template_path,
+                                            'properties.sql']), tid=tid, clid=clid
+                                  , show_sys_objects=self.blueprint.show_system_objects)
+
+            status, res = self.conn.execute_dict(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            data = dict(res['rows'][0])
+            # We do not want to display length as -1 in create query
+            if 'attlen' in data and data['attlen'] == -1:
+                data['attlen'] = ''
+            # Adding parent into data dict, will be using it while creating sql
+            data['schema'] = self.schema
+            data['table'] = self.table
+            # check type for '[]' in it
+            if 'cltype' in data:
+                data['cltype'] = self._cltype_formatter(data['cltype'])
+                data['hasSqrBracket'] = self.hasSqrBracket
+
+            # We will add table & schema as well
+            data = self._formatter(scid, tid, clid, data)
+
+            SQL = self.get_sql(scid, tid, None, data)
+
+            sql_header = "-- Column: {0}\n\n-- ".format(self.qtIdent(self.conn,
+                                                                     data['schema'],
+                                                                     data['table'],
+                                                                     data['name']))
+            sql_header += render_template("/".join([self.template_path,
+                                                    'delete.sql']),
+                                          data=data, conn=self.conn)
+            SQL = sql_header + '\n\n' + SQL
+
+            return SQL
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def dependents(self, gid, sid, did, scid, tid, clid):
+        """
+        This function get the dependents and return ajax response
+        for the column node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            scid: Schema ID
+            tid: Table ID
+            clid: Column ID
+        """
+        # Specific condition for column which we need to append
+        where = "WHERE dep.refobjid={0}::OID AND dep.refobjsubid={1}".format(
+            tid, clid
+        )
+
+        dependents_result = self.get_dependents(
+            self.conn, clid, where=where
+        )
+
+        # Specific sql to run againt column to fetch dependents
+        SQL = render_template("/".join([self.template_path,
+                                        'depend.sql']), where=where)
+
+        status, res = self.conn.execute_dict(SQL)
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        for row in res['rows']:
+            ref_name = row['refname']
+            if ref_name is None:
+                continue
+
+            dep_type = ''
+            dep_str = row['deptype']
+            if dep_str == 'a':
+                dep_type = 'auto'
+            elif dep_str == 'n':
+                dep_type = 'normal'
+            elif dep_str == 'i':
+                dep_type = 'internal'
+
+            dependents_result.append({'type': 'sequence', 'name': ref_name, 'field': dep_type})
+
+        return ajax_response(
+                response=dependents_result,
+                status=200
+                )
+
+    @check_precondition
+    def dependencies(self, gid, sid, did, scid, tid, clid):
+        """
+        This function get the dependencies and return ajax response
+        for the column node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            scid: Schema ID
+            tid: Table ID
+            clid: Column ID
+
+        """
+        # Specific condition for column which we need to append
+        dependencies_result = self.get_dependencies(
+            self.conn, clid
+        )
+
+        return ajax_response(
+                response=dependencies_result,
+                status=200
+                )
+
+
+ColumnsView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/static/img/coll-column.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/static/img/coll-column.png
new file mode 100644
index 0000000000000000000000000000000000000000..89d758834d4176c1df2548db10b46b1f6b2e4ec5
GIT binary patch
literal 400
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbK}cz{ocE09*4`h3Ev&s(m&yL<QU
z)2C0LJ$u%^|9SG<<M-~}d-(9-vSrKOym_;3-MW`AU#?uaa_!o+>({S;_3G90=g%KJ
zc<}o5>kl73eEaro$BrEvHf-3qapU*z-`~D{TatgM6KFJJNswPKgTu2MX+REVfk$L9
zkoEv$x0Bg+Kt_S5i(`ny<=FG?VhsvBt`}W4E@ZQg__p6qm@nby;qrG1j0_I@c^(;r
zuhP)2X<D_P?dti2$vzyv(k(V*o?f?H<i?gXiRA)mhTUpwofQn*P8`|LWw=McNaXQ!
zy+q@@Yd0m1ylF3f{(An_-EV$!P4L^#_`09vh+=cW8=&2)C9V-ADTyViR>?)FK#IZ0
zz|cU~&`8(7FvQ5f%EZ{p#6;V`)XKoXVy3DbiiX_$l+3hBhz0{oum+H7D+4o#hEvl+
R*8nvzc)I$ztaD0e0s#BYr!@co

literal 0
HcmV?d00001

diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/static/img/column.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/static/img/column.png
new file mode 100644
index 0000000000000000000000000000000000000000..bd9f81df98fe27d81ade5144d66b3b09b96123c1
GIT binary patch
literal 435
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbK}X@F0NE09*4`h3Ev&s(m&yL<QU
zy?giW-@pI#>C<P=p0)3PzHHgD=g*(Nc=6)Rn>Xv$t$X?M<;s;SSFBjEcJ12r>({?}
z_3FWc2M-@UeDvti>eZ{)tXZ>Z)20s}KD>VY`qQURpFe;8`t|F#Z{K$8*s)>5hK(CH
ze*gac?c2BS-o49eKe!ZVF=I)PUoeBivm0qZ4rhT!WHFHT0Ash4*>*risi%u$h{WaE
z^B0Ah6a-om4Rm-iuV3+X<o2rm?|w$}?!!eN_y0*dcT_ORb6x7A={6cu<^6X}kY2Ib
zZ0TMHrih1I^CUh^d%@<y)3TvOv&K6iH~-RCTdVU6czMe9*h~1l{VS1_(D3~9P6_q4
zgXi+))!6E^|9xfrB*GzI-TA)^=m6Cc*NBpo#FA92<f2p{#b9J$XrOCoq-$UpVq{=t
zVr*q%qHSPmWnf@2Q&kQ{LvDUbW?CgggMlSj14y-%ff+=@sp+9>fEpM)UHx3vIVCg!
E0NRqnZ~y=R

literal 0
HcmV?d00001

diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/templates/column/js/column.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/templates/column/js/column.js
new file mode 100644
index 0000000..5f8edc6
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/templates/column/js/column.js
@@ -0,0 +1,586 @@
+define(
+        ['jquery', 'underscore', 'underscore.string', 'pgadmin', 'pgadmin.browser',
+        'backform', 'alertify', 'pgadmin.browser.collection'],
+function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
+
+  if (!pgBrowser.Nodes['coll-column']) {
+    var databases = pgAdmin.Browser.Nodes['coll-column'] =
+      pgAdmin.Browser.Collection.extend({
+        node: 'column',
+        label: '{{ _('Columns') }}',
+        type: 'coll-column',
+        sqlAlterHelp: 'sql-altertable.html',
+        sqlCreateHelp: 'sql-altertable.html',
+        columns: ['name', 'atttypid', 'description']
+      });
+  };
+
+  // Switch Cell for Primary Key selection
+  var SwitchDepCell = Backgrid.BooleanCell.extend({
+      initialize: function() {
+        Backgrid.BooleanCell.prototype.initialize.apply(this, arguments);
+        Backgrid.Extension.DependentCell.prototype.initialize.apply(this, arguments);
+      },
+      dependentChanged: function () {
+        var model = this.model,
+          column = this.column,
+          editable = this.column.get("editable"),
+          input = this.$el.find('input[type=checkbox]').first();
+
+        is_editable = _.isFunction(editable) ? !!editable.apply(column, [model]) : !!editable;
+        if (is_editable) {
+           this.$el.addClass("editable");
+           input.prop('disabled', false);
+         } else {
+           this.$el.removeClass("editable");
+           input.prop('disabled', true);
+         }
+
+        this.delegateEvents();
+        return this;
+      },
+      remove: Backgrid.Extension.DependentCell.prototype.remove
+    });
+
+   // This Node model will be used for variable control for column
+   var VariablesModel = Backform.VariablesModel = pgAdmin.Browser.Node.Model.extend({
+    defaults: {
+      name: null,
+      value: null
+    },
+    schema: [{
+      id: 'name', label: '{{ _('Name') }}', cell: 'select2',
+      type: 'text', disabled: false, node: 'column',
+      options: [['n_distinct', 'n_distinct'],
+      ['n_distinct_inherited','n_distinct_inherited']],
+      select2: {placeholder: "Select variable"},
+      cellHeaderClasses:'width_percent_50'
+    },{
+      id: 'value', label: '{{ _('Value') }}',
+      type: 'text', disabled: false,
+      cellHeaderClasses:'width_percent_50'
+    }],
+    validate: function() {
+      var err = {},
+          errmsg = null;
+
+      if (_.isUndefined(this.get('value')) ||
+        _.isNull(this.get('value')) ||
+        String(this.get('value')).replace(/^\s+|\s+$/g, '') == '') {
+            errmsg =  '{{ _('Please provide input for variable.')}}';
+            this.errorModel.set('value', errmsg);
+            return errmsg;
+          } else {
+            this.errorModel.unset('value');
+          }
+      return null;
+    }
+  });
+
+  if (!pgBrowser.Nodes['column']) {
+    pgAdmin.Browser.Nodes['column'] = pgAdmin.Browser.Node.extend({
+      parent_type: ['table', 'view', 'mview'],
+      collection_type: ['coll-table', 'coll-view', 'coll-mview'],
+      type: 'column',
+      label: '{{ _('Column') }}',
+      hasSQL:  true,
+      canDrop: function(itemData, item, data){
+        if (pgBrowser.Nodes['schema'].canChildDrop.apply(this, [itemData, item, data])) {
+          var t = pgBrowser.tree, i = item, d = itemData, parents = [];
+          // To iterate over tree to check parent node
+          while (i) {
+            parents.push(d._type);
+            i = t.hasParent(i) ? t.parent(i) : null;
+            d = i ? t.itemData(i) : null;
+          }
+
+          // Check if menu is allowed ?
+          if(_.indexOf(parents, 'catalog') > -1 ||
+             _.indexOf(parents, 'view') > -1 ||
+             _.indexOf(parents, 'mview') > -1) {
+            return false;
+          } else if(_.indexOf(parents, 'table') > -1) {
+            return true;
+          }
+        } else {
+          return false;
+        }
+      },
+      hasDepends: true,
+      Init: function() {
+        /* Avoid mulitple registration of menus */
+        if (this.initialized)
+            return;
+
+        this.initialized = true;
+
+        pgBrowser.add_menus([{
+          name: 'create_column_on_coll', node: 'coll-column', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('Column...') }}',
+          icon: 'wcTabIcon icon-column', data: {action: 'create', check: true},
+          enable: 'canCreate'
+        },{
+          name: 'create_column', node: 'column', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('Column...') }}',
+          icon: 'wcTabIcon icon-column', data: {action: 'create', check: true},
+          enable: 'canCreate'
+        },{
+          name: 'create_column_onTable', node: 'table', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('Column...') }}',
+          icon: 'wcTabIcon icon-column', data: {action: 'create', check: true},
+          enable: 'canCreate'
+        },{
+          name: 'create_column_onView', node: 'view', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('Column...') }}',
+          icon: 'wcTabIcon icon-column', data: {action: 'create', check: true},
+          enable: 'canCreate'
+        }
+        ]);
+      },
+      model: pgAdmin.Browser.Node.Model.extend({
+        defaults: {
+          name: undefined,
+          attowner: undefined,
+          atttypid: undefined,
+          attnum: undefined,
+          cltype: undefined,
+          collspcname: undefined,
+          attacl: undefined,
+          description: undefined,
+          parent_tbl: undefined,
+          min_val: undefined,
+          max_val: undefined,
+          edit_types: undefined,
+          is_primary_key: false,
+          inheritedfrom: undefined,
+          attstattarget:undefined
+        },
+        schema: [{
+          id: 'name', label: '{{ _('Name') }}', cell: 'string',
+          type: 'text', disabled: 'inSchemaWithColumnCheck',
+          cellHeaderClasses:'width_percent_30',
+          editable: 'editable_check_for_table'
+        },{
+          // Need to show this field only when creating new table [in SubNode control]
+          id: 'is_primary_key', label: '{{ _('Is primary key?') }}', cell: SwitchDepCell,
+          type: 'switch', deps:['name'],
+          options: {
+            onText: 'Yes', offText: 'No', onColor: 'success',
+            offColor: 'primary', size: 'small'},
+          cellHeaderClasses:'width_percent_5',
+          visible: function(m) {
+            return _.isUndefined(m.top.node_info['table'] || m.top.node_info['view'] || m.top.node_info['mview']);
+          },
+          disabled: function(m){
+            // If primary key already exist then disable.
+            if (m.top && !_.isUndefined(m.top.get('oid')) &&
+                        m.top.get('primary_key').length > 0 &&
+                        !_.isUndefined(m.top.get('primary_key').first().get('oid'))) {
+              return true;
+            }
+
+            var name = m.get('name');
+
+            if(!m.inSchemaWithColumnCheck.apply(this, [m]) &&
+            (_.isUndefined(name)  || _.isNull(name) || name == '')) {
+              return true;
+            }
+            return false;
+          },
+          editable: function(m){
+            var name = m.get('name');
+            // If HeaderCell then allow True
+            if(m instanceof Backbone.Collection) {
+              return true;
+            }
+            // If primary key already exist then disable.
+            if (m.top && !_.isUndefined(m.top.get('oid')) &&
+                      m.top.get('primary_key').length > 0 &&
+                      !_.isUndefined(m.top.get('primary_key').first().get('oid'))) {
+
+              return false;
+            }
+
+            if(!m.inSchemaWithColumnCheck.apply(this, [m]) &&
+              !_.isUndefined(name) && !_.isNull(name) && name !== '') {
+              return true;
+            }
+            return false;
+            // Set to false if no condition is met
+            m.set('is_primary_key', false);
+          }
+        },{
+          id: 'attnum', label:'{{ _('Position') }}', cell: 'string',
+          type: 'text', disabled: 'inSchema', mode: ['properties']
+        },{
+          id: 'cltype', label:'{{ _('Data type') }}', cell: 'node-ajax-options',
+          type: 'text', disabled: 'inSchemaWithColumnCheck',
+          control: 'node-ajax-options', url: 'get_types', node: 'table',
+          cellHeaderClasses:'width_percent_30', first_empty: true,
+          select2: { allowClear: false }, group: '{{ _('Definition') }}',
+          transform: function(data, cell) {
+            /* 'transform' function will be called by control, and cell both.
+             * The way, we use the transform in cell, and control is different.
+             * Because - options are shared using 'column' object in backgrid,
+             * hence - the cell is passed as second parameter, while the control
+             * uses (this) as a object.
+             */
+            var control = cell || this,
+                m = control.model;
+
+            /* We need different data in create mode & in edit mode
+             * if we are in create mode then return data as it is
+             * if we are in edit mode then we need to filter data
+             */
+            control.model.datatypes = data;
+            var edit_types = m.get('edit_types'),
+                result = [];
+
+            // If called from Table, We will check if in edit mode
+            // then send edit_types only
+            if( !_.isUndefined(m.top) && !m.top.isNew() ) {
+              _.each(data, function(t) {
+                if (_.indexOf(edit_types, t.value) != -1) {
+                  result.push(t);
+                }
+            });
+              // There may be case that user adds new column in  existing collection
+              // we will not have edit types then
+              return result.length > 0 ? result : data;
+            }
+
+            // If called from Column
+            if(m.isNew()) {
+              return data;
+            } else {
+              //edit mode
+              _.each(data, function(t) {
+                if (_.indexOf(edit_types, t.value) != -1) {
+                  result.push(t);
+                }
+              });
+
+              return result;
+            }
+          },
+          editable: 'editable_check_for_table'
+        },{
+          // Need to show this field only when creating new table [in SubNode control]
+          id: 'inheritedfrom', label: '{{ _('Inherited from table') }}',
+          type: 'text', disabled: true, editable: false,
+          cellHeaderClasses:'width_percent_30',
+          visible: function(m) {
+            return _.isUndefined(m.top.node_info['table'] || m.top.node_info['view'] || m.top.node_info['mview']);
+          }
+        },{
+          id: 'attlen', label:'{{ _('Length') }}', cell: 'string',
+           deps: ['cltype'], type: 'int', group: '{{ _('Definition') }}',
+           disabled: function(m) {
+             var of_type = m.get('cltype'),
+               flag = true;
+              _.each(m.datatypes, function(o) {
+                if ( of_type == o.value ) {
+                    if(o.length)
+                    {
+                      m.set('min_val', o.min_val, {silent: true});
+                      m.set('max_val', o.max_val, {silent: true});
+                      flag = false;
+                    }
+                }
+              });
+
+              flag && setTimeout(function() {
+                  m.set('attlen', null);
+                },10);
+
+              return flag;
+           }
+        },{
+          id: 'attprecision', label:'{{ _('Precision') }}', cell: 'string',
+           deps: ['cltype'], type: 'int', group: '{{ _('Definition') }}',
+           disabled: function(m) {
+             var of_type = m.get('cltype'),
+               flag = true;
+              _.each(m.datatypes, function(o) {
+                if ( of_type == o.value ) {
+                    if(o.precision)
+                    {
+                      m.set('min_val', o.min_val, {silent: true});
+                      m.set('max_val', o.max_val, {silent: true});
+                      flag = false;
+                    }
+                }
+              });
+
+              flag && setTimeout(function() {
+                  m.set('attprecision', null);
+                },10);
+              return flag;
+           }
+         },{
+          id: 'collspcname', label:'{{ _('Collation') }}', cell: 'string',
+          type: 'text', control: 'node-ajax-options', url: 'get_collations',
+          group: '{{ _('Definition') }}', node: 'collation',
+          deps: ['cltype'], disabled: function(m) {
+             var of_type = m.get('cltype'),
+               flag = true;
+              _.each(m.datatypes, function(o) {
+                if ( of_type == o.value ) {
+                    if(o.is_collatable)
+                    {
+                      flag = false;
+                    }
+                }
+              });
+              if (flag) {
+                setTimeout(function(){
+                  m.set('collspcname', "");
+                }, 10);
+              }
+              return flag;
+          }
+        },{
+          id: 'defval', label:'{{ _('Default Value') }}', cell: 'string',
+          type: 'text', disabled: 'inSchemaWithColumnCheck',
+          group: '{{ _('Definition') }}'
+        },{
+          id: 'attnotnull', label:'{{ _('Not NULL?') }}', cell: 'string',
+          type: 'switch', disabled: 'inSchemaWithColumnCheck',
+          group: '{{ _('Definition') }}'
+        },{
+          id: 'attstattarget', label:'{{ _('Statistics') }}', cell: 'string',
+          type: 'text', disabled: 'inSchemaWithColumnCheck', mode: ['properties', 'edit'],
+          group: '{{ _('Definition') }}'
+        },{
+          id: 'attstorage', label:'{{ _('Storage') }}', group: '{{ _('Definition') }}',
+          type: 'text', mode: ['properties', 'edit'],
+          cell: 'string', disabled: 'inSchemaWithColumnCheck', first_empty: true,
+          control: 'select2', select2: { placeholder: "Select storage",
+            allowClear: false,
+            width: "100%"
+          },
+          options: [
+            {label: "PLAIN", value: "p"},
+            {label: "MAIN", value: "m"},
+            {label: "EXTERNAL", value: "e"},
+            {label: "EXTENDED", value: "x"},
+           ]
+        },{
+          id: 'is_pk', label:'{{ _('Primary key?') }}',
+          type: 'switch', disabled: true, mode: ['properties']
+        },{
+          id: 'is_fk', label:'{{ _('Foreign key?') }}',
+          type: 'switch', disabled: true, mode: ['properties']
+        },{
+          id: 'is_inherited', label:'{{ _('Inherited?') }}',
+          type: 'switch', disabled: true, mode: ['properties']
+        },{
+          id: 'tbls_inherited', label:'{{ _('Inherited from table(s)') }}',
+          type: 'text', disabled: true, mode: ['properties'], deps: ['is_inherited'],
+          visible: function(m) {
+              if (!_.isUndefined(m.get('is_inherited')) && m.get('is_inherited')) {
+                return true;
+              } else {
+                return false;
+              }
+          }
+        },{
+          id: 'is_sys_column', label:'{{ _('System Column?') }}', cell: 'string',
+          type: 'switch', disabled: true, mode: ['properties']
+        },{
+          id: 'description', label:'{{ _('Comment') }}', cell: 'string',
+          type: 'multiline', mode: ['properties', 'create', 'edit'],
+          disabled: 'inSchema'
+        },{
+          id: 'attacl', label: 'Privileges', type: 'collection',
+          group: '{{ _('Security') }}', control: 'unique-col-collection',
+          model: pgAdmin.Browser.Node.PrivilegeRoleModel.extend({
+          privileges: ['a','r','w','x']}),
+          mode: ['edit'], canAdd: true, canDelete: true,
+          uniqueCol : ['grantee']
+        },{
+          id: 'attoptions', label: 'Variables', type: 'collection',
+          group: '{{ _('Security') }}', control: 'unique-col-collection',
+          model: VariablesModel, uniqueCol : ['name'],
+          mode: ['edit', 'create'], canAdd: true, canEdit: false,
+          canDelete: true
+        },{
+          id: 'seclabels', label: '{{ _('Security Labels') }}',
+          model: pgAdmin.Browser.SecurityModel,
+          editable: false, type: 'collection',
+          group: '{{ _('Security') }}', mode: ['edit', 'create'],
+          min_version: 90100, canAdd: true,
+          canEdit: false, canDelete: true, control: 'unique-col-collection'
+        }
+        ],
+        validate: function(keys) {
+          var err = {},
+              changedAttrs = this.changed,
+              msg = undefined;
+
+          // Nothing to validate
+          if (keys && keys.length == 0) {
+            this.errorModel.clear();
+            return null;
+          } else {
+            this.errorModel.clear();
+          }
+
+          if (_.isUndefined(this.get('name'))
+              || String(this.get('name')).replace(/^\s+|\s+$/g, '') == '') {
+            msg = '{{ _('Column name can not be empty.') }}';
+            this.errorModel.set('name', msg);
+            return msg;
+          }
+
+          if (_.isUndefined(this.get('cltype'))
+              || String(this.get('cltype')).replace(/^\s+|\s+$/g, '') == '') {
+            msg = '{{ _('Column type can not be empty.') }}';
+            this.errorModel.set('cltype', msg);
+            return msg;
+          }
+
+          if (!_.isUndefined(this.get('cltype'))
+                && !_.isUndefined(this.get('attlen'))
+                && !_.isNull(this.get('attlen'))
+                && this.get('attlen') !== '') {
+            // Validation for Length field
+            if (this.get('attlen') < this.get('min_val'))
+              msg = '{{ _('Length should not be less than: ') }}' + this.get('min_val');
+            if (this.get('attlen') > this.get('max_val'))
+              msg = '{{ _('Length should not be greater than: ') }}' + this.get('max_val');
+            // If we have any error set then throw it to user
+            if(msg) {
+              this.errorModel.set('attlen', msg)
+              return msg;
+            }
+          }
+
+          if (!_.isUndefined(this.get('cltype'))
+                && !_.isUndefined(this.get('attprecision'))
+                && !_.isNull(this.get('attprecision'))
+                && this.get('attprecision') !== '') {
+            // Validation for precision field
+            if (this.get('attprecision') < this.get('min_val'))
+              msg = '{{ _('Precision should not be less than: ') }}' + this.get('min_val');
+            if (this.get('attprecision') > this.get('max_val'))
+              msg = '{{ _('Precision should not be greater than: ') }}' + this.get('max_val');
+            // If we have any error set then throw it to user
+            if(msg) {
+              this.errorModel.set('attprecision', msg)
+              return msg;
+            }
+          }
+
+          return null;
+        },
+        isInhertedColumn: function() {
+        },
+        // We will check if we are under schema node & in 'create' mode
+        inSchema: function() {
+          if(this.node_info &&  'catalog' in this.node_info)
+          {
+            return true;
+          }
+          return false;
+        },
+        // We will check if we are under schema node & in 'create' mode
+        inSchemaWithModelCheck: function(m) {
+          if(this.node_info &&  'schema' in this.node_info)
+          {
+            // We will disable control if it's in 'edit' mode
+            if (m.isNew()) {
+              return false;
+            } else {
+              return true;
+            }
+          }
+          return true;
+        },
+        // Checks weather to enable/disable control
+        inSchemaWithColumnCheck: function(m) {
+          var node_info = this.node_info || m.node_info || m.top.node_info;
+
+          // disable all fields if column is listed under view or mview
+          if ('view' in node_info || 'mview' in node_info) {
+            if (this && _.has(this, 'name') && (this.name != 'defval')) {
+              return true;
+            }
+          }
+
+          if(node_info &&  'schema' in node_info)
+          {
+            // We will disable control if it's system columns
+            // inheritedfrom check is useful when we use this schema in table node
+            // inheritedfrom has value then we should disable it
+            if(!_.isUndefined(m.get('inheritedfrom'))) {
+                return true;
+            }
+            // ie: it's position is less then 1
+            if (m.isNew()) {
+              return false;
+            }
+            // if we are in edit mode
+            if (!_.isUndefined(m.get('attnum')) && m.get('attnum') > 0 ) {
+              return false;
+            } else {
+              return true;
+            }
+           }
+          return true;
+        },
+        editable_check_for_table: function(arg) {
+            if (arg instanceof Backbone.Collection) {
+                return !arg.model.prototype.inSchemaWithColumnCheck.apply(
+                         this, [arg.top]
+                       );
+            } else {
+                return !arg.inSchemaWithColumnCheck.apply(
+                         this, [arg]
+                       );
+            }
+        }
+      }),
+      // Below function will enable right click menu for creating column
+      canCreate: function(itemData, item, data) {
+          // If check is false then , we will allow create menu
+          if (data && data.check == false)
+            return true;
+
+          var t = pgBrowser.tree, i = item, d = itemData, parents = [];
+          // To iterate over tree to check parent node
+          while (i) {
+            // If it is schema then allow user to create table
+            if (_.indexOf(['schema'], d._type) > -1) {
+              return true;
+            }
+            else if (_.indexOf(['view', 'coll-view',
+                                'mview',
+                                'coll-mview'], d._type) > -1) {
+              parents.push(d._type);
+              break;
+            }
+            parents.push(d._type);
+            i = t.hasParent(i) ? t.parent(i) : null;
+            d = i ? t.itemData(i) : null;
+          }
+          // If node is under catalog then do not allow 'create' menu
+          if (_.indexOf(parents, 'catalog') > -1 ||
+              _.indexOf(parents, 'coll-view') > -1 ||
+              _.indexOf(parents, 'coll-mview') > -1 ||
+              _.indexOf(parents, 'mview') > -1 ||
+              _.indexOf(parents, 'view') > -1) {
+            return false;
+          } else {
+            return true;
+          }
+      }
+  });
+ }
+
+  return pgBrowser.Nodes['column'];
+});
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/templates/column/macros/privilege.macros b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/templates/column/macros/privilege.macros
new file mode 100644
index 0000000..7eafd60
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/templates/column/macros/privilege.macros
@@ -0,0 +1,13 @@
+{% macro APPLY(conn, schema_name, table_object, column_object, role, privs, with_grant_privs) -%}
+{% if privs %}
+GRANT {% for p in privs %}{% if loop.index != 1 %}, {% endif %}{{p}}({{conn|qtIdent(column_object)}}){% endfor %}
+ ON {{ conn|qtIdent(schema_name, table_object) }} TO {{ conn|qtIdent(role) }};
+{% endif %}
+{% if with_grant_privs %}
+GRANT {% for p in with_grant_privs %}{% if loop.index != 1 %}, {% endif %}{{p}}({{conn|qtIdent(column_object)}}){% endfor %}
+ ON {{ conn|qtIdent(schema_name, table_object) }} TO {{ conn|qtIdent(role) }} WITH GRANT OPTION;
+{% endif %}
+{%- endmacro %}
+{% macro RESETALL(conn, schema_name, table_object, column_object, role) -%}
+REVOKE ALL({{ conn|qtIdent(column_object) }}) ON {{ conn|qtIdent(schema_name, table_object) }} FROM {{ conn|qtIdent(role) }};
+{%- endmacro %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/templates/column/macros/security.macros b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/templates/column/macros/security.macros
new file mode 100644
index 0000000..39587c3
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/templates/column/macros/security.macros
@@ -0,0 +1,6 @@
+{% macro APPLY(conn, type, schema_name, parent_object, child_object, provider, label) -%}
+SECURITY LABEL FOR {{ conn|qtIdent(provider) }} ON {{ type }} {{ conn|qtIdent(schema_name, parent_object, child_object) }} IS {{ label|qtLiteral }};
+{%- endmacro %}
+{% macro DROP(conn, type, schema_name, parent_object, child_object, provider) -%}
+SECURITY LABEL FOR {{ conn|qtIdent(provider) }} ON {{ type }} {{ conn|qtIdent(schema_name, parent_object, child_object) }} IS NULL;
+{%- endmacro %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/__init__.py
new file mode 100644
index 0000000..475c71f
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/__init__.py
@@ -0,0 +1,133 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+"""Implements Constraint Node"""
+
+from flask.ext.babel import gettext
+from flask import render_template, make_response
+from pgadmin.browser.collection import CollectionNodeModule
+import pgadmin.browser.server_groups.servers.databases as database
+from pgadmin.utils.ajax import make_json_response, \
+     make_response as ajax_response
+from .type import ConstraintRegistry
+
+
+class ConstraintsModule(CollectionNodeModule):
+    """
+    class ConstraintsModule(CollectionNodeModule)
+
+        A module class for Constraint node derived from CollectionNodeModule.
+
+    Methods:
+    -------
+    * __init__(*args, **kwargs)
+      - Method is used to initialize the ConstraintsModule and it's base module.
+
+    * get_nodes(gid, sid, did)
+      - Method is used to generate the browser collection node.
+
+    * node_inode()
+      - Method is overridden from its base class to make the node as leaf node.
+
+    * script_load()
+      - Load the module script for constraint node, when any of the database node is
+        initialized.
+    """
+
+    NODE_TYPE = 'constraints'
+    COLLECTION_LABEL = gettext("Constraints")
+
+    def __init__(self, *args, **kwargs):
+        self.min_ver = None
+        self.max_ver = None
+        super(ConstraintsModule, self).__init__(*args, **kwargs)
+
+    def get_nodes(self, gid, sid, did, scid, tid):
+        """
+        Generate the collection node
+        """
+        yield self.generate_browser_collection_node(tid)
+
+    @property
+    def script_load(self):
+        """
+        Load the module script for constraints, when any of the table node is
+        initialized.
+        """
+        return database.DatabaseModule.NODE_TYPE
+
+blueprint = ConstraintsModule(__name__)
+
+
+@blueprint.route('/nodes/<int:gid>/<int:sid>/<int:did>/<int:scid>/<int:tid>/')
+def nodes(**kwargs):
+    """
+    Returns all constraint as a tree node.
+
+    Args:
+      **kwargs:
+
+    Returns:
+
+    """
+
+    cmd = {"cmd": "nodes"}
+    res = []
+    for name in ConstraintRegistry.registry:
+        module = (ConstraintRegistry.registry[name])['nodeview']
+        view = module(**cmd)
+        res = res + view.get_nodes(**kwargs)
+
+    return make_json_response(
+                data=res,
+                status=200
+                )
+
+
+@blueprint.route('/obj/<int:gid>/<int:sid>/<int:did>/<int:scid>/<int:tid>/')
+def proplist(**kwargs):
+    """
+    Returns all constraint with properties.
+    Args:
+      **kwargs:
+
+    Returns:
+
+    """
+
+    cmd = {"cmd": "obj"}
+    res = []
+    for name in ConstraintRegistry.registry:
+        module = (ConstraintRegistry.registry[name])['nodeview']
+        view = module(**cmd)
+        res = res + view.get_node_list(**kwargs)
+
+    return ajax_response(
+                response=res,
+                status=200
+                )
+
+
+@blueprint.route('/module.js')
+def module_js():
+    """
+      This property defines whether javascript exists for this node.
+
+    """
+    return make_response(
+            render_template(
+                "constraints/js/constraints.js",
+                _=gettext,
+                constraints=[
+                  (ConstraintRegistry.registry[n])['blueprint'].NODE_TYPE \
+                  for n in ConstraintRegistry.registry
+                  ]
+                ),
+            200, {'Content-Type': 'application/x-javascript'}
+            )
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/__init__.py
new file mode 100644
index 0000000..f2eb81b
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/__init__.py
@@ -0,0 +1,833 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+"""Implements the Check Constraint Module."""
+
+import json
+from flask import render_template, make_response, request, jsonify
+from flask.ext.babel import gettext as _
+from pgadmin.utils.ajax import make_json_response, \
+    make_response as ajax_response, internal_server_error
+from pgadmin.browser.utils import PGChildNodeView
+from pgadmin.browser.collection import CollectionNodeModule
+import pgadmin.browser.server_groups.servers.databases as database
+from pgadmin.utils.ajax import precondition_required
+from pgadmin.utils.driver import get_driver
+from config import PG_DEFAULT_DRIVER
+from functools import wraps
+from pgadmin.browser.server_groups.servers.databases.schemas.tables.constraints.type \
+    import ConstraintRegistry, ConstraintTypeModule
+
+
+class CheckConstraintModule(CollectionNodeModule):
+    """
+    class CheckConstraintModule(CollectionNodeModule):
+
+        This class represents The Check Constraint Module.
+
+    Methods:
+    -------
+    * __init__(*args, **kwargs)
+      - Initialize the Check Constraint Module.
+
+    * get_nodes(gid, sid, did, scid)
+      - Generate the Check Constraint collection node.
+
+    * node_inode(gid, sid, did, scid)
+      - Returns Check Constraint node as leaf node.
+
+    * script_load()
+      - Load the module script for the Check Constraint, when any of the
+        Check node is initialized.
+    """
+    NODE_TYPE = 'check_constraints'
+    COLLECTION_LABEL = _("Check Constraints")
+
+    def __init__(self, *args, **kwargs):
+        super(CheckConstraintModule, self).__init__(*args, **kwargs)
+        self.min_ver = None
+        self.max_ver = None
+
+    def get_nodes(self, gid, sid, did, scid, doid):
+        """
+        Generate the Check Constraint collection node.
+        """
+        yield self.generate_browser_collection_node(doid)
+
+    @property
+    def node_inode(self):
+        """
+        Returns Check Constraint node as leaf node.
+        """
+        return False
+
+    @property
+    def script_load(self):
+        """
+        Load the module script for the Check Constraint, when any of the
+        Check node is initialized.
+        """
+        return database.DatabaseModule.NODE_TYPE
+
+    @property
+    def csssnippets(self):
+        """
+        Returns a snippet of css to include in the page
+        """
+        return [
+                render_template(
+                    "check_constraint/css/check_constraint.css",
+                    node_type=self.node_type
+                    )
+                ]
+
+
+blueprint = CheckConstraintModule(__name__)
+
+
+class CheckConstraintView(PGChildNodeView):
+    """
+    class CheckConstraintView(PGChildNodeView):
+
+    This class inherits PGChildNodeView to get the different routes for
+    the module.
+
+    The class is responsible to Create, Read, Update and Delete operations for
+    the Check Constraint.
+
+    Methods:
+    -------
+
+    * module_js():
+      - Load JS file (check-constraints.js) for this module.
+
+    * check_precondition(f):
+      - Works as a decorator.
+      -  Checks database connection status.
+      -  Attach connection object and template path.
+
+    * list(gid, sid, did, scid, doid):
+      - List the Check Constraints.
+
+    * nodes(gid, sid, did, scid):
+      - Returns all the Check Constraints to generate Nodes in the browser.
+
+    * properties(gid, sid, did, scid, doid):
+      - Returns the Check Constraint properties.
+
+    * create(gid, sid, did, scid):
+      - Creates a new Check Constraint object.
+
+    * update(gid, sid, did, scid, doid):
+      - Updates the Check Constraint object.
+
+    * delete(gid, sid, did, scid, doid):
+      - Drops the Check Constraint object.
+
+    * sql(gid, sid, did, scid, doid=None):
+      - Returns the SQL for the Check Constraint object.
+
+    * msql(gid, sid, did, scid, doid=None):
+      - Returns the modified SQL.
+
+    * get_sql(gid, sid, data, scid, tid=None):
+      - Generates the SQL statements to create/update the Check Constraint.
+        object.
+
+    * dependents(gid, sid, did, scid, tid, cid):
+      - Returns the dependents for the Check Constraint object.
+
+    * dependencies(gid, sid, did, scid, tid, cid):
+      - Returns the dependencies for the Check Constraint object.
+
+    * validate_check_constraint(gid, sid, did, scid, tid, cid):
+      - Validate check constraint.
+    """
+    node_type = blueprint.node_type
+
+    parent_ids = [
+        {'type': 'int', 'id': 'gid'},
+        {'type': 'int', 'id': 'sid'},
+        {'type': 'int', 'id': 'did'},
+        {'type': 'int', 'id': 'scid'},
+        {'type': 'int', 'id': 'tid'}
+    ]
+    ids = [
+        {'type': 'int', 'id': 'cid'}
+    ]
+
+    operations = dict({
+        'obj': [
+            {'get': 'properties', 'delete': 'delete', 'put': 'update'},
+            {'get': 'list', 'post': 'create'}
+        ],
+        'delete': [{'delete': 'delete'}],
+        'children': [{'get': 'children'}],
+        'nodes': [{'get': 'node'}, {'get': 'nodes'}],
+        'sql': [{'get': 'sql'}],
+        'msql': [{'get': 'msql'}, {'get': 'msql'}],
+        'stats': [{'get': 'statistics'}],
+        'dependency': [{'get': 'dependencies'}],
+        'dependent': [{'get': 'dependents'}],
+        'module.js': [{}, {}, {'get': 'module_js'}],
+        'validate': [{'get': 'validate_check_constraint'}],
+    })
+
+    def module_js(self):
+        """
+        Load JS file (check_constraint.js) for this module.
+        """
+        return make_response(
+            render_template(
+                "check_constraint/js/check_constraint.js",
+                _=_
+            ),
+            200, {'Content-Type': 'application/x-javascript'}
+        )
+
+    def check_precondition(f):
+        """
+        Works as a decorator.
+        Checks database connection status.
+        Attach connection object and template path.
+        """
+        @wraps(f)
+        def wrap(*args, **kwargs):
+            self = args[0]
+            driver = get_driver(PG_DEFAULT_DRIVER)
+            self.manager = driver.connection_manager(kwargs['sid'])
+            self.conn = self.manager.connection(did=kwargs['did'])
+            self.qtIdent = driver.qtIdent
+
+            # If DB not connected then return error to browser
+            if not self.conn.connected():
+                return precondition_required(
+                    _("Connection to the server has been lost!")
+                )
+
+            ver = self.manager.version
+
+            # we will set template path for sql scripts
+            if ver >= 90200:
+                self.template_path = 'check_constraint/sql/9.2_plus'
+            elif ver >= 90100:
+                self.template_path = 'check_constraint/sql/9.1_plus'
+
+            SQL = render_template("/".join([self.template_path,
+                                            'get_parent.sql']),
+                                  tid=kwargs['tid'])
+            status, rset = self.conn.execute_2darray(SQL)
+            if not status:
+                return internal_server_error(errormsg=rset)
+
+            self.schema = rset['rows'][0]['schema']
+            self.table = rset['rows'][0]['table']
+
+            return f(*args, **kwargs)
+
+        return wrap
+
+    def end_transaction(self):
+        """
+            End database transaction.
+        Returns:
+
+        """
+        SQL = "END;"
+        self.conn.execute_scalar(SQL)
+
+    @check_precondition
+    def list(self, gid, sid, did, scid, tid, cid=None):
+        """
+        List the Check Constraints.
+
+        Args:
+            gid: Server Group Id
+            sid: Server Id
+            did: Database Id
+            scid: Schema Id
+            tid: Table Id
+            cid: Check Id
+        """
+        try:
+            res = self.get_node_list(gid, sid, did, scid, tid, cid)
+            return ajax_response(
+                    response=res,
+                    status=200
+                    )
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def get_node_list(self, gid, sid, did, scid, tid, cid=None):
+        """
+        This function returns all check constraints
+        nodes within that collection as a list.
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          cid: Cehck constraint ID
+
+        Returns:
+
+        """
+        SQL = render_template("/".join([self.template_path, 'properties.sql']),
+                              tid=tid)
+        status, res = self.conn.execute_dict(SQL)
+
+        return res['rows']
+
+    @check_precondition
+    def nodes(self, gid, sid, did, scid, tid, cid=None):
+        """
+        Returns all the Check Constraints.
+
+        Args:
+            gid: Server Group Id
+            sid: Server Id
+            did: Database Id
+            scid: Schema Id
+            tid: Table Id
+            cid: Check constraint Id.
+        """
+        try:
+            res = self.get_nodes(gid, sid, did, scid, tid, cid)
+            return make_json_response(
+                    data=res,
+                    status=200
+                    )
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def get_nodes(self, gid, sid, did, scid, tid, cid=None):
+        """
+        This function returns all event check constraint as a list.
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          cid: Check constraint ID
+
+        Returns:
+
+        """
+        res = []
+        SQL = render_template("/".join([self.template_path,
+                                        'nodes.sql']),
+                              tid=tid)
+        status, rset = self.conn.execute_2darray(SQL)
+
+        for row in rset['rows']:
+            if "convalidated" in row and row["convalidated"]:
+                icon = "icon-check_constraints_bad"
+                valid = False
+            else:
+                icon = "icon-check_constraints"
+                valid = True
+            res.append(
+                    self.blueprint.generate_browser_node(
+                        row['oid'],
+                        tid,
+                        row['name'],
+                        icon=icon,
+                        valid=valid
+                    ))
+        return res
+
+    @check_precondition
+    def properties(self, gid, sid, did, scid, tid, cid):
+        """
+        Returns the Check Constraints property.
+
+        Args:
+            gid: Server Group Id
+            sid: Server Id
+            did: Database Id
+            scid: Schema Id
+            tid: Check Id
+            cid: Check Constraint Id
+        """
+
+        SQL = render_template("/".join([self.template_path,
+                                        'properties.sql']),
+                              tid=tid, cid=cid)
+        status, res = self.conn.execute_dict(SQL)
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        data = res['rows'][0]
+        return ajax_response(
+            response=data,
+            status=200
+        )
+
+    @check_precondition
+    def create(self, gid, sid, did, scid, tid, cid=None):
+        """
+        This function will create a primary key.
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          cid: Check constraint ID
+
+        Returns:
+
+        """
+        required_args = ['consrc']
+
+        data = request.form if request.form else json.loads(request.data.decode())
+
+        for k, v in data.items():
+            try:
+                data[k] = json.loads(v)
+            except (ValueError, TypeError):
+                data[k] = v
+
+        for arg in required_args:
+            if arg not in data or data[arg] == '':
+                return make_json_response(
+                    status=400,
+                    success=0,
+                    errormsg=_(
+                        "Couldn't find the required parameter (%s)." % arg
+                    )
+                )
+
+        data['schema'] = self.schema
+        data['table'] = self.table
+        try:
+            if 'name' not in data or data['name'] == "":
+                SQL = "BEGIN;"
+                # Start transaction.
+                status, res = self.conn.execute_scalar(SQL)
+                if not status:
+                    self.end_transaction()
+                    return internal_server_error(errormsg=res)
+
+            # The below SQL will execute CREATE DDL only
+            SQL = render_template(
+                "/".join([self.template_path, 'create.sql']),
+                data=data
+                )
+
+            status, msg = self.conn.execute_scalar(SQL)
+            if not status:
+                self.end_transaction()
+                return internal_server_error(errormsg=msg)
+
+            if 'name' not in data or data['name'] == "":
+                sql = render_template(
+                    "/".join([self.template_path,
+                              'get_oid_with_transaction.sql'],
+                             ),
+                    tid=tid)
+
+                status, res = self.conn.execute_dict(sql)
+                if not status:
+                    self.end_transaction()
+                    return internal_server_error(errormsg=res)
+
+                self.end_transaction()
+
+                data['name'] = res['rows'][0]['name']
+
+            else:
+                sql = render_template("/".join([self.template_path, 'get_oid.sql']),
+                                      tid=tid,
+                                      name=data['name'])
+                status, res = self.conn.execute_dict(sql)
+                if not status:
+                    self.end_transaction()
+                    return internal_server_error(errormsg=res)
+
+            if "convalidated" in res['rows'][0] and res['rows'][0]["convalidated"]:
+                icon = "icon-check_constraints_bad"
+                valid = False
+            else:
+                icon = "icon-check_constraints"
+                valid = True
+
+            sql = render_template("/".join([self.template_path, 'alter.sql']),
+                                  data=data,
+                                  conn=self.conn)
+            sql = sql.strip('\n').strip(' ')
+
+            if sql != '':
+                status, result = self.conn.execute_scalar(sql)
+                if not status:
+                    self.end_transaction()
+                    return internal_server_error(errormsg=result)
+
+            return jsonify(
+                node=self.blueprint.generate_browser_node(
+                    res['rows'][0]['oid'],
+                    tid,
+                    data['name'],
+                    icon=icon,
+                    valid=valid
+                    )
+                )
+
+        except Exception as e:
+            self.end_transaction()
+            return make_json_response(
+                status=400,
+                success=0,
+                errormsg=e
+            )
+
+    @check_precondition
+    def delete(self, gid, sid, did, scid, tid, cid):
+        """
+        Drops the Check Constraint object.
+
+        Args:
+            gid: Server Group Id
+            sid: Server Id
+            did: Database Id
+            scid: Schema Id
+            tid: Check Id
+            cid: Check Constraint Id
+        """
+        try:
+            SQL = render_template("/".join([self.template_path,
+                                            'properties.sql']),
+                                  tid=tid, cid=cid)
+            status, res = self.conn.execute_dict(SQL)
+
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            data = res['rows'][0]
+
+            SQL = render_template("/".join([self.template_path,
+                                            'delete.sql']),
+                                  data=data)
+            status, res = self.conn.execute_scalar(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            return make_json_response(
+                success=1,
+                info=_("Check Constraint dropped"),
+                data={
+                    'id': tid,
+                    'scid': scid,
+                    'sid': sid,
+                    'gid': gid,
+                    'did': did
+                }
+            )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def update(self, gid, sid, did, scid, tid, cid):
+        """
+        Updates the Check Constraint object.
+
+        Args:
+            gid: Server Group Id
+            sid: Server Id
+            did: Database Id
+            scid: Schema Id
+            tid: Table Id
+            cid: Check Constraint Id
+        """
+        data = request.form if request.form else json.loads(request.data.decode())
+
+        try:
+            data['schema'] = self.schema
+            data['table'] = self.table
+
+            SQL = self.get_sql(gid, sid, data, scid, tid, cid)
+            SQL = SQL.strip('\n').strip(' ')
+            if SQL != "":
+                status, res = self.conn.execute_scalar(SQL)
+                if not status:
+                    return internal_server_error(errormsg=res)
+
+                sql = render_template("/".join([self.template_path, 'get_name.sql']),
+                                      cid=cid)
+                status, res = self.conn.execute_dict(sql)
+                if not status:
+                    return internal_server_error(errormsg=res)
+
+                if "convalidated" in res['rows'][0] and res['rows'][0]["convalidated"]:
+                    icon = 'icon-check_constraints_)bad'
+                    valid = False
+                else:
+                    icon = 'icon-check_constraints'
+                    valid = True
+
+                return make_json_response(
+                    success=1,
+                    info="Check Constraint updated",
+                    data={
+                        'id': cid,
+                        'tid': tid,
+                        'scid': scid,
+                        'sid': sid,
+                        'gid': gid,
+                        'did': did,
+                        'icon': icon,
+                        'val    id': valid
+                    }
+                )
+            else:
+                return make_json_response(
+                    success=1,
+                    info="Nothing to update",
+                    data={
+                        'id': cid,
+                        'tid': tid,
+                        'scid': scid,
+                        'sid': sid,
+                        'gid': gid,
+                        'did': did
+                    }
+                )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def sql(self, gid, sid, did, scid, tid, cid=None):
+        """
+        Returns the SQL for the Check Constraint object.
+
+        Args:
+            gid: Server Group Id
+            sid: Server Id
+            did: Database Id
+            scid: Schema Id
+            tid: Table Id
+            cid: Check Constraint Id
+        """
+
+        SQL = render_template("/".join([self.template_path,
+                                        'properties.sql']),
+                              tid=tid, cid=cid)
+        status, res = self.conn.execute_dict(SQL)
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        data = res['rows'][0]
+        data['schema'] = self.schema
+        data['table'] = self.table
+
+        SQL = render_template("/".join([self.template_path,
+                                        'create.sql']),
+                              data=data)
+        SQL += "\n"
+        SQL += render_template(
+                "/".join([self.template_path, 'alter.sql']),
+                data=data)
+
+        sql_header = "-- Constraint: {0}\n\n-- ".format(data['name'])
+
+        sql_header += render_template(
+                "/".join([self.template_path, 'delete.sql']),
+                data=data)
+        sql_header += "\n"
+
+        SQL = sql_header + SQL
+
+        return ajax_response(response=SQL)
+
+    @check_precondition
+    def msql(self, gid, sid, did, scid, tid, cid=None):
+        """
+        Returns the modified SQL.
+
+        Args:
+            gid: Server Group Id
+            sid: Server Id
+            did: Database Id
+            scid: Schema Id
+            tid: Table Id
+            cid: Check Constraint Id
+
+        Returns:
+            Check Constraint object in json format.
+        """
+        data = {}
+        for k, v in request.args.items():
+            try:
+                data[k] = json.loads(v)
+            except ValueError:
+                data[k] = v
+
+        data['schema'] = self.schema
+        data['table'] = self.table
+        try:
+            sql = self.get_sql(gid, sid, data, scid, tid, cid)
+            sql = sql.strip('\n').strip(' ')
+
+            return make_json_response(
+                    data=sql,
+                    status=200
+                    )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    def get_sql(self, gid, sid, data, scid, tid, cid=None):
+        """
+        Generates the SQL statements to create/update the Check Constraint.
+
+         Args:
+            gid: Server Group Id
+            sid: Server Id
+            did: Database Id
+            scid: Schema Id
+            tid: Table Id
+            cid: Check Constraint Id
+        """
+        try:
+            if cid is not None:
+                SQL = render_template("/".join([self.template_path,
+                                                'properties.sql']),
+                                      tid=tid, cid=cid)
+                status, res = self.conn.execute_dict(SQL)
+
+                if not status:
+                    return False, internal_server_error(errormsg=res)
+
+                old_data = res['rows'][0]
+                required_args = ['name']
+                for arg in required_args:
+                    if arg not in data:
+                        data[arg] = old_data[arg]
+
+                SQL = render_template(
+                    "/".join([self.template_path, 'update.sql']),
+                    data=data, o_data=old_data, conn=self.conn
+                    )
+            else:
+                required_args = ['consrc']
+
+                for arg in required_args:
+                    if arg not in data:
+                        return _('-- definition incomplete')
+                    elif isinstance(data[arg], list) and len(data[arg]) < 1:
+                        return _('-- definition incomplete')
+
+                SQL = render_template("/".join([self.template_path,
+                                                'create.sql']),
+                                      data=data)
+                SQL += "\n"
+                SQL += render_template("/".join([self.template_path, 'alter.sql']),
+                                       data=data)
+
+            return SQL
+        except Exception as e:
+            return False, internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def dependents(self, gid, sid, did, scid, tid, cid):
+        """
+        This function get the dependents and return ajax response
+        for the Check Constraint node.
+
+        Args:
+            gid:  Server Group Id
+            sid:  Server Id
+            did:  Database Id
+            scid: Schema Id
+            tid: Table Id
+            cid: Check Constraint Id
+        """
+        dependents_result = self.get_dependents(self.conn, cid)
+        return ajax_response(
+                response=dependents_result,
+                status=200
+                )
+
+    @check_precondition
+    def dependencies(self, gid, sid, did, scid, tid, cid):
+        """
+        This function get the dependencies and return ajax response
+        for the Check Constraint node.
+
+        Args:
+            gid: Server Group Id
+            sid: Server Id
+            did: Database Id
+            scid: Schema Id
+            tid: Table Id
+            cid: Check Constraint Id
+        """
+        dependencies_result = self.get_dependencies(self.conn, cid)
+        return ajax_response(
+                response=dependencies_result,
+                status=200
+                )
+
+    @check_precondition
+    def validate_check_constraint(self, gid, sid, did, scid, tid, cid):
+        """
+        Validate check constraint.
+        Args:
+            gid: Server Group Id
+            sid: Server Id
+            did: Database Id
+            scid: Schema Id
+            tid: Table Id
+            cid: Check Constraint Id
+
+        Returns:
+
+        """
+        data = {}
+        try:
+            data['schema'] = self.schema
+            data['table'] = self.table
+            sql = render_template("/".join([self.template_path, 'get_name.sql']), cid=cid)
+            status, res = self.conn.execute_scalar(sql)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            data['name'] = res
+            sql = render_template("/".join([self.template_path, 'validate.sql']), data=data)
+            status, res = self.conn.execute_dict(sql)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            return make_json_response(
+                success=1,
+                info=_("Check constraint updated."),
+                data={
+                    'id': cid,
+                    'tid': tid,
+                    'scid': scid,
+                    'did': did
+                }
+            )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+constraint = ConstraintRegistry(
+    'check_constraint', CheckConstraintModule, CheckConstraintView
+    )
+CheckConstraintView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/static/img/check-constraints-bad.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/static/img/check-constraints-bad.png
new file mode 100644
index 0000000000000000000000000000000000000000..32a045b8fafdc08640d53b2a86b1dcabcb0fe0fd
GIT binary patch
literal 579
zcmV-J0=)f+P)<h;3K|Lk000e1NJLTq000mG000mO0{{R3C@l|D00001b5ch_0Itp)
z=>Px$AW%$HMR1Z9#Q*@REHmdHAm<<;=p`lTDl6$LE15$|nM6yxJ3#6&F}^)Qx<p3n
zH#h4zIK)Ou#79fTM@#HJKkY(8?L$QEL`CjJMeasM?ng(;QB>|oNbX2U?n+AUOH1!e
zOz%xi?@dncPEXKRS?^Cz#amtQQBm+xQt(q#@KaRqR8;U)Rq<9<@mE*YVq(`~V)0vB
z+GS<)VPW%PV%=$Jag!JHXlV6qZS`($_HuH3pd<EncJ_C7f1@XWqbGu>Du=8uhpjJ)
zvN4agH<i3UrMYgWyK<eyN1Vq+p2tbA!G5C3PO!m$q|HvV#D$~JOsv;ftk_qv-CeQX
zT*cC%$J3;><6_L$t<Kr8)!w|r@o>cPam4X*+~mi`^K{Glc|xh<NdN!<0d!JMQvg8b
z*k%9#00Cl4M??UK1szBL000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipf34<ROg
z(p72z0056kL_t&-)1{2Z3c^qT1mDEody6IZuCW&s1V!`^4}$goe?(18@b2Db*j*w1
z%4M(p;&Zw?9ZaKAxo*x;COX}<8fzjqKRv^2kF1spymYHMjE2m7Hl|a~emCNwG8(i?
z8I#``(kiBrEbh}(Qn8TL2+$}b3Hn^7p`K6R#_6zQ2$?ux;lXBYB>hkN@C%g?4vVBM
R$bbL<002ovPDHLkV1min0OSAw

literal 0
HcmV?d00001

diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/static/img/check-constraints.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/static/img/check-constraints.png
new file mode 100644
index 0000000000000000000000000000000000000000..9d1d2a061c7948168d7b1c2474d769b31709f1cf
GIT binary patch
literal 406
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbK}X@F0NE08{VY2nhHc^eMaU%j`d
zaI$#+HuEKC{pKEZKYn>h(+aIMH^MjGjcs3}f9Cqyt&fvx7AT*)xv^`L;hf{Hi_iP4
zxgK%&V?q65_4c*;8}G%;JMMY<SLM___M4Bi9{E^!<YUpX&n1ga`7PgFwEkdS!(#P<
zNn&@N9OqiK(i&(nV@Z%-FoVOh8)-leXMsm#F_88EW4Dvpc0fjir;B5V#O36K1sn!O
zhRVf}5jSsGPH?f<xudc|vBoY<&5cb=uTGB9v187J4II+it5?jhn8F{TsCZIWRad$D
zg1*K9W%cu2NsD(hEfVT#*wm#pYw;D04+0E(uQE?s`Z6*ZXoqTvYeY#(Vo9o1a#1Rf
zVlXl=G|)9P(lsy)F*2|+F}5->(Kax(GBB{1sVaw}AvZrIGp!P$!N3x%0i@c>zzm|{
T)b!9bKn)C@u6{1-oD!M<=4O^k

literal 0
HcmV?d00001

diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/css/check_constraint.css b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/css/check_constraint.css
new file mode 100644
index 0000000..0691868
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/css/check_constraint.css
@@ -0,0 +1,15 @@
+.icon-check_bad, .icon-check_constraints_bad {
+  background-image: url('{{ url_for('NODE-%s.static' % node_type, filename='img/check-constraints-bad.png' )}}') !important;
+  background-repeat: no-repeat;
+  align-content: center;
+  vertical-align: middle;
+  height: 1.3em;
+}
+
+.icon-check, .icon-check_constraints {
+  background-image: url('{{ url_for('NODE-%s.static' % node_type, filename='img/check-constraints.png' )}}') !important;
+  background-repeat: no-repeat;
+  align-content: center;
+  vertical-align: middle;
+  height: 1.3em;
+}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/js/check_constraint.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/js/check_constraint.js
new file mode 100644
index 0000000..afc5ba9
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/js/check_constraint.js
@@ -0,0 +1,216 @@
+// Check Constraint Module: Node
+define(
+  [
+   'jquery', 'underscore', 'underscore.string', 'pgadmin', 'pgadmin.browser',
+   'alertify', 'pgadmin.browser.collection'
+  ],
+function($, _, S, pgAdmin, pgBrowser, Alertify) {
+
+  // Check Constraint Node
+  if (!pgBrowser.Nodes['check_constraints']) {
+    pgAdmin.Browser.Nodes['check_constraints'] = pgBrowser.Node.extend({
+      type: 'check_constraints',
+      label: '{{ _('Check') }}',
+      collection_type: 'coll-constraints',
+      sqlAlterHelp: 'ddl-alter.html',
+      sqlCreateHelp: 'ddl-constraints.html',
+      hasSQL: true,
+      hasDepends: true,
+      parent_type: ['table'],
+      Init: function() {
+        // Avoid mulitple registration of menus
+        if (this.initialized)
+            return;
+
+        this.initialized = true;
+
+        pgBrowser.add_menus([{
+          name: 'create_check_constraints_on_coll', node: 'coll-constraints', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 5, label: '{{ _('Check...') }}',
+          icon: 'wcTabIcon icon-check_constraints', data: {action: 'create', check: true},
+          enable: 'canCreate'
+        },{
+          name: 'validate_check_constraint', node: 'check_constraints', module: this,
+          applies: ['object', 'context'], callback: 'validate_check_constraint',
+          category: 'validate', priority: 4, label: '{{ _('Validate check constraint') }}',
+          icon: 'fa fa-link', enable : 'is_not_valid', data: {action: 'edit', check: true}
+        }
+        ]);
+
+      },
+      is_not_valid: function(itemData, item, data) {
+        if (this.canCreate(itemData, item, data)) {
+          return (itemData && !itemData.valid);
+        } else {
+          return false;
+        }
+      },
+      callbacks: {
+        validate_check_constraint: function(args) {
+          var input = args || {};
+          obj = this,
+          t = pgBrowser.tree,
+          i = input.item || t.selected(),
+          d = i && i.length == 1 ? t.itemData(i) : undefined;
+
+          if (!d) {
+            return false;
+          }
+          var data = d;
+          $.ajax({
+            url: obj.generate_url(i, 'validate', d, true),
+            type:'GET',
+            success: function(res) {
+              if (res.success == 1) {
+                Alertify.success("{{ _('" + res.info + "') }}");
+                t.removeIcon(i);
+                data.valid = true;
+                data.icon = 'icon-check_constraints';
+                t.addIcon(i, {icon: data.icon});
+                setTimeout(function() {t.deselect(i);}, 10);
+                setTimeout(function() {t.select(i);}, 100);
+              }
+            },
+            error: function(xhr, status, error) {
+              try {
+                var err = $.parseJSON(xhr.responseText);
+                if (err.success == 0) {
+                  msg = S('{{ _(' + err.errormsg + ')}}').value();
+                  Alertify.error("{{ _('" + err.errormsg + "') }}");
+                }
+              } catch (e) {}
+              t.unload(i);
+            }
+            });
+
+          return false;
+        }
+      },
+      canDrop: pgBrowser.Nodes['schema'].canChildDrop,
+      model: pgAdmin.Browser.Node.Model.extend({
+        defaults: {
+          name: undefined,
+          oid: undefined,
+          description: undefined,
+          consrc: undefined,
+          connoinherit: undefined,
+          convalidated: true
+        },
+        // Check Constraint Schema
+        schema: [{
+          id: 'name', label: '{{ _('Name') }}', type:'text', cell:'string',
+          disabled: 'isDisabled'
+        },{
+          id: 'oid', label:'{{ _('OID') }}', cell: 'string',
+          type: 'text' , mode: ['properties']
+        },{
+          id: 'comment', label: '{{ _('Comment') }}', type: 'multiline', cell:
+          'string', mode: ['properties', 'create', 'edit'],
+          deps:['name'], disabled:function(m) {
+            var name = m.get('name');
+            if (!(name && name != '')) {
+              setTimeout(function(){
+                m.set('comment', null);
+              },10);
+              return true;
+            } else {
+              return false;
+            }
+          }
+        },{
+          id: 'consrc', label: '{{ _('Check') }}', type: 'multiline', cell:
+          'string', group: '{{ _('Definition') }}', mode: ['properties',
+          'create', 'edit'], disabled: function(m) {
+            return ((_.has(m, 'handler') &&
+              !_.isUndefined(m.handler) &&
+              !_.isUndefined(m.get('oid'))) || (_.isFunction(m.isNew) && !m.isNew()));
+          }, editable: false
+        },{
+          id: 'connoinherit', label: '{{ _('No Inherit') }}', type:
+          'switch', cell: 'boolean', group: '{{ _('Definition') }}', mode:
+          ['properties', 'create', 'edit'], min_version: 90200,
+          disabled: function(m) {
+            return ((_.has(m, 'handler') &&
+              !_.isUndefined(m.handler) &&
+              !_.isUndefined(m.get('oid'))) || (_.isFunction(m.isNew) && !m.isNew()));
+          }
+        },{
+          id: 'convalidated', label: "{{ _("Don't validate") }}", type: 'switch', cell:
+          'boolean', group: '{{ _('Definition') }}', min_version: 90200,
+          disabled: function(m) {
+            if ((_.isFunction(m.isNew) && !m.isNew()) ||
+                  (_.has(m, 'handler') &&
+                  !_.isUndefined(m.handler) &&
+                  !_.isUndefined(m.get('oid')))) {
+
+              return !m.get("convalidated");
+            } else {
+              return false;
+            }
+          },
+          mode: ['properties', 'create', 'edit']
+        }],
+        // Client Side Validation
+        validate: function() {
+          var err = {},
+              errmsg;
+
+          if (_.isUndefined(this.get('consrc')) || String(this.get('consrc')).replace(/^\s+|\s+$/g, '') == '') {
+            err['consrc'] = '{{ _('Check can not be empty!') }}';
+            errmsg = errmsg || err['consrc'];
+          }
+
+          this.errorModel.clear().set(err);
+
+          if (_.size(err)) {
+            this.trigger('on-status', {msg: errmsg});
+            return errmsg;
+          }
+
+          return null;
+
+        },
+        isDisabled: function(m){
+          if ((_.has(m, 'handler') &&
+              !_.isUndefined(m.handler) &&
+              !_.isUndefined(m.get('oid'))) ||
+            (_.isFunction(m.isNew) && !m.isNew())) {
+            var server = (this.node_info || m.top.node_info).server;
+            if (server.version < 90200)
+            {
+              return true;
+            }
+          }
+          return false;
+        }
+      }),
+      // Below function will enable right click menu for creating check constraint.
+      canCreate: function(itemData, item, data) {
+          // If check is false then , we will allow create menu
+          if (data && data.check == false)
+            return true;
+
+          var t = pgBrowser.tree, i = item, d = itemData, parents = [];
+          // To iterate over tree to check parent node
+          while (i) {
+            // If it is schema then allow user to c reate table
+            if (_.indexOf(['schema'], d._type) > -1)
+              return true;
+            parents.push(d._type);
+            i = t.hasParent(i) ? t.parent(i) : null;
+            d = i ? t.itemData(i) : null;
+          }
+          // If node is under catalog then do not allow 'create' menu
+          if (_.indexOf(parents, 'catalog') > -1) {
+            return false;
+          } else {
+            return true;
+          }
+      }
+  });
+
+  }
+
+  return pgBrowser.Nodes['check_constraints'];
+});
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/__init__.py
new file mode 100644
index 0000000..cf599e5
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/__init__.py
@@ -0,0 +1,820 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+"""Implements Exclusion constraint Node"""
+
+import json
+from flask import render_template, make_response, request, jsonify
+from flask.ext.babel import gettext as _
+from pgadmin.utils.ajax import make_json_response, \
+    make_response as ajax_response, internal_server_error
+from pgadmin.browser.utils import PGChildNodeView
+from pgadmin.utils.ajax import precondition_required
+from pgadmin.utils.driver import get_driver
+from config import PG_DEFAULT_DRIVER
+import pgadmin.browser.server_groups.servers.databases as database
+from functools import wraps
+from pgadmin.browser.server_groups.servers.databases.schemas.tables.constraints.type \
+    import ConstraintRegistry, ConstraintTypeModule
+
+
+class ExclusionConstraintModule(ConstraintTypeModule):
+    """
+    class ForeignKeyConstraintModule(CollectionNodeModule)
+
+        A module class for Exclusion constraint node derived from ConstraintTypeModule.
+
+    Methods:
+    -------
+    * __init__(*args, **kwargs)
+      - Method is used to initialize the ForeignKeyConstraintModule and it's base module.
+
+    * get_nodes(gid, sid, did)
+      - Method is used to generate the browser collection node.
+
+    * node_inode()
+      - Method is overridden from its base class to make the node as leaf node.
+
+    * script_load()
+      - Load the module script for language, when any of the database node is
+        initialized.
+    """
+
+    NODE_TYPE = 'exclusion_constraint'
+    COLLECTION_LABEL = _("Foreign Keys")
+
+    def __init__(self, *args, **kwargs):
+        """
+        Method is used to initialize the ForeignKeyConstraintModule and it's base module.
+
+        Args:
+          *args:
+          **kwargs:
+
+        Returns:
+
+        """
+        self.min_ver = None
+        self.max_ver = None
+        super(ExclusionConstraintModule, self).__init__(*args, **kwargs)
+
+    def get_nodes(self, gid, sid, did, scid, tid):
+        """
+        Generate the collection node
+        """
+        pass
+
+    @property
+    def node_inode(self):
+        """
+        Override this property to make the node a leaf node.
+
+        Returns: False as this is the leaf node
+        """
+        return False
+
+    @property
+    def script_load(self):
+        """
+        Load the module script for exclusion_constraint, when any of the table node is
+        initialized.
+
+        Returns: node type of the server module.
+        """
+        return database.DatabaseModule.NODE_TYPE
+
+blueprint = ExclusionConstraintModule(__name__)
+
+
+class ExclusionConstraintView(PGChildNodeView):
+    """
+    class ExclusionConstraintView(PGChildNodeView)
+
+        A view class for Exclusion constraint node derived from PGChildNodeView. This class is
+        responsible for all the stuff related to view like creating, updating Exclusion constraint
+        node, showing properties, showing sql in sql pane.
+
+    Methods:
+    -------
+    * __init__(**kwargs)
+      - Method is used to initialize the ForeignKeyConstraintView and it's base view.
+
+    * module_js()
+      - This property defines (if javascript) exists for this node.
+        Override this property for your own logic
+
+    * check_precondition()
+      - This function will behave as a decorator which will checks
+        database connection before running view, it will also attaches
+        manager,conn & template_path properties to self
+
+    * end_transaction()
+      - To end any existing database transaction.
+
+    * list()
+      - This function returns Exclusion constraint nodes within that
+        collection as http response.
+
+    * get_list()
+      - This function is used to list all the language nodes within that collection
+        and return list of Exclusion constraint nodes.
+
+    * nodes()
+      - This function returns child node within that collection.
+        Here return all Exclusion constraint node as http response.
+
+    * get_nodes()
+      - returns all Exclusion constraint nodes' list.
+
+    * properties()
+      - This function will show the properties of the selected Exclusion.
+
+    * update()
+      - This function will update the data for the selected Exclusion.
+
+    * msql()
+      - This function is used to return modified SQL for the selected Exclusion.
+
+    * get_sql()
+      - This function will generate sql from model data.
+
+    * sql():
+      - This function will generate sql to show it in sql pane for the selected Exclusion.
+
+    * get_access_methods():
+      - Returns access methods for exclusion constraint.
+
+    * get_oper_class():
+      - Returns operator classes for selected access method.
+
+    * get_operator():
+      - Returns operators for selected column.
+
+    """
+
+    node_type = 'exclusion_constraint'
+
+    parent_ids = [
+            {'type': 'int', 'id': 'gid'},
+            {'type': 'int', 'id': 'sid'},
+            {'type': 'int', 'id': 'did'},
+            {'type': 'int', 'id': 'scid'},
+            {'type': 'int', 'id': 'tid'}
+            ]
+    ids = [{'type': 'int', 'id': 'exid'}
+            ]
+
+    operations = dict({
+        'obj': [
+            {'get': 'properties', 'delete': 'delete', 'put': 'update'},
+            {'get': 'list', 'post': 'create'}
+        ],
+        'delete': [{'delete': 'delete'}],
+        'children': [{'get': 'children'}],
+        'nodes': [{'get': 'node'}, {'get': 'nodes'}],
+        'sql': [{'get': 'sql'}],
+        'msql': [{'get': 'msql'}, {'get': 'msql'}],
+        'stats': [{'get': 'statistics'}],
+        'module.js': [{}, {}, {'get': 'module_js'}]
+    })
+
+    def module_js(self):
+        """
+        This property defines (if javascript) exists for this node.
+        Override this property for your own logic.
+        """
+        return make_response(
+                render_template(
+                    "exclusion_constraint/js/exclusion_constraint.js",
+                    _=_
+                    ),
+                200, {'Content-Type': 'application/x-javascript'}
+                )
+
+    def check_precondition(f):
+        """
+        This function will behave as a decorator which will checks
+        database connection before running view, it will also attaches
+        manager,conn & template_path properties to self
+        """
+        @wraps(f)
+        def wrap(*args, **kwargs):
+            # Here args[0] will hold self & kwargs will hold gid,sid,did
+            self = args[0]
+            self.manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(
+                kwargs['sid']
+                )
+            self.conn = self.manager.connection(did=kwargs['did'])
+
+            # If DB not connected then return error to browser
+            if not self.conn.connected():
+                return precondition_required(
+                    _(
+                            "Connection to the server has been lost!"
+                    )
+                )
+
+            ver = self.manager.version
+
+            if ver >= 90200:
+                self.template_path = 'exclusion_constraint/sql/9.2_plus'
+            elif ver >= 90100:
+                self.template_path = 'exclusion_constraint/sql/9.1_plus'
+
+            # We need parent's name eg table name and schema name
+            SQL = render_template("/".join([self.template_path,
+                                            'get_parent.sql']),
+                                  tid=kwargs['tid'])
+            status, rset = self.conn.execute_2darray(SQL)
+            if not status:
+                return internal_server_error(errormsg=rset)
+
+            for row in rset['rows']:
+                self.schema = row['schema']
+                self.table = row['table']
+            return f(*args, **kwargs)
+
+        return wrap
+
+    def end_transaction(self):
+        SQL = render_template(
+                "/".join([self.template_path, 'end.sql']))
+        # End transaction if any.
+        self.conn.execute_scalar(SQL)
+
+    @check_precondition
+    def properties(self, gid, sid, did, scid, tid, exid=None):
+        """
+        This function is used to list all the Exclusion constraint
+        nodes within that collection.
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          exid: Exclusion constraint ID
+
+        Returns:
+
+        """
+        try:
+            sql = render_template("/".join([self.template_path, 'properties.sql']),
+                                  tid=tid, cid=exid)
+
+            status, res = self.conn.execute_dict(sql)
+
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            result = res['rows'][0]
+
+            sql = render_template(
+                "/".join([self.template_path, 'get_constraint_cols.sql']),
+                cid=exid,
+                colcnt=result['indnatts'])
+            status, res = self.conn.execute_dict(sql)
+
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            columns = []
+            for row in res['rows']:
+                if row['options'] & 1:
+                    order = False
+                    nulls_order = True if (row['options'] & 2) else False
+                else:
+                    order = True
+                    nulls_order = True if (row['options'] & 2) else False
+
+                columns.append({"column": row['coldef'].strip('"'),
+                                "oper_class": row['opcname'],
+                                "order": order,
+                                "nulls_order": nulls_order,
+                                "operator": row['oprname'],
+                                "col_type": row['datatype']
+                                })
+
+            result['columns'] = columns
+
+            return ajax_response(
+                    response=result,
+                    status=200
+                    )
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def list(self, gid, sid, did, scid, tid, exid=None):
+        """
+        This function returns all exclusion constraints
+        nodes within that collection as a http response.
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          exid: Exclusion constraint ID
+
+        Returns:
+
+        """
+        try:
+            res = self.get_node_list(gid, sid, did, scid, tid, exid)
+            return ajax_response(
+                    response=res,
+                    status=200
+                    )
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def get_node_list(self, gid, sid, did, scid, tid, exid=None):
+        """
+        This function returns all exclusion constraints
+        nodes within that collection as a list.
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          exid: Exclusion constraint ID
+
+        Returns:
+
+        """
+        SQL = render_template("/".join([self.template_path,
+                                        'properties.sql']),
+                                        tid=tid)
+        status, res = self.conn.execute_dict(SQL)
+
+        return res['rows']
+
+    @check_precondition
+    def nodes(self, gid, sid, did, scid, tid, exid=None):
+        """
+        This function returns all Exclusion constraint nodes as a
+        http response.
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          exid: Exclusion constraint ID
+
+        Returns:
+
+        """
+        try:
+            res = self.get_nodes(gid, sid, did, scid, tid, exid)
+            return make_json_response(
+                    data=res,
+                    status=200
+                    )
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def get_nodes(self, gid, sid, did, scid, tid, exid=None):
+        """
+        This function returns all Exclusion constraint nodes as a list.
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          exid: Exclusion constraint ID
+
+        Returns:
+
+        """
+        res = []
+        SQL = render_template("/".join([self.template_path,
+                                        'nodes.sql']),
+                              tid=tid)
+        status, rset = self.conn.execute_2darray(SQL)
+
+        for row in rset['rows']:
+            res.append(
+                    self.blueprint.generate_browser_node(
+                        row['oid'],
+                        tid,
+                        row['name'],
+                        icon="icon-exclusion_constraint"
+                    ))
+        return res
+
+    @check_precondition
+    def create(self, gid, sid, did, scid, tid, exid=None):
+        """
+        This function will create a Exclusion constraint.
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          exid: Exclusion constraint ID
+
+        Returns:
+
+        """
+        required_args = ['columns']
+
+        data = request.form if request.form else json.loads(request.data.decode())
+
+        for k, v in data.items():
+            try:
+                data[k] = json.loads(v)
+            except (ValueError, TypeError):
+                data[k] = v
+
+        for arg in required_args:
+            if arg not in data:
+                return make_json_response(
+                      status=400,
+                      success=0,
+                      errormsg=_(
+                          "Couldn't find required parameter (%s)." % str(arg)
+                      )
+                    )
+            elif isinstance(data[arg], list) and len(data[arg]) < 1:
+                return make_json_response(
+                      status=400,
+                      success=0,
+                      errormsg=_(
+                          "Couldn't find required parameter (%s)." % str(arg)
+                      )
+                    )
+
+        data['schema'] = self.schema
+        data['table'] = self.table
+        try:
+            if 'name' not in data or data['name'] == "":
+                SQL = render_template(
+                    "/".join([self.template_path, 'begin.sql']))
+                # Start transaction.
+                status, res = self.conn.execute_scalar(SQL)
+                if not status:
+                    self.end_transaction()
+                    return internal_server_error(errormsg=res)
+
+            # The below SQL will execute CREATE DDL only
+            SQL = render_template(
+                "/".join([self.template_path, 'create.sql']),
+                data=data, conn=self.conn
+                )
+            status, res = self.conn.execute_scalar(SQL)
+            if not status:
+                self.end_transaction()
+                return internal_server_error(errormsg=res)
+
+            if 'name' not in data or data['name'] == "":
+                sql = render_template(
+                    "/".join([self.template_path,
+                              'get_oid_with_transaction.sql']),
+                    tid=tid)
+
+                status, res = self.conn.execute_dict(sql)
+                if not status:
+                    self.end_transaction()
+                    return internal_server_error(errormsg=res)
+
+                self.end_transaction()
+
+                data['name'] = res['rows'][0]['name']
+
+            else:
+                sql = render_template("/".join([self.template_path, 'get_oid.sql']), name=data['name'])
+                status, res = self.conn.execute_dict(sql)
+                if not status:
+                    self.end_transaction()
+                    return internal_server_error(errormsg=res)
+            if 'name' in data and data['name'] != '':
+                sql = render_template("/".join([self.template_path, 'alter.sql']), data=data, conn=self.conn)
+                sql = sql.strip('\n').strip(' ')
+
+                if sql != '':
+                    status, result = self.conn.execute_scalar(sql)
+                    if not status:
+                        self.end_transaction()
+                        return internal_server_error(errormsg=result)
+
+            return jsonify(
+                node=self.blueprint.generate_browser_node(
+                    res['rows'][0]['oid'],
+                    tid,
+                    data['name'],
+                    icon="icon-exclusion_constraint"
+                    )
+                )
+
+        except Exception as e:
+            self.end_transaction()
+
+            return make_json_response(
+                status=400,
+                success=0,
+                errormsg=e
+            )
+
+    @check_precondition
+    def update(self, gid, sid, did, scid, tid, exid=None):
+        """
+        This function will update the data for the selected
+        Exclusion constraint.
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          exid: Exclusion constraint ID
+
+        Returns:
+
+        """
+        data = request.form if request.form else json.loads(request.data.decode())
+
+        try:
+            data['schema'] = self.schema
+            data['table'] = self.table
+            sql = self.get_sql(data, tid, exid)
+            sql = sql.strip('\n').strip(' ')
+            if sql != "":
+                status, res = self.conn.execute_scalar(sql)
+                if not status:
+                    return internal_server_error(errormsg=res)
+
+                sql = render_template("/".join([self.template_path, 'get_oid.sql']), name=data['name'])
+                status, res = self.conn.execute_dict(sql)
+                if not status:
+                    return internal_server_error(errormsg=res)
+
+                return make_json_response(
+                    success=1,
+                    info="Exclusion constraint updated",
+                    data={
+                        'id': res['rows'][0]['oid'],
+                        'tid': tid,
+                        'scid': scid,
+                        'sid': sid,
+                        'gid': gid,
+                        'did': did,
+                    }
+                )
+            else:
+                return make_json_response(
+                    success=1,
+                    info="Nothing to update",
+                    data={
+                        'id': exid,
+                        'tid': tid,
+                        'scid': scid,
+                        'sid': sid,
+                        'gid': gid,
+                        'did': did
+                    }
+                )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def delete(self, gid, sid, did, scid, tid, exid=None):
+        """
+        This function will delete an existing Exclusion.
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          exid: Exclusion constraint ID
+
+        Returns:
+
+        """
+        # Below code will decide if it's simple drop or drop with cascade call
+        if self.cmd == 'delete':
+            # This is a cascade operation
+            cascade = True
+        else:
+            cascade = False
+        try:
+            sql = render_template("/".join([self.template_path, 'get_name.sql']),
+                                  cid=exid)
+            status, res = self.conn.execute_dict(sql)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            data = res['rows'][0]
+            data['schema'] = self.schema
+            data['table'] = self.table
+
+            sql = render_template("/".join([self.template_path, 'delete.sql']),
+                                  data=data,
+                                  cascade=cascade)
+            status, res = self.conn.execute_scalar(sql)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            return make_json_response(
+                success=1,
+                info=_("Exclusion constraint dropped."),
+                data={
+                    'id': exid,
+                    'sid': sid,
+                    'gid': gid,
+                    'did': did
+                }
+            )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def msql(self, gid, sid, did, scid, tid, exid=None):
+        """
+        This function returns modified SQL for the selected
+        Exclusion constraint.
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          exid: Exclusion constraint ID
+
+        Returns:
+
+        """
+        data = {}
+        for k, v in request.args.items():
+            try:
+                data[k] = json.loads(v)
+            except ValueError:
+                data[k] = v
+
+        data['schema'] = self.schema
+        data['table'] = self.table
+        try:
+            sql = self.get_sql(data, tid, exid)
+            sql = sql.strip('\n').strip(' ')
+
+            return make_json_response(
+                    data=sql,
+                    status=200
+                    )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    def get_sql(self, data, tid, exid=None):
+        """
+        This function will generate sql from model data.
+
+        Args:
+          data: Contains the data of the selected Exclusion constraint.
+          tid: Table ID.
+          exid: Exclusion constraint ID
+
+        Returns:
+
+        """
+        if exid is not None:
+            sql = render_template("/".join([self.template_path, 'properties.sql']),
+                                  tid=tid,
+                                  cid=exid)
+            status, res = self.conn.execute_dict(sql)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            old_data = res['rows'][0]
+            required_args = ['name']
+            for arg in required_args:
+                if arg not in data:
+                    data[arg] = old_data[arg]
+
+            sql = render_template("/".join([self.template_path, 'update.sql']),
+                                  data=data, o_data=old_data)
+        else:
+            required_args = ['columns']
+
+            for arg in required_args:
+                if arg not in data:
+                    return _('-- definition incomplete')
+                elif isinstance(data[arg], list) and len(data[arg]) < 1:
+                    return _('-- definition incomplete')
+
+            sql = render_template("/".join([self.template_path, 'create.sql']),
+                                  data=data, conn=self.conn)
+            sql += "\n"
+            sql += render_template("/".join([self.template_path, 'alter.sql']),
+                                   data=data, conn=self.conn)
+
+        return sql
+
+    @check_precondition
+    def sql(self, gid, sid, did, scid, tid, exid=None):
+        """
+        This function generates sql to show in the sql pane for the selected
+        Exclusion constraint.
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          exid: Exclusion constraint ID
+
+        Returns:
+
+        """
+        try:
+            SQL = render_template(
+                "/".join([self.template_path, 'properties.sql']),
+                tid=tid, conn=self.conn, cid=exid)
+            status, result = self.conn.execute_dict(SQL)
+            if not status:
+                return internal_server_error(errormsg=result)
+
+            data = result['rows'][0]
+            data['schema'] = self.schema
+            data['table'] = self.table
+
+            sql = render_template(
+                "/".join([self.template_path, 'get_constraint_cols.sql']),
+                cid=exid,
+                colcnt=data['indnatts'])
+            status, res = self.conn.execute_dict(sql)
+
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            columns = []
+            for row in res['rows']:
+                if row['options'] & 1:
+                    order = False
+                    nulls_order = True if (row['options'] & 2) else False
+                else:
+                    order = True
+                    nulls_order = True if (row['options'] & 2) else False
+
+                columns.append({"column": row['coldef'].strip('"'),
+                                "oper_class": row['opcname'],
+                                "order": order,
+                                "nulls_order": nulls_order,
+                                "operator": row['oprname']
+                                })
+
+            data['columns'] = columns
+
+            if not data['amname'] or data['amname'] == '':
+                data['amname'] = 'btree'
+
+            SQL = render_template(
+                "/".join([self.template_path, 'create.sql']), data=data)
+            SQL += "\n"
+            SQL += render_template(
+                "/".join([self.template_path, 'alter.sql']),
+                data=data, conn=self.conn)
+
+            sql_header = "-- Constraint: {0}\n\n-- ".format(data['name'])
+
+            sql_header += render_template(
+                    "/".join([self.template_path, 'delete.sql']),
+                    data=data)
+            sql_header += "\n"
+
+            SQL = sql_header + SQL
+
+            return ajax_response(response=SQL)
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+constraint = ConstraintRegistry(
+    'exclusion_constraint', ExclusionConstraintModule, ExclusionConstraintView
+    )
+ExclusionConstraintView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/static/img/exclusion_constraint.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/static/img/exclusion_constraint.png
new file mode 100644
index 0000000000000000000000000000000000000000..bd62eef6410d9315857d2e6d246770e8b65b8f47
GIT binary patch
literal 725
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47y|-)LR^8|wi}<ymTvVw_QrY1
zLC3?d^*UDhFWLA1|9`)wM`KREbvXQ5A-=(6%9fR9ZhU_6^4^pwS28lLWMw^=HS5>=
z_isLZP1<@%wQ`Qjk=K%*nNgG09JqAnY+~Zm($d$dsZT2^E~KQ~e)?Lsd6{J1L`ko#
z8QYH^XzhAZSorVPuP+-md|tBT-`~HFYif>6nkJPuNuqp?YIOD56Ib^8`rV6+d^K<0
zzkmPUtXQ!pGFqZ!hGg3swe*g4XK!wIaz5qe_HfFSrwbQu^AC`0S|K@Qk7Uk-*~hPM
zEhsq<82I=1?;BI6UhV1m_vg>S@bIm*jgk|0NG?2Of9R!T^@7Cpr%znEwc5~Vm%sly
zUEQ5NKC5l*c3rqFx8Q{2nrn7@9?A4<w%>5&&c`3`Z{FOOoV;9Hdxfs<!JM4Ox9?6m
zenWfBW$A4XY?hzYUUH^<`Bv54PXhWDq@H_cwegx-ao6F7A05CjWh@Eu3ubV5b|VeM
zN%D4g;b^-zwF=1LEbxdd2GSm2>~=ES4#-&V>Eak7aXC5R07H*Y2Gbdx45l?XZ+LiQ
zWMmY~)Ws(}c=qt=V{riyAu&Nw;pq&V9$ucOPn<e=Qd>hyv$&ZhB;@K9Q<JS*N=v?e
zImpD;=5|bN*|M}_&%~xBFluK@M_UI6S4XqEt8Zx7+`W4C?)K%=xA(7?_c&m$V4z{4
zVq&6Wqh!RTA|NX)Ek1w3j45*_&6>t1bmBw`i*--4qPDWM%7n?><t2V{=CjN{U1V)w
zV3-jtUHUai{xs0(swJ)wB`Jv|saDBFsX&Us$iUE0*8qr2Lkumf3@ojTjkFEStPBi}
hcbK)IXvob^$xN%ntzp~MJ}aOG22WQ%mvv4FO#q89Jv#sZ

literal 0
HcmV?d00001

diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/templates/exclusion_constraint/js/exclusion_constraint.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/templates/exclusion_constraint/js/exclusion_constraint.js
new file mode 100644
index 0000000..6cfa7c3
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/templates/exclusion_constraint/js/exclusion_constraint.js
@@ -0,0 +1,915 @@
+define(
+        ['jquery', 'underscore', 'underscore.string', 'pgadmin',
+        'pgadmin.browser', 'alertify', 'pgadmin.browser.collection'],
+function($, _, S, pgAdmin, pgBrowser, Alertify) {
+
+  var ExclusionConstraintColumnModel = pgBrowser.Node.Model.extend({
+    defaults: {
+      column: undefined,
+      oper_class: undefined,
+      order: undefined,
+      nulls_order: undefined,
+      operator:undefined,
+      col_type:undefined
+    },
+    toJSON: function () {
+      var d = pgBrowser.Node.Model.prototype.toJSON.apply(this, arguments);
+      delete d.col_type;
+      return d;
+    },
+    schema: [{
+        id: 'column', label:'{{ _('Column') }}', type:'text', editable: false,
+        cell:'string'
+      },{
+        id: 'oper_class', label:'{{ _('Operator class') }}', type:'text',
+        node: 'table', url: 'get_oper_class', first_empty: true,
+        editable: function(m) {
+          if (m instanceof Backbone.Collection) {
+            return true;
+          }
+          if ((_.has(m.collection, 'handler') &&
+                !_.isUndefined(m.collection.handler) &&
+                !_.isUndefined(m.collection.handler.get('oid')))) {
+            return false;
+          }
+
+          if (m.collection) {
+            var indexType = m.collection.handler.get('amname')
+            return (indexType == 'btree' || _.isUndefined(indexType) ||
+              _.isNull(indexType) || indexType == '');
+          } else {
+            return true;
+          }
+        },
+        select2: {
+          allowClear: true, width: 'style',
+          placeholder: '{{ _("Select the operator class") }}'
+        }, cell: Backgrid.Extension.Select2Cell.extend({
+          initialize: function () {
+            Backgrid.Extension.Select2Cell.prototype.initialize.apply(this, arguments);
+
+          var self = this,
+            url = self.column.get('url') || self.defaults.url,
+            m = self.model,
+            indextype = self.model.collection.handler.get('amname');
+
+            if (url && (indextype == 'btree' || _.isUndefined(indextype) ||
+                _.isNull(indextype) || indextype == '')) {
+              var node = this.column.get('schema_node'),
+                  eventHandler = m.top || m,
+                  node_info = this.column.get('node_info'),
+                  full_url = node.generate_url.apply(
+                    node, [
+                      null, url, this.column.get('node_data'),
+                      this.column.get('url_with_id') || false, node_info
+                    ]),
+                  data = [];
+
+              indextype = 'btree';
+
+              if (this.column.get('version_compatible')) {
+                eventHandler.trigger('pgadmin:view:fetching', m, self.column);
+                $.ajax({
+                  async: false,
+                  data : {indextype:indextype},
+                  url: full_url,
+                  success: function(res) {
+                    data = res.data;
+                  },
+                  error: function() {
+                    eventHandler.trigger('pgadmin:view:fetch:error', m, self.column);
+                  }
+                });
+                eventHandler.trigger('pgadmin:view:fetched', m, self.column);
+              }
+              /*
+               * Transform the data
+               */
+              transform = self.column.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.column.set('options', transform.bind(self, data));
+              } else {
+                self.column.set('options', data);
+              }
+            } else {
+              self.column.set('options', []);
+            }
+          }
+        })
+      },{
+        id: 'order', label:'{{ _('DESC') }}', type: 'switch',
+        options: {
+          onText: 'ASC',
+          offText: 'DESC',
+        },editable: function(m) {
+          if (m instanceof Backbone.Collection) {
+            return true;
+          }
+          if ((_.has(m.collection, 'handler') &&
+                !_.isUndefined(m.collection.handler) &&
+                !_.isUndefined(m.collection.handler.get('oid')))) {
+            return false;
+          }
+          return true;
+        }
+      },{
+        id: 'nulls_order', label:'{{ _('NULLs order') }}', type:"switch",
+        options: {
+          onText: 'FIRST',
+          offText: 'LAST',
+        },editable: function(m) {
+          if (m instanceof Backbone.Collection) {
+            return true;
+          }
+          if ((_.has(m.collection, 'handler') &&
+                !_.isUndefined(m.collection.handler) &&
+                !_.isUndefined(m.collection.handler.get('oid')))) {
+            return false;
+          }
+          return true;
+        }
+      },{
+        id: 'operator', label:'{{ _('Operator') }}', type: 'text',
+        node: 'table', url: 'get_operator',
+        editable: function(m) {
+          if (m instanceof Backbone.Collection) {
+            return true;
+          }
+          if ((_.has(m.collection, 'handler') &&
+                !_.isUndefined(m.collection.handler) &&
+                !_.isUndefined(m.collection.handler.get('oid')))) {
+            return false;
+          }
+          return true;
+        },
+        select2: {
+          allowClear: false, width: 'style',
+        }, cell: Backgrid.Extension.Select2Cell.extend({
+        initialize: function () {
+          Backgrid.Extension.Select2Cell.prototype.initialize.apply(this, arguments);
+
+          var self = this,
+            url = self.column.get('url') || self.defaults.url,
+            m = self.model,
+            col_type = self.model.get('col_type');
+
+            self.column.set('options', []);
+
+            if (url && !_.isUndefined(col_type) && !_.isNull(col_type) && col_type != '') {
+              var node = this.column.get('schema_node'),
+                  eventHandler = m.top || m,
+                  node_info = this.column.get('node_info'),
+                  full_url = node.generate_url.apply(
+                    node, [
+                      null, url, this.column.get('node_data'),
+                      this.column.get('url_with_id') || false, node_info
+                    ]),
+                  data = [];
+
+              if (this.column.get('version_compatible')) {
+                eventHandler.trigger('pgadmin:view:fetching', m, self.column);
+                $.ajax({
+                  async: false,
+                  data : {col_type:col_type},
+                  url: full_url,
+                  success: function(res) {
+                    data = res.data;
+                  },
+                  error: function() {
+                    eventHandler.trigger('pgadmin:view:fetch:error', m, self.column);
+                  }
+                });
+                eventHandler.trigger('pgadmin:view:fetched', m, self.column);
+              }
+              /*
+               * Transform the data
+               */
+              transform = self.column.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.column.set('options', transform.bind(self, data));
+              } else {
+                self.column.set('options', data);
+              }
+            }
+          }
+        })
+      }
+    ]
+  });
+
+  var ExclusionConstraintColumnControl =  Backform.ExclusionConstraintColumnControl =
+    Backform.UniqueColCollectionControl.extend({
+
+    initialize: function(opts) {
+      Backform.UniqueColCollectionControl.prototype.initialize.apply(
+        this, arguments
+          );
+
+      var self = this,
+        node = 'exclusion_constraint',
+        headerSchema = [{
+          id: 'column', label:'', type:'text',
+          node: 'column', control: Backform.NodeListByNameControl.extend({
+            initialize: function() {
+              // Here we will decide if we need to call URL
+              // Or fetch the data from parent columns collection
+                if(self.model.handler) {
+                  Backform.Select2Control.prototype.initialize.apply(this, arguments);
+                  // Do not listen for any event(s) for existing constraint.
+                  if (_.isUndefined(self.model.get('oid'))) {
+                    var tableCols = self.model.top.get('columns');
+                    this.listenTo(tableCols, 'remove' , this.removeColumn);
+                    this.listenTo(tableCols, 'change:name', this.resetColOptions);
+                    this.listenTo(tableCols, 'change:cltype', this.resetColOptions);
+                  }
+                  this.custom_options();
+                } else {
+                  Backform.NodeListByNameControl.prototype.initialize.apply(this, arguments);
+                }
+            },
+            removeColumn: function (m) {
+              var that = this;
+              setTimeout(function   () {
+                that.custom_options();
+                that.render.apply(that);
+              }, 50);
+            },
+            resetColOptions: function(m) {
+              var that = this;
+
+              if (m.previous('name') ==  self.headerData.get('column')) {
+                /*
+                 * Table column name has changed so update
+                 * column name in exclude constraint as well.
+                 */
+                self.headerData.set(
+                  {"column": m.get('name')});
+                  self.headerDataChanged();
+              }
+
+              setTimeout(function () {
+                that.custom_options();
+                that.render.apply(that);
+              }, 50);
+            },
+            custom_options: function() {
+              // We will add all the columns entered by user in table model
+              var columns = self.model.top.get('columns'),
+                  added_columns_from_tables = [],
+                  col_types = [];
+
+              if (columns.length > 0) {
+                _.each(columns.models, function(m) {
+                  var col = m.get('name');
+                  if(!_.isUndefined(col) && !_.isNull(col)) {
+                    added_columns_from_tables.push({
+                      label: col, value: col, image:'icon-column'
+                      });
+                    col_types.push({name:col, type:m.get('cltype')});
+                  }
+                });
+              }
+              // Set the values in to options so that user can select
+              this.field.set('options', added_columns_from_tables);
+              self.field.set('col_types', col_types);
+            },
+            remove: function () {
+              if(self.model.handler) {
+                  tableCols = self.model.top.get('columns');
+                  this.stopListening(tableCols, 'remove' , this.removeColumn);
+                  this.stopListening(tableCols, 'change:name' , this.resetColOptions);
+                  this.stopListening(tableCols, 'change:cltype' , this.resetColOptions);
+
+                Backform.Select2Control.prototype.remove.apply(this, arguments);
+
+              } else {
+                Backform.NodeListByNameControl.prototype.remove.apply(this, arguments);
+              }
+            },
+            template: _.template([
+              '<div class="<%=Backform.controlsClassName%> <%=extraClasses.join(\' \')%>">',
+              '  <select class="pgadmin-node-select form-control" name="<%=name%>" style="width:100%;" value="<%-value%>" <%=disabled ? "disabled" : ""%> <%=required ? "required" : ""%> >',
+              '    <% if (first_empty) { %>',
+              '    <option value="" <%="" === rawValue ? "selected" : "" %>><%- empty_value %></option>',
+              '    <% } %>',
+              '    <% for (var i=0; i < options.length; i++) { %>',
+              '    <% var option = options[i]; %>',
+              '    <option <% if (option.image) { %> data-image=<%= option.image %> <% } %> value=<%= formatter.fromRaw(option.value) %> <%=option.value === rawValue ? "selected=\'selected\'" : "" %>><%-option.label%></option>',
+              '    <% } %>',
+              '  </select>',
+              '</div>'].join("\n"))
+          }),
+          transform: function(rows) {
+            // This will only get called in case of NodeListByNameControl.
+
+            var that = this,
+                node = that.field.get('schema_node'),
+                res = [],
+                col_types = [],
+                filter = that.field.get('filter') || function() { return true; };
+
+            filter = filter.bind(that);
+
+            _.each(rows, function(r) {
+              if (filter(r)) {
+                var l = (_.isFunction(node['node_label']) ?
+                      (node['node_label']).apply(node, [r, that.model, that]) :
+                      r.label),
+                    image = (_.isFunction(node['node_image']) ?
+                      (node['node_image']).apply(
+                        node, [r, that.model, that]
+                        ) :
+                      (node['node_image'] || ('icon-' + node.type)));
+                res.push({
+                  'value': r.label,
+                  'image': image,
+                  'label': l
+                });
+                col_types.push({name:r.label, type:r.datatype});
+              }
+            });
+            self.field.set('col_types', col_types);
+            return res;
+          },
+          canAdd: function(m) {
+            return !((_.has(m, 'handler') &&
+              !_.isUndefined(m.handler) &&
+              !_.isUndefined(m.get('oid'))) || (_.isFunction(m.isNew) && !m.isNew()));
+          },
+          select2: {
+            allowClear: false, width: 'style',
+            placeholder: 'Select column'
+          }, first_empty: !self.model.isNew(),
+          disabled: function(m) {
+            return !_.isUndefined(self.model.get('oid'));
+          }
+        }],
+        headerDefaults = {column: null},
+
+        gridCols = ['column', 'oper_class', 'order', 'nulls_order', 'operator'];
+
+      self.headerData = new (Backbone.Model.extend({
+        defaults: headerDefaults,
+        schema: headerSchema
+      }))({});
+
+      var headerGroups = Backform.generateViewSchema(
+          self.field.get('node_info'), self.headerData, 'create',
+          node, self.field.get('node_data')
+          ),
+          fields = [];
+
+      _.each(headerGroups, function(o) {
+        fields = fields.concat(o.fields);
+      });
+
+      self.headerFields = new Backform.Fields(fields);
+      self.gridSchema = Backform.generateGridColumnsFromModel(
+          self.field.get('node_info'), self.field.get('model'), 'edit', gridCols, self.field.get('schema_node')
+          );
+
+      self.controls = [];
+      self.listenTo(self.headerData, "change", self.headerDataChanged);
+      self.listenTo(self.headerData, "select2", self.headerDataChanged);
+      self.listenTo(self.collection, "add", self.onAddorRemoveColumns);
+      self.listenTo(self.collection, "remove", self.onAddorRemoveColumns);
+    },
+
+    generateHeader: function(data) {
+      var header = [
+        '<div class="subnode-header-form">',
+        ' <div class="container-fluid">',
+        '  <div class="row">',
+        '   <div class="col-xs-4">',
+        '    <label class="control-label"><%-column_label%></label>',
+        '   </div>',
+        '   <div class="col-xs-4" header="column"></div>',
+        '   <div class="col-xs-4">',
+        '     <button class="btn-sm btn-default add" <%=canAdd ? "" : "disabled=\'disabled\'"%> ><%-add_label%></buttton>',
+        '   </div>',
+        '  </div>',
+        ' </div>',
+        '</div>',].join("\n")
+
+      _.extend(data, {
+        column_label: '{{ _('Column')}}',
+        add_label: '{{ _('ADD')}}'
+      });
+
+      var self = this,
+          headerTmpl = _.template(header),
+          $header = $(headerTmpl(data)),
+          controls = this.controls;
+
+      this.headerFields.each(function(field) {
+        var control = new (field.get("control"))({
+          field: field,
+          model: self.headerData
+        });
+
+        $header.find('div[header="' + field.get('name') + '"]').append(
+          control.render().$el
+        );
+
+        controls.push(control);
+      });
+
+      // We should not show add but in properties mode
+      if (data.mode == 'properties') {
+        $header.find("button.add").remove();
+      }
+
+      self.$header = $header;
+
+      return $header;
+    },
+
+    events: _.extend(
+                  {}, Backform.UniqueColCollectionControl.prototype.events,
+                {'click button.add': 'addColumns'}
+                ),
+
+    showGridControl: function(data) {
+
+      var self = this,
+          titleTmpl = _.template("<div class='subnode-header'></div>"),
+          $gridBody =
+            $("<div class='pgadmin-control-group backgrid form-group col-xs-12 object subnode'></div>").append(
+              titleTmpl({label: data.label})
+            );
+
+      $gridBody.append(self.generateHeader(data));
+
+      var gridColumns = _.clone(this.gridSchema.columns);
+
+      // Insert Delete Cell into Grid
+      if (data.disabled == false && data.canDelete) {
+          gridColumns.unshift({
+            name: "pg-backform-delete", label: "",
+            cell: Backgrid.Extension.DeleteCell,
+            editable: false, cell_priority: -1
+          });
+      }
+
+      if (self.grid) {
+        self.grid.remove();
+        self.grid.null;
+      }
+      // Initialize a new Grid instance
+      var grid = self.grid = new Backgrid.Grid({
+        columns: gridColumns,
+        collection: self.collection,
+        className: "backgrid table-bordered"
+      });
+      self.$grid = grid.render().$el;
+
+      $gridBody.append(self.$grid);
+
+      setTimeout(function() {
+        self.headerData.set({
+          'column': self.$header.find(
+            'div[header="column"] select'
+            ).val()
+            }, {silent:true}
+          );
+      }, 10);
+
+      // Render node grid
+      return $gridBody;
+    },
+
+    headerDataChanged: function() {
+      var self = this, val,
+          data = this.headerData.toJSON(),
+          inSelected = false,
+          checkVars = ['column'];
+
+      if (!self.$header) {
+        return;
+      }
+
+      if (self.control_data.canAdd) {
+        self.collection.each(function(m) {
+          if (!inSelected) {
+            _.each(checkVars, function(v) {
+              if (!inSelected) {
+                val = m.get(v);
+                inSelected = ((
+                  (_.isUndefined(val) || _.isNull(val)) &&
+                  (_.isUndefined(data[v]) || _.isNull(data[v]))
+                  ) ||
+                  (val == data[v]));
+              }
+            });
+          }
+        });
+      }
+      else {
+        inSelected = true;
+      }
+
+      self.$header.find('button.add').prop('disabled', inSelected);
+    },
+
+    addColumns: function(ev) {
+      ev.preventDefault();
+      var self = this,
+          column = self.headerData.get('column');
+
+      if (!column || column == '') {
+        return false;
+      }
+
+      var coll = self.model.get(self.field.get('name')),
+          m = new (self.field.get('model'))(
+                self.headerData.toJSON(), {
+                  silent: true, top: self.model.top,
+                  collection: coll, handler: coll
+                }),
+          col_types =self.field.get('col_types') || [];
+
+      for(var i=0; i < col_types.length; i++) {
+        var col_type = col_types[i];
+        if (col_type['name'] ==  m.get('column')) {
+            m.set({'col_type':col_type['type']});
+          break;
+        }
+      }
+
+      coll.add(m);
+
+      var idx = coll.indexOf(m);
+
+      // idx may not be always > -1 because our UniqueColCollection may
+      // remove 'm' if duplicate value found.
+      if (idx > -1) {
+        self.$grid.find('.new').removeClass('new');
+
+        var newRow = self.grid.body.rows[idx].$el;
+
+        newRow.addClass("new");
+        $(newRow).pgMakeVisible('backform-tab');
+      } else {
+        delete m;
+      }
+
+      return false;
+    },
+
+    onAddorRemoveColumns: function() {
+      var self = this;
+
+      // Wait for collection to be updated before checking for the button to be
+      // enabled, or not.
+      setTimeout(function() {
+          self.collection.trigger('pgadmin:columns:updated', self.collection);
+        self.headerDataChanged();
+      }, 10);
+    },
+
+    remove: function() {
+      /*
+       * Stop listening the events registered by this control.
+       */
+      this.stopListening(this.headerData, "change", this.headerDataChanged);
+      this.listenTo(this.headerData, "select2", this.headerDataChanged);
+      this.listenTo(this.collection, "remove", this.onAddorRemoveColumns);
+
+      // Remove header controls.
+      _.each(this.controls, function(controls) {
+        controls.remove();
+      });
+
+      ExclusionConstraintColumnControl.__super__.remove.apply(this, arguments);
+
+      // Remove the header model
+      delete (this.headerData);
+
+    }
+  });
+
+  // Extend the browser's node class for exclusion constraint node
+  if (!pgBrowser.Nodes['exclusion_constraint']) {
+    pgAdmin.Browser.Nodes['exclusion_constraint'] = pgBrowser.Node.extend({
+      type: 'exclusion_constraint',
+      label: '{{ _('Exclusion constraint') }}',
+      collection_type: 'coll-constraints',
+      sqlAlterHelp: 'ddl-alter.html',
+      sqlCreateHelp: 'ddl-constraints.html',
+      hasSQL: true,
+      parent_type: 'table',
+      canDrop: true,
+      canDropCascade: true,
+      hasDepends: true,
+      Init: function() {
+        /* Avoid multiple registration of menus */
+        if (this.initialized)
+            return;
+
+        this.initialized = true;
+
+        pgBrowser.add_menus([{
+          name: 'create_exclusion_constraint_on_coll', node: 'coll-constraints', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('Exclusion constraint...') }}',
+          icon: 'wcTabIcon icon-exclusion_constraint', data: {action: 'create', check: true},
+          enable: 'canCreate'
+        }]);
+      },
+      is_not_valid: function(node) {
+        return (node && !node.valid);
+      },
+      // Define the model for exclusion constraint node
+      model: pgAdmin.Browser.Node.Model.extend({
+        defaults: {
+          name: undefined,
+          oid: undefined,
+          comment: undefined,
+          spcname: "pg_default",
+          amname: "gist",
+          fillfactor: undefined,
+          condeferrable: undefined,
+          condeferred: undefined,
+          columns: []
+        },
+
+        // Define the schema for the exclusion constraint node
+        schema: [{
+          id: 'name', label: '{{ _('Name') }}', type: 'text',
+          mode: ['properties', 'create', 'edit'], editable: true,
+        },{
+          id: 'oid', label:'{{ _('OID') }}', cell: 'string',
+          type: 'text' , mode: ['properties']
+        },{
+          id: 'comment', label:'{{ _('Comment') }}', cell: 'string',
+          type: 'multiline', mode: ['properties', 'create', 'edit'],
+          deps:['name'], disabled:function(m) {
+            var name = m.get('name');
+            if (!(name && name != '')) {
+              setTimeout(function(){
+                m.set('comment', null);
+              },10);
+              return true;
+            } else {
+              return false;
+            }
+          }
+        },{
+          id: 'spcname', label: '{{ _('Tablespace') }}',
+          type: 'text', group: '{{ _('Definition') }}',
+          control: 'node-list-by-name', node: 'tablespace',
+          select2:{allowClear:false},
+          filter: function(m) {
+            // Don't show pg_global tablespace in selection.
+            if (m.label == "pg_global") return false;
+            else return true;
+          }
+        },{
+          id: 'amname', label: '{{ _('Access method') }}',
+          type: 'text', group: '{{ _('Definition') }}',
+          url:"get_access_methods", node: 'table',
+          control: Backform.NodeAjaxOptionsControl.extend({
+            // When access method changes we need to clear columns collection
+            onChange: function() {
+              Backform.NodeAjaxOptionsControl.prototype.onChange.apply(this, arguments);
+              var self = this,
+              // current access method
+              current_am = self.model.get('amname'),
+              // previous access method
+              previous_am = self.model.previous('amname'),
+              column_collection = self.model.get('columns');
+
+              if (column_collection.length > 0 && current_am != previous_am) {
+                var msg = '{{ _('Changing access method will clear columns collection') }}';
+                Alertify.confirm(msg, function (e) {
+                    // User clicks Ok, lets clear collection
+                    column_collection.reset();
+                    setTimeout(function() {
+                      column_collection.trigger('pgadmin:columns:updated', column_collection);
+                    }, 10);
+
+                  }, function() {
+                    // User clicks Cancel set previous value again in combo box
+                    setTimeout(function(){
+                      self.model.set('amname', previous_am);
+                    }, 10);
+                });
+              }
+            }
+          }),
+          select2:{allowClear:true},
+          disabled: function(m) {
+            return ((_.has(m, 'handler') &&
+              !_.isUndefined(m.handler) &&
+              !_.isUndefined(m.get('oid'))) || (_.isFunction(m.isNew) && !m.isNew()));
+          }
+        },{
+          id: 'fillfactor', label: '{{ _('Fill factor') }}',
+          type: 'int', group: '{{ _('Definition') }}', allowNull: true
+        },{
+          id: 'condeferrable', label: '{{ _('Deferrable') }}',
+          type: 'switch', group: '{{ _('Definition') }}', deps: ['index'],
+          disabled: function(m) {
+            return ((_.has(m, 'handler') &&
+              !_.isUndefined(m.handler) &&
+              !_.isUndefined(m.get('oid'))) || (_.isFunction(m.isNew) && !m.isNew()));
+          }
+        },{
+          id: 'condeferred', label: '{{ _('Deferred') }}',
+          type: 'switch', group: '{{ _('Definition') }}',
+          deps: ['condeferrable'],
+          disabled: function(m) {
+            if((_.has(m, 'handler') &&
+              !_.isUndefined(m.handler) &&
+              !_.isUndefined(m.get('oid'))) || (_.isFunction(m.isNew) && !m.isNew())) {
+              return true;
+            }
+
+            // Disable if condeferred is false or unselected.
+            if(m.get('condeferrable') == true) {
+              return false;
+            } else {
+              setTimeout(function(){
+                m.set('condeferred', false);
+              },10);
+              return true;
+            }
+          }
+        },{
+          id: 'constraint', label:'{{ _('Constraint') }}', cell: 'string',
+          type: 'multiline', mode: ['create', 'edit'], editable: false,
+          group: '{{ _('Definition') }}', disabled: function(m) {
+            return ((_.has(m, 'handler') &&
+              !_.isUndefined(m.handler) &&
+              !_.isUndefined(m.get('oid'))) || (_.isFunction(m.isNew) && !m.isNew()));
+          }
+        },{
+          id: 'columns', label: '{{ _('Columns') }}',
+          type: 'collection', group: '{{ _('Columns') }}', disabled: false,
+          deps:['amname'], canDelete: true, editable: false,
+          canAdd: function(m) {
+            // We can't update columns of existing exclusion constraint.
+            return !((_.has(m, 'handler') &&
+              !_.isUndefined(m.handler) &&
+              !_.isUndefined(m.get('oid'))) || (_.isFunction(m.isNew) && !m.isNew()));
+          },
+          control: ExclusionConstraintColumnControl,
+          model: ExclusionConstraintColumnModel,
+          disabled: function(m) {
+            return ((_.has(m, 'handler') &&
+              !_.isUndefined(m.handler) &&
+              !_.isUndefined(m.get('oid'))) || (_.isFunction(m.isNew) && !m.isNew()));
+          },
+          cell: Backgrid.StringCell.extend({
+            initialize: function() {
+              Backgrid.StringCell.prototype.initialize.apply(this, arguments);
+              var self = this;
+              // Do not listen for any event(s) for existing constraint.
+              if (_.isUndefined(self.model.get('oid'))) {
+                var tableCols = self.model.top.get('columns');
+
+                self.listenTo(tableCols, 'remove' , self.removeColumn);
+                self.listenTo(tableCols, 'change:name', self.resetColOptions);
+                self.listenTo(tableCols, 'change:cltype', self.removeColumnWithType);
+              }
+
+              this.model.get('columns').on('pgadmin:columns:updated', function() {
+                self.render.apply(self);
+              });
+            },
+            removeColumnWithType: function(m){
+              var self = this,
+                  cols = self.model.get('columns'),
+                  removedCols = cols.where(
+                    {col_type: m.previous('cltype')}
+                    );
+
+              cols.remove(removedCols);
+              setTimeout(function () {
+                self.render();
+              }, 10);
+
+              setTimeout(function () {
+                constraints = self.model.top.get("exclude_constraint");
+                var removed = [];
+                constraints.each(function(constraint) {
+                  if (constraint.get("columns").length == 0) {
+                     removed.push(constraint);
+                  }
+                });
+                constraints.remove(removed);
+              },100);
+            },
+            removeColumn: function(m){
+              var self = this,
+                  removedCols = self.model.get('columns').where(
+                    {column: m.get('name')}
+                    );
+
+              self.model.get('columns').remove(removedCols);
+              setTimeout(function () {
+                self.render();
+              }, 10);
+
+              setTimeout(function () {
+                constraints = self.model.top.get("exclude_constraint");
+                var removed = [];
+                constraints.each(function(constraint) {
+                  if (constraint.get("columns").length == 0) {
+                     removed.push(constraint);
+                  }
+                });
+                constraints.remove(removed);
+              },100);
+            },
+            resetColOptions : function(m) {
+                var self = this,
+                  updatedCols = self.model.get('columns').where(
+                  {"column": m.previous('name')}
+                  );
+
+                if (updatedCols.length > 0) {
+                  /*
+                   * Table column name has changed so update
+                   * column name in foreign key as well.
+                   */
+                  updatedCols[0].set(
+                  {"column": m.get('name')});
+                }
+
+                setTimeout(function () {
+                  self.render();
+                }, 10);
+            },
+            formatter: {
+              fromRaw: function (rawValue, model) {
+                return rawValue.pluck("column").toString();
+              },
+              toRaw: function (val, model) {
+                return val;
+              }
+            },
+            render: function() {
+              return Backgrid.StringCell.prototype.render.apply(this, arguments);
+            },
+            remove: function() {
+              var tableCols = this.model.top.get('columns'),
+                  cols = this.model.get('columns');
+              if (cols) {
+                cols.off('pgadmin:columns:updated');
+              }
+
+              this.stopListening(tableCols, 'remove' , self.removeColumn);
+              this.stopListening(tableCols, 'change:name' , self.resetColOptions);
+              this.stopListening(tableCols, 'change:cltype' , self.removeColumnWithType);
+
+              Backgrid.StringCell.prototype.remove.apply(this, arguments);
+            }
+          }),
+        }],
+        validate: function() {
+          this.errorModel.clear();
+          var columns = this.get('columns');
+          if ((_.isUndefined(columns) || _.isNull(columns) || columns.length < 1)) {
+            var msg = '{{ _('Please specify columns for Exclude constraint.') }}';
+            this.errorModel.set('columns', msg);
+            return msg;
+          }
+
+          return null;
+        }
+      }),
+
+      canCreate: function(itemData, item, data) {
+          // If check is false then , we will allow create menu
+          if (data && data.check == false)
+            return true;
+
+          var t = pgBrowser.tree, i = item, d = itemData, parents = [];
+          // To iterate over tree to check parent node
+          while (i) {
+            // If it is schema then allow user to create table
+            if (_.indexOf(['schema'], d._type) > -1)
+              return true;
+            parents.push(d._type);
+            i = t.hasParent(i) ? t.parent(i) : null;
+            d = i ? t.itemData(i) : null;
+          }
+          // If node is under catalog then do not allow 'create' menu
+          if (_.indexOf(parents, 'catalog') > -1) {
+            return false;
+          } else {
+            return true;
+          }
+      }
+    });
+  }
+
+  return pgBrowser.Nodes['exclusion_constraint'];
+});
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/__init__.py
new file mode 100644
index 0000000..ce05031
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/__init__.py
@@ -0,0 +1,1072 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+"""Implements Foreign key constraint Node"""
+
+import json
+from flask import render_template, make_response, request, jsonify
+from flask.ext.babel import gettext as _
+from pgadmin.utils.ajax import make_json_response, \
+    make_response as ajax_response, internal_server_error
+from pgadmin.browser.utils import PGChildNodeView
+from pgadmin.utils.ajax import precondition_required
+from pgadmin.utils.driver import get_driver
+from config import PG_DEFAULT_DRIVER
+import pgadmin.browser.server_groups.servers.databases as database
+from functools import wraps
+from pgadmin.browser.server_groups.servers.databases.schemas.tables.constraints.type \
+    import ConstraintRegistry, ConstraintTypeModule
+
+
+class ForeignKeyConstraintModule(ConstraintTypeModule):
+    """
+    class ForeignKeyConstraintModule(CollectionNodeModule)
+
+        A module class for Foreign key constraint node derived from ConstraintTypeModule.
+
+    Methods:
+    -------
+    * __init__(*args, **kwargs)
+      - Method is used to initialize the ForeignKeyConstraintModule and it's base module.
+
+    * get_nodes(gid, sid, did)
+      - Method is used to generate the browser collection node.
+
+    * node_inode()
+      - Method is overridden from its base class to make the node as leaf node.
+
+    * script_load()
+      - Load the module script for language, when any of the database node is
+        initialized.
+    """
+
+    NODE_TYPE = 'foreign_key'
+    COLLECTION_LABEL = _("Foreign Keys")
+
+    def __init__(self, *args, **kwargs):
+        """
+        Method is used to initialize the ForeignKeyConstraintModule and it's base module.
+
+        Args:
+          *args:
+          **kwargs:
+
+        Returns:
+
+        """
+        self.min_ver = None
+        self.max_ver = None
+        super(ForeignKeyConstraintModule, self).__init__(*args, **kwargs)
+
+    def get_nodes(self, gid, sid, did, scid, tid):
+        """
+        Generate the collection node
+        """
+        pass
+
+    @property
+    def node_inode(self):
+        """
+        Override this property to make the node a leaf node.
+
+        Returns: False as this is the leaf node
+        """
+        return False
+
+    @property
+    def script_load(self):
+        """
+        Load the module script for foreign_key, when any of the table node is
+        initialized.
+
+        Returns: node type of the server module.
+        """
+        return database.DatabaseModule.NODE_TYPE
+
+    @property
+    def csssnippets(self):
+        """
+        Returns a snippet of css to include in the page
+        """
+        snippets = [
+                render_template(
+                    "browser/css/collection.css",
+                    node_type=self.node_type,
+                    _=_
+                    ),
+                render_template(
+                    "foreign_key/css/foreign_key.css",
+                    node_type=self.node_type,
+                    _=_
+                    )
+                ]
+
+        for submodule in self.submodules:
+            snippets.extend(submodule.csssnippets)
+
+        return snippets
+
+blueprint = ForeignKeyConstraintModule(__name__)
+
+
+class ForeignKeyConstraintView(PGChildNodeView):
+    """
+    class ForeignKeyConstraintView(PGChildNodeView)
+
+        A view class for Foreign key constraint node derived from PGChildNodeView. This class is
+        responsible for all the stuff related to view like creating, updating Foreign key constraint
+        node, showing properties, showing sql in sql pane.
+
+    Methods:
+    -------
+    * __init__(**kwargs)
+      - Method is used to initialize the ForeignKeyConstraintView and it's base view.
+
+    * module_js()
+      - This property defines (if javascript) exists for this node.
+        Override this property for your own logic
+
+    * check_precondition()
+      - This function will behave as a decorator which will checks
+        database connection before running view, it will also attaches
+        manager,conn & template_path properties to self
+
+    * list()
+      - This function returns foreign key constraint nodes within that
+        collection as http response.
+
+    * get_list()
+      - This function is used to list all the language nodes within that collection
+        and return list of foreign key constraint nodes.
+
+    * nodes()
+      - This function returns child node within that collection.
+        Here return all foreign key constraint node as http response.
+
+    * get_nodes()
+      - returns all foreign key constraint nodes' list.
+
+    * properties()
+      - This function will show the properties of the selected foreign key.
+
+    * update()
+      - This function will update the data for the selected foreign key.
+
+    * msql()
+      - This function is used to return modified SQL for the selected foreign key.
+
+    * get_sql()
+      - This function will generate sql from model data.
+
+    * sql():
+      - This function will generate sql to show it in sql pane for the selected foreign key.
+
+    * get_indices():
+        - This function returns indices for current table.
+
+    """
+
+    node_type = 'foreign_key'
+
+    parent_ids = [
+            {'type': 'int', 'id': 'gid'},
+            {'type': 'int', 'id': 'sid'},
+            {'type': 'int', 'id': 'did'},
+            {'type': 'int', 'id': 'scid'},
+            {'type': 'int', 'id': 'tid'}
+            ]
+    ids = [{'type': 'int', 'id': 'fkid'}
+            ]
+
+    operations = dict({
+        'obj': [
+            {'get': 'properties', 'delete': 'delete', 'put': 'update'},
+            {'get': 'list', 'post': 'create'}
+        ],
+        'delete': [{'delete': 'delete'}],
+        'children': [{'get': 'children'}],
+        'nodes': [{'get': 'node'}, {'get': 'nodes'}],
+        'sql': [{'get': 'sql'}],
+        'msql': [{'get': 'msql'}, {'get': 'msql'}],
+        'stats': [{'get': 'statistics'}],
+        'dependency': [{'get': 'dependencies'}],
+        'dependent': [{'get': 'dependents'}],
+        'module.js': [{}, {}, {'get': 'module_js'}],
+        'indices': [{}, {'get': 'get_indices'}],
+        'validate': [{'get': 'validate_foreign_key'}],
+        'get_coveringindex': [{}, {'get': 'get_coveringindex'}]
+    })
+
+    def module_js(self):
+        """
+        This property defines (if javascript) exists for this node.
+        Override this property for your own logic.
+        """
+        return make_response(
+                render_template(
+                    "foreign_key/js/foreign_key.js",
+                    _=_
+                    ),
+                200, {'Content-Type': 'application/x-javascript'}
+                )
+
+    def check_precondition(f):
+        """
+        This function will behave as a decorator which will checks
+        database connection before running view, it will also attaches
+        manager,conn & template_path properties to self
+        """
+        @wraps(f)
+        def wrap(*args, **kwargs):
+            # Here args[0] will hold self & kwargs will hold gid,sid,did
+            self = args[0]
+            self.manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(
+                kwargs['sid']
+                )
+            self.conn = self.manager.connection(did=kwargs['did'])
+
+            # If DB not connected then return error to browser
+            if not self.conn.connected():
+                return precondition_required(
+                    _(
+                            "Connection to the server has been lost!"
+                    )
+                )
+
+            self.template_path = 'foreign_key/sql'
+            # We need parent's name eg table name and schema name
+            SQL = render_template("/".join([self.template_path,
+                                            'get_parent.sql']),
+                                  tid=kwargs['tid'])
+            status, rset = self.conn.execute_2darray(SQL)
+            if not status:
+                return internal_server_error(errormsg=rset)
+
+            for row in rset['rows']:
+                self.schema = row['schema']
+                self.table = row['table']
+            return f(*args, **kwargs)
+
+        return wrap
+
+    def end_transaction(self):
+        SQL = render_template(
+                "/".join([self.template_path, 'end.sql']))
+        # End transaction if any.
+        self.conn.execute_scalar(SQL)
+
+    @check_precondition
+    def properties(self, gid, sid, did, scid, tid, fkid=None):
+        """
+        This function is used to list all the foreign key
+        nodes within that collection.
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          fkid: Foreign key constraint ID
+
+        Returns:
+
+        """
+        try:
+            sql = render_template("/".join([self.template_path, 'properties.sql']),
+                                  tid=tid, cid=fkid)
+
+            status, res = self.conn.execute_dict(sql)
+
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            result = res['rows'][0]
+
+            sql = render_template("/".join([self.template_path,
+                                            'get_constraint_cols.sql']),
+                                  tid=tid,
+                                  keys=zip(result['confkey'], result['conkey']),
+                                  confrelid=result['confrelid'])
+
+            status, res = self.conn.execute_dict(sql)
+
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            columns = []
+            cols = []
+            for row in res['rows']:
+                columns.append({"local_column": row['conattname'],
+                                "references": result['confrelid'],
+                                "referenced": row['confattname']})
+                cols.append(row['conattname'])
+
+            result['columns'] = columns
+
+            if fkid:
+                coveringindex = self.search_coveringindex(tid, cols)
+                result['coveringindex'] = coveringindex
+                if coveringindex:
+                    result['autoindex'] = True
+                    result['hasindex'] = True
+                else:
+                    result['autoindex'] = False
+                    result['hasindex'] = False
+
+            return ajax_response(
+                    response=result,
+                    status=200
+                    )
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def list(self, gid, sid, did, scid, tid, fkid=None):
+        """
+        This function returns all foreign keys
+        nodes within that collection as a http response.
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          fkid: Foreign key constraint ID
+
+        Returns:
+
+        """
+        try:
+            res = self.get_node_list(gid, sid, did, scid, tid, fkid)
+            return ajax_response(
+                    response=res,
+                    status=200
+                    )
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def get_node_list(self, gid, sid, did, scid, tid, fkid=None):
+        """
+        This function returns all foreign keys
+        nodes within that collection as a list.
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          fkid: Foreign key constraint ID
+
+        Returns:
+
+        """
+        SQL = render_template("/".join([self.template_path,
+                                        'properties.sql']),
+                                        tid=tid)
+        status, res = self.conn.execute_dict(SQL)
+
+        return res['rows']
+
+    @check_precondition
+    def nodes(self, gid, sid, did, scid, tid, fkid=None):
+        """
+        This function returns all event trigger nodes as a
+        http response.
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          fkid: Foreign key constraint ID
+
+        Returns:
+
+        """
+        try:
+            res = self.get_nodes(gid, sid, did, scid, tid, fkid)
+            return make_json_response(
+                    data=res,
+                    status=200
+                    )
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def get_nodes(self, gid, sid, did, scid, tid, fkid=None):
+        """
+        This function returns all event trigger nodes as a list.
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          fkid: Foreign key constraint ID
+
+        Returns:
+
+        """
+        res = []
+        SQL = render_template("/".join([self.template_path,
+                                        'nodes.sql']),
+                              tid=tid)
+        status, rset = self.conn.execute_2darray(SQL)
+
+        for row in rset['rows']:
+            if row["convalidated"]:
+                icon = "icon-foreign_key_no_validate"
+                valid = False
+            else:
+                icon = "icon-foreign_key"
+                valid = True
+            res.append(
+                    self.blueprint.generate_browser_node(
+                        row['oid'],
+                        tid,
+                        row['name'],
+                        icon=icon,
+                        valid=valid
+                    ))
+        return res
+
+    @check_precondition
+    def create(self, gid, sid, did, scid, tid, fkid=None):
+        """
+        This function will create a foreign key.
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          fkid: Foreign key constraint ID
+
+        Returns:
+
+        """
+        required_args = ['columns']
+
+        data = request.form if request.form else json.loads(request.data.decode())
+
+        for k, v in data.items():
+            try:
+                data[k] = json.loads(v)
+            except (ValueError, TypeError):
+                data[k] = v
+
+        for arg in required_args:
+            if arg not in data:
+                return make_json_response(
+                      status=400,
+                      success=0,
+                      errormsg=_(
+                          "Couldn't find required parameter (%s)." % str(arg)
+                      )
+                    )
+            elif isinstance(data[arg], list) and len(data[arg]) < 1:
+                return make_json_response(
+                      status=400,
+                      success=0,
+                      errormsg=_(
+                          "Couldn't find required parameter (%s)." % str(arg)
+                      )
+                    )
+
+        data['schema'] = self.schema
+        data['table'] = self.table
+        try:
+            SQL = render_template("/".join([self.template_path,
+                                            'get_parent.sql']),
+                                  tid=data['columns'][0]['references'])
+            status, res = self.conn.execute_2darray(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            data['remote_schema'] = res['rows'][0]['schema']
+            data['remote_table'] = res['rows'][0]['table']
+
+            if 'name' not in data or data['name'] == "":
+                SQL = render_template(
+                    "/".join([self.template_path, 'begin.sql']))
+                # Start transaction.
+                status, res = self.conn.execute_scalar(SQL)
+                if not status:
+                    self.end_transaction()
+                    return internal_server_error(errormsg=res)
+
+            # The below SQL will execute CREATE DDL only
+            SQL = render_template(
+                "/".join([self.template_path, 'create.sql']),
+                data=data, conn=self.conn
+                )
+            status, res = self.conn.execute_scalar(SQL)
+            if not status:
+                self.end_transaction()
+                return internal_server_error(errormsg=res)
+
+            if 'name' not in data or data['name'] == "":
+                sql = render_template(
+                    "/".join([self.template_path,
+                              'get_oid_with_transaction.sql']),
+                    tid=tid)
+
+                status, res = self.conn.execute_dict(sql)
+                if not status:
+                    self.end_transaction()
+                    return internal_server_error(errormsg=res)
+
+                self.end_transaction()
+
+                data['name'] = res['rows'][0]['name']
+
+            else:
+                sql = render_template("/".join([self.template_path, 'get_oid.sql']), name=data['name'])
+                status, res = self.conn.execute_dict(sql)
+                if not status:
+                    self.end_transaction()
+                    return internal_server_error(errormsg=res)
+
+            if res['rows'][0]["convalidated"]:
+                icon = "icon-foreign_key_no_validate"
+                valid = False
+            else:
+                icon = "icon-foreign_key"
+                valid = True
+
+            sql = render_template("/".join([self.template_path, 'alter.sql']), data=data, conn=self.conn)
+            sql = sql.strip('\n').strip(' ')
+
+            if sql != '':
+                status, result = self.conn.execute_scalar(sql)
+                if not status:
+                    self.end_transaction()
+                    return internal_server_error(errormsg=result)
+
+            if data['autoindex']:
+                sql = render_template(
+                    "/".join([self.template_path, 'create_index.sql']),
+                    data=data, conn=self.conn)
+                sql = sql.strip('\n').strip(' ')
+
+                if sql != '':
+                    status, idx_res = self.conn.execute_scalar(sql)
+                    if not status:
+                        self.end_transaction()
+                        return internal_server_error(errormsg=idx_res)
+
+            return jsonify(
+                node=self.blueprint.generate_browser_node(
+                    res['rows'][0]['oid'],
+                    tid,
+                    data['name'],
+                    valid=valid,
+                    icon=icon
+                    )
+                )
+
+        except Exception as e:
+            self.end_transaction()
+            return make_json_response(
+                status=400,
+                success=0,
+                errormsg=e
+            )
+
+    @check_precondition
+    def update(self, gid, sid, did, scid, tid, fkid=None):
+        """
+        This function will update the data for the selected
+        foreign key.
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          fkid: Foreign key constraint ID
+
+        Returns:
+
+        """
+        data = request.form if request.form else json.loads(request.data.decode())
+
+        try:
+            data['schema'] = self.schema
+            data['table'] = self.table
+            sql = self.get_sql(data, tid, fkid)
+            sql = sql.strip('\n').strip(' ')
+            if sql != "":
+                status, res = self.conn.execute_scalar(sql)
+                if not status:
+                    return internal_server_error(errormsg=res)
+
+                sql = render_template("/".join([self.template_path, 'get_oid.sql']),
+                                      tid=tid,
+                                      name=data['name'])
+                status, res = self.conn.execute_dict(sql)
+                if not status:
+                    return internal_server_error(errormsg=res)
+
+                if res['rows'][0]["convalidated"]:
+                    icon = "icon-foreign_key_no_validate"
+                    valid = False
+                else:
+                    icon = "icon-foreign_key"
+                    valid = True
+
+                return make_json_response(
+                    success=1,
+                    info="Foreign key updated",
+                    data={
+                        'id': res['rows'][0]['oid'],
+                        'tid': tid,
+                        'scid': scid,
+                        'sid': sid,
+                        'gid': gid,
+                        'did': did,
+                        'icon':icon,
+                        'valid':valid
+                    }
+                )
+            else:
+                return make_json_response(
+                    success=1,
+                    info="Nothing to update",
+                    data={
+                        'id': fkid,
+                        'tid': tid,
+                        'scid': scid,
+                        'sid': sid,
+                        'gid': gid,
+                        'did': did
+                    }
+                )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def delete(self, gid, sid, did, scid, tid, fkid=None):
+        """
+        This function will delete an existing foreign key.
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          fkid: Foreign key constraint ID
+
+        Returns:
+
+        """
+        # Below code will decide if it's simple drop or drop with cascade call
+        if self.cmd == 'delete':
+            # This is a cascade operation
+            cascade = True
+        else:
+            cascade = False
+        try:
+            sql = render_template("/".join([self.template_path, 'get_name.sql']), fkid=fkid)
+            status, res = self.conn.execute_dict(sql)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            data = res['rows'][0]
+            data['schema'] = self.schema
+            data['table'] = self.table
+
+            sql = render_template("/".join([self.template_path, 'delete.sql']), data=data, cascade=cascade)
+            status, res = self.conn.execute_scalar(sql)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            return make_json_response(
+                success=1,
+                info=_("Foreign key dropped."),
+                data={
+                    'id': fkid,
+                    'sid': sid,
+                    'gid': gid,
+                    'did': did
+                }
+            )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def msql(self, gid, sid, did, scid, tid, fkid=None):
+        """
+        This function returns modified SQL for the selected
+        foreign key.
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          fkid: Foreign key constraint ID
+
+        Returns:
+
+        """
+        data = {}
+        for k, v in request.args.items():
+            try:
+                data[k] = json.loads(v)
+            except ValueError:
+                data[k] = v
+
+        data['schema'] = self.schema
+        data['table'] = self.table
+        try:
+            sql = self.get_sql(data, tid, fkid)
+            sql = sql.strip('\n').strip(' ')
+
+            return make_json_response(
+                    data=sql,
+                    status=200
+                    )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    def get_sql(self, data, tid, fkid=None):
+        """
+        This function will generate sql from model data.
+
+        Args:
+          data: Contains the data of the selected foreign key constraint.
+          tid: Table ID.
+          fkid: Foreign key constraint ID
+
+        Returns:
+
+        """
+        if fkid is not None:
+            sql = render_template("/".join([self.template_path, 'properties.sql']), tid=tid, cid=fkid)
+            status, res = self.conn.execute_dict(sql)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            old_data = res['rows'][0]
+            required_args = ['name']
+            for arg in required_args:
+                if arg not in data:
+                    data[arg] = old_data[arg]
+
+            sql = render_template("/".join([self.template_path, 'update.sql']),
+                                  data=data, o_data=old_data)
+
+            if 'autoindex' in data and data['autoindex'] and\
+                    ('coveringindex' in data and
+                             data['coveringindex'] != ''):
+
+                col_sql = render_template("/".join([self.template_path,
+                                                'get_constraint_cols.sql']),
+                                      tid=tid,
+                                      keys=zip(old_data['confkey'], old_data['conkey']),
+                                      confrelid=old_data['confrelid'])
+
+                status, res = self.conn.execute_dict(col_sql)
+
+                if not status:
+                    return internal_server_error(errormsg=res)
+
+                columns = []
+                for row in res['rows']:
+                    columns.append({"local_column": row['conattname'],
+                                    "references": old_data['confrelid'],
+                                    "referenced": row['confattname']})
+
+                data['columns'] = columns
+
+                sql += render_template(
+                    "/".join([self.template_path, 'create_index.sql']),
+                    data=data, conn=self.conn)
+        else:
+            required_args = ['columns']
+
+            for arg in required_args:
+                if arg not in data:
+                    return _('-- definition incomplete')
+                elif isinstance(data[arg], list) and len(data[arg]) < 1:
+                    return _('-- definition incomplete')
+
+            if data['autoindex'] and ('coveringindex' not in data or
+                                      data['coveringindex'] == ''):
+                return _('-- definition incomplete')
+
+            SQL = render_template("/".join([self.template_path,
+                                            'get_parent.sql']),
+                                  tid=data['columns'][0]['references'])
+            status, rset = self.conn.execute_2darray(SQL)
+            if not status:
+                return internal_server_error(errormsg=rset)
+
+            data['remote_schema'] = rset['rows'][0]['schema']
+            data['remote_table'] = rset['rows'][0]['table']
+
+            sql = render_template("/".join([self.template_path, 'create.sql']),
+                                  data=data, conn=self.conn)
+            sql += "\n"
+            sql += render_template("/".join([self.template_path, 'alter.sql']),
+                                   data=data, conn=self.conn)
+
+            if data['autoindex']:
+                sql += render_template(
+                    "/".join([self.template_path, 'create_index.sql']),
+                    data=data, conn=self.conn)
+        return sql
+
+    @check_precondition
+    def sql(self, gid, sid, did, scid, tid, fkid=None):
+        """
+        This function generates sql to show in the sql pane for the selected
+        foreign key.
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          fkid: Foreign key constraint ID
+
+        Returns:
+
+        """
+        try:
+            SQL = render_template(
+                "/".join([self.template_path, 'properties.sql']),
+                tid=tid, conn=self.conn, cid=fkid)
+            status, res = self.conn.execute_dict(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            data = res['rows'][0]
+            data['schema'] = self.schema
+            data['table'] = self.table
+
+            sql = render_template("/".join([self.template_path,
+                                            'get_constraint_cols.sql']),
+                                  tid=tid,
+                                  keys=zip(data['confkey'], data['conkey']),
+                                  confrelid=data['confrelid'])
+
+            status, res = self.conn.execute_dict(sql)
+
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            columns = []
+            for row in res['rows']:
+                columns.append({"local_column": row['conattname'],
+                                "references": data['confrelid'],
+                                "referenced": row['confattname']})
+
+            data['columns'] = columns
+
+            SQL = render_template("/".join([self.template_path,
+                                            'get_parent.sql']),
+                                  tid=data['columns'][0]['references'])
+            status, res = self.conn.execute_2darray(SQL)
+
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            data['remote_schema'] = res['rows'][0]['schema']
+            data['remote_table'] = res['rows'][0]['table']
+
+            SQL = render_template(
+                "/".join([self.template_path, 'create.sql']), data=data)
+            SQL += "\n"
+            SQL += render_template(
+                "/".join([self.template_path, 'alter.sql']),
+                data=data, conn=self.conn)
+
+            sql_header = "-- Constraint: {0}\n\n-- ".format(data['name'])
+
+            sql_header += render_template(
+                    "/".join([self.template_path, 'delete.sql']),
+                    data=data)
+            sql_header += "\n"
+
+            SQL = sql_header + SQL
+
+            return ajax_response(response=SQL)
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def dependents(self, gid, sid, did, scid, tid, fkid=None):
+        """
+        This function gets the dependents and returns an ajax response
+        for the event trigger node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            etid: Event trigger ID
+        """
+        dependents_result = self.get_dependents(self.conn, fkid)
+        return ajax_response(
+                response=dependents_result,
+                status=200
+                )
+
+    @check_precondition
+    def dependencies(self, gid, sid, did, scid, tid, fkid=None):
+        """
+        This function gets the dependencies and returns an ajax response
+        for the event trigger node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            etid: Event trigger ID
+        """
+        dependencies_result = self.get_dependencies(self.conn, fkid)
+        return ajax_response(
+                response=dependencies_result,
+                status=200
+                )
+
+    @check_precondition
+    def validate_foreign_key(self, gid, sid, did, scid, tid, fkid):
+        """
+
+        Args:
+          gid:
+          sid:
+          did:
+          scid:
+          tid:
+          fkid:
+
+        Returns:
+
+        """
+        data = {}
+        try:
+            data['schema'] = self.schema
+            data['table'] = self.table
+            sql = render_template("/".join([self.template_path, 'get_name.sql']), fkid=fkid)
+            status, res = self.conn.execute_scalar(sql)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            data['name'] = res
+            sql = render_template("/".join([self.template_path, 'validate.sql']), data=data)
+            status, res = self.conn.execute_dict(sql)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            return make_json_response(
+                success=1,
+                info=_("Foreign key updated."),
+                data={
+                    'id': fkid,
+                    'tid': tid,
+                    'scid': scid,
+                    'did': did
+                }
+            )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    def search_coveringindex(self, tid, cols):
+        """
+
+        Args:
+          tid: Table id
+          cols: column list
+
+        Returns:
+
+        """
+
+        cols = set(cols)
+        SQL = render_template("/".join([self.template_path,
+                                        'get_constraints.sql']),
+                              tid=tid)
+        status, constraints = self.conn.execute_dict(SQL)
+
+        if not status:
+            raise Exception(constraints)
+
+        for costrnt in constraints['rows']:
+
+            sql = render_template(
+                "/".join([self.template_path, 'get_cols.sql']),
+                cid=costrnt['oid'],
+                colcnt=costrnt['indnatts'])
+            status, rest = self.conn.execute_dict(sql)
+
+            if not status:
+                return internal_server_error(errormsg=rest)
+
+            indexcols = set()
+            for r in rest['rows']:
+                indexcols.add(r['column'].strip('"'))
+
+            if len(cols - indexcols) == len(indexcols - cols) == 0:
+                return costrnt["idxname"]
+
+        return None
+
+    @check_precondition
+    def get_coveringindex(self, gid, sid, did, scid, tid=None):
+        """
+
+        Args:
+          gid:
+          sid:
+          did:
+          scid:
+          tid:
+
+        Returns:
+
+        """
+
+        data = request.args if request.args else None
+        index = None
+        try:
+            if data and 'cols' in data:
+                cols = set(json.loads(data['cols']))
+                index = self.search_coveringindex(tid, cols)
+
+            return make_json_response(
+                data=index,
+                status=200
+                )
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+constraint = ConstraintRegistry(
+    'foreign_key', ForeignKeyConstraintModule, ForeignKeyConstraintView
+    )
+ForeignKeyConstraintView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/static/img/foreign_key.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/static/img/foreign_key.png
new file mode 100644
index 0000000000000000000000000000000000000000..b3605500439db72c2c43879abb61a24c956e1bf5
GIT binary patch
literal 299
zcmeAS@N?(olHy`uVBq!ia0vp^0wBx*Bp9q_EZ7UAm`Z~Df*BafCZDwc@shmVT^JZv
z^(q?yd7K3vk;OpT1B~5HX4?T7@t!V@ArhC96BcmYxO{&<`^@{hp1!(zcCE*!Xt{ek
z>#~zoS#lB*UhMz1;M236-R60Bchvnn_1J5|fxo9_r|aE`sZD=6Ra!x`dfT1-l|Ns#
zc?qz5Y;4QhSCW{_ZI`Xd&M@z_Ipcx{mt%ldsg}4#l%yn<q*^5xr2;7iBLhPNT|*;X
z1H%v_11l3_D-%;~15+ylgL&`tR-tIf%}>cptAuDUumo!Wsy4AQFoS3~H9d3<Py>Uf
LtDnm{r-UW|7b#?7

literal 0
HcmV?d00001

diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/static/img/foreign_key_no_validate.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/static/img/foreign_key_no_validate.png
new file mode 100644
index 0000000000000000000000000000000000000000..975561bcf7237d5e99e9d42ff705db67f1bb2fdb
GIT binary patch
literal 618
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47?}cmLR^8|J$v@__xDejFyZ2b
zi$8z-{QB`zYisM4En6<0I(I!O=_mukh49ENQx_g}_r9B%`S9VxT^qNb3Jm#HUVhl!
zdv;s@UR$S+;o(=WUVZT3K}|{3x3aQtMMYop^7dFed<+YF@9+Q4!}I?A`&DI?UvqQ6
zWMq6!O8O8Q`rZ#H?s56j<qIdyd`?XK7#;l~B;>uX-#d5r&6_u0x^(Hn`SXVl9ln*C
z`XLx7?)%QoZIzC3Utiz$4V$k4O$ZKt@8k2%)%A^?{c8)0-OjEbf`Z<Ad%tyYeQj?3
z%Fytow)Tg>z;|9=Z=GFcI(xm;(te?;`dmTbt&{T+H?Q>ONi$u%pUW#W=hVD!YnKOx
z0%J*#UoeBivm0qZ4rhT!WHFHT0Ash4*>*t2d`}n05Q)ocd!Gt51&FlhcQmc(yxVnG
z_QqY=_y4tuT#tzt)X$mu_uM%>#d^WRQWlF}KCf&v?%p7fwDq9h|E9y52U)it=ayGp
zV=v&MA>$~rv4TnDgeT|961JN$^VB39^+a5!oSK^T_Oj!Ts>L_67GHkr`19O1cITdB
zlVAFHub7p*F(z^E%~veD|1!GIIVYasa7c9fZ)Shnk3kvpt3v;?HQy7Q(A;;*1?W`O
z64!{5l*E!$tK_0oAjM#0U}&goV61Ck5n^a$WoT|?V5x0jW@TV-`Pqsj6b-rgDVb@N
WxHT-=EpQL0fx*+&&t;ucLK6V@6Aj$}

literal 0
HcmV?d00001

diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/templates/foreign_key/css/foreign_key.css b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/templates/foreign_key/css/foreign_key.css
new file mode 100644
index 0000000..aeaff11
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/templates/foreign_key/css/foreign_key.css
@@ -0,0 +1,12 @@
+.icon-foreign_key {
+  background-image: url('{{ url_for('NODE-foreign_key.static', filename='img/foreign_key.png') }}') !important;
+  background-repeat: no-repeat;
+  align-content: center;
+  vertical-align: middle;
+  height: 1.3em;
+}
+
+.icon-foreign_key_no_validate {
+  background-image: url('{{ url_for('NODE-foreign_key.static', filename='img/foreign_key_no_validate.png') }}') !important;
+  border-radius: 10px
+}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/templates/foreign_key/js/foreign_key.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/templates/foreign_key/js/foreign_key.js
new file mode 100644
index 0000000..7da458a
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/templates/foreign_key/js/foreign_key.js
@@ -0,0 +1,1072 @@
+define(
+        ['jquery', 'underscore', 'underscore.string', 'pgadmin',
+        'pgadmin.browser', 'alertify', 'pgadmin.browser.collection'],
+function($, _, S, pgAdmin, pgBrowser, Alertify) {
+
+  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 class="wcTabIcon ' + optimage + '"/>' + opt.text + '</span>'
+          );
+    }
+  },
+      headerSelectControlTemplate =  _.template([
+                              '<div class="<%=Backform.controlsClassName%> <%=extraClasses.join(\' \')%>">',
+                              '  <select class="pgadmin-node-select form-control" name="<%=name%>" style="width:100%;" value="<%-value%>" <%=disabled ? "disabled" : ""%> <%=required ? "required" : ""%> >',
+                              '    <% if (first_empty) { %>',
+                              '    <option value="" <%="" === rawValue ? "selected" : "" %>><%- empty_value %></option>',
+                              '    <% } %>',
+                              '    <% for (var i=0; i < options.length; i++) { %>',
+                              '    <% var option = options[i]; %>',
+                              '    <option <% if (option.image) { %> data-image=<%= option.image %> <% } %> value=<%= formatter.fromRaw(option.value) %> <%=option.value === rawValue ? "selected=\'selected\'" : "" %>><%-option.label%></option>',
+                              '    <% } %>',
+                              '  </select>',
+                              '</div>'].join("\n"));
+
+  var ForeignKeyColumnModel = pgBrowser.Node.Model.extend({
+    defaults: {
+      local_column: undefined,
+      references: undefined,
+      referenced: undefined
+    },
+    schema: [{
+        id: 'local_column', label:'Local', type:'text', editable: false,
+        cellHeaderClasses: 'width_percent_50', cell:'string',
+        headerCell: Backgrid.Extension.CustomHeaderCell
+      },{
+        id: 'referenced', label:'Referenced', type: 'text', editable: false,
+        cell:'string', cellHeaderClasses: 'width_percent_50',
+        headerCell: Backgrid.Extension.CustomHeaderCell
+      }]
+  });
+
+  var ForeignKeyColumnControl =  Backform.ForeignKeyColumnControl =
+    Backform.UniqueColCollectionControl.extend({
+
+    initialize: function(opts) {
+      Backform.UniqueColCollectionControl.prototype.initialize.apply(
+        this, arguments
+          );
+
+      var self = this,
+        node = 'foreign_key',
+        headerSchema = [{
+          id: 'local_column', label:'', type:'text',
+          node: 'column', control: Backform.NodeListByNameControl.extend({
+            initialize: function() {
+              // Here we will decide if we need to call URL
+              // Or fetch the data from parent columns collection
+                if(self.model.handler) {
+                  Backform.Select2Control.prototype.initialize.apply(this, arguments);
+                  // Do not listen for any event(s) for existing constraint.
+                  if (_.isUndefined(self.model.get('oid'))) {
+                    var tableCols = self.model.top.get('columns');
+                    this.listenTo(tableCols, 'remove' , this.removeColumn);
+                    this.listenTo(tableCols, 'change:name', this.resetColOptions);
+                  }
+
+                  this.custom_options();
+                } else {
+                  Backform.NodeListByNameControl.prototype.initialize.apply(this, arguments);
+                }
+            },
+            removeColumn: function (m) {
+              var that = this;
+              setTimeout(function   () {
+                that.custom_options();
+                that.render.apply(that);
+              }, 50);
+            },
+            resetColOptions: function(m) {
+              var that = this;
+
+              if (m.previous('name') ==  self.headerData.get('local_column')) {
+                /*
+                 * Table column name has changed so update
+                 * column name in foreign key as well.
+                 */
+                self.headerData.set(
+                  {"local_column": m.get('name')});
+                  self.headerDataChanged();
+              }
+
+              setTimeout(function () {
+                that.custom_options();
+                that.render.apply(that);
+              }, 50);
+            },
+            custom_options: function() {
+              // We will add all the columns entered by user in table model
+              var columns = self.model.top.get('columns'),
+                  added_columns_from_tables = [];
+
+              if (columns.length > 0) {
+                _.each(columns.models, function(m) {
+                    var col = m.get('name');
+                    if(!_.isUndefined(col) && !_.isNull(col)) {
+                      added_columns_from_tables.push(
+                        {label: col, value: col, image:'icon-column'}
+                      );
+                    }
+                });
+              }
+              // Set the values in to options so that user can select
+              this.field.set('options', added_columns_from_tables);
+            },
+            template: headerSelectControlTemplate,
+            remove: function () {
+              if(self.model.handler) {
+                var tableCols = self.model.top.get('columns');
+                this.stopListening(tableCols, 'remove' , this.removeColumn);
+                this.stopListening(tableCols, 'change:name' , this.resetColOptions);
+
+                Backform.Select2Control.prototype.remove.apply(this, arguments);
+
+              } else {
+                Backform.NodeListByNameControl.prototype.remove.apply(this, arguments);
+              }
+            }
+          }),
+          select2: {
+            allowClear: false, width: 'style',
+            placeholder: 'Select column'
+          }, first_empty: !_.isUndefined(self.model.get('oid')),
+          version_compatible: self.field.get('version_compatible'),
+          disabled: function(m) {
+            return !_.isUndefined(self.model.get('oid'));
+          }
+        },{
+          id: 'references', label:'', type: 'text', cache_level: 'server',
+          select2: {
+            allowClear: false, width: 'style',
+            placeholder: 'Select foreign table',
+          }, first_empty: true,
+          control: Backform.NodeListByNameControl.extend({
+            formatter: Backform.ControlFormatter,
+            template: headerSelectControlTemplate
+            }),
+          url: 'all_tables', node: 'table',
+          version_compatible: self.field.get('version_compatible'),
+          disabled: function(m) {
+            return !_.isUndefined(self.model.get('oid'));
+          },
+          transform: function(rows) {
+            var res = [];
+            _.each(rows, function(r) {
+              res.push({
+                'value': r.value,
+                'image': "icon-table",
+                'label': r.label
+              });
+            });
+            return res;
+          }
+        },{
+          id: 'referenced', label:'', type: 'text', cache_level: 'server',
+          transform: function(rows) {
+            var res = [];
+            _.each(rows, function(r) {
+              res.push({
+                'value': r.name,
+                'image': 'icon-column',
+                'label': r.name
+              });
+            });
+            return res;
+          },
+          control: Backform.Select2Control.extend({
+            formatter: Backform.ControlFormatter,
+            template: headerSelectControlTemplate,
+            render: function() {
+              var self = this,
+              url = self.field.get('url') || self.defaults.url,
+              m = self.model,
+              tid = m.get('references');
+
+              // Clear any existing value before setting new options.
+              m.set(self.field.get('name'), null, {silent: true});
+
+              if (url && !_.isUndefined(tid) && !_.isNull(tid) && tid != '') {
+                var node = this.field.get('schema_node'),
+                    node_info = this.field.get('node_info'),
+                    full_url = node.generate_url.apply(
+                      node, [
+                        null, url, this.field.get('node_data'),
+                        this.field.get('url_with_id') || false, node_info
+                      ]),
+                    data = [];
+
+                if (this.field.get('version_compatible')) {
+                  m.trigger('pgadmin:view:fetching', m, self.field);
+                  $.ajax({
+                    async: false,
+                    data : {tid:tid},
+                    url: full_url,
+                    success: function(res) {
+                      data = res.data;
+                    },
+                    error: function() {
+                      m.trigger('pgadmin:view:fetch:error', m, self.field);
+                    }
+                  });
+                  m.trigger('pgadmin:view:fetched', m, self.field);
+                }
+                /*
+                 * Transform the data
+                 */
+                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);
+                }
+              } else {
+                self.field.set('options', []);
+              }
+              Backform.Select2Control.prototype.render.apply(this, arguments);
+              return this;
+            }
+          }), url: 'get_columns', first_empty: true,
+          select2: {
+            width: "style",
+            placeholder: 'Select column',
+            templateResult: formatNode,
+            templateSelection: formatNode
+          },
+          deps:['references'],  node: 'table',
+          version_compatible: self.field.get('version_compatible'),
+          disabled: function(m) {
+            return !_.isUndefined(self.model.get('oid'));
+          }
+        }],
+        headerDefaults = {local_column: null,
+                          references: null,
+                          referenced:null},
+        gridCols = ['local_column', 'references', 'referenced'];
+
+      if ((!self.model.isNew() && _.isUndefined(self.model.handler)) ||
+          (_.has(self.model, 'handler') &&
+          !_.isUndefined(self.model.handler) &&
+          !_.isUndefined(self.model.get('oid')))) {
+        var column = self.collection.first();
+        if (column) {
+          headerDefaults["references"] = column.get("references");
+        }
+      }
+
+      self.headerData = new (Backbone.Model.extend({
+        defaults: headerDefaults,
+        schema: headerSchema
+      }))({});
+
+      var headerGroups = Backform.generateViewSchema(
+          self.field.get('node_info'), self.headerData, 'create',
+          node, self.field.get('node_data')
+          ),
+          fields = [];
+
+      _.each(headerGroups, function(o) {
+        fields = fields.concat(o.fields);
+      });
+
+      self.headerFields = new Backform.Fields(fields);
+      self.gridSchema = Backform.generateGridColumnsFromModel(
+          //null, ForeignKeyColumnModel, 'edit', gridCols
+          self.field.get('node_info'), self.field.get('model'), 'edit',
+          gridCols, self.field.get('schema_node')
+          );
+
+      self.controls = [];
+      self.listenTo(self.headerData, "change", self.headerDataChanged);
+      self.listenTo(self.headerData, "select2", self.headerDataChanged);
+      self.listenTo(self.collection, "add", self.onAddorRemoveColumns);
+      self.listenTo(self.collection, "remove", self.onAddorRemoveColumns);
+    },
+
+    generateHeader: function(data) {
+      var header = [
+        '<div class="subnode-header-form">',
+        ' <div class="container-fluid">',
+        '  <div class="row">',
+        '   <div class="col-md-4">',
+        '    <label class="control-label"><%-column_label%></label>',
+        '   </div>',
+        '   <div class="col-md-4" header="local_column"></div>',
+        '   <div class="col-md-4">',
+        '     <button class="btn-sm btn-default add" <%=canAdd ? "" : "disabled=\'disabled\'"%> ><%-add_label%></buttton>',
+        '   </div>',
+        '  </div>',
+        '  <div class="row">',
+        '   <div class="col-md-4">',
+        '    <label class="control-label"><%-references_label%></label>',
+        '   </div>',
+        '   <div class="col-md-4" header="references"></div>',
+        '  </div>',
+        '  <div class="row">',
+        '   <div class="col-md-4">',
+        '    <label class="control-label"><%-referenced_label%></label>',
+        '   </div>',
+        '   <div class="col-md-4" header="referenced"></div>',
+        '  </div>',
+        ' </div>',
+        '</div>',].join("\n")
+
+      _.extend(data, {
+        column_label: '{{ _('Local column')}}',
+        add_label: '{{ _('ADD')}}',
+        references_label: '{{ _('References')}}',
+        referenced_label: '{{ _('Referencing')}}'
+      });
+
+      var self = this,
+          headerTmpl = _.template(header),
+          $header = $(headerTmpl(data)),
+          controls = this.controls;
+
+      this.headerFields.each(function(field) {
+        var control = new (field.get("control"))({
+          field: field,
+          model: self.headerData
+        });
+
+        $header.find('div[header="' + field.get('name') + '"]').append(
+          control.render().$el
+        );
+
+        controls.push(control);
+      });
+
+      // We should not show add but in properties mode
+      if (data.mode == 'properties') {
+        $header.find("button.add").remove();
+      }
+
+      self.$header = $header;
+
+      return $header;
+    },
+
+    events: _.extend(
+                {}, Backform.UniqueColCollectionControl.prototype.events,
+                {'click button.add': 'addColumns'}
+                ),
+
+    showGridControl: function(data) {
+
+      var self = this,
+          titleTmpl = _.template([
+            "<div class='subnode-header'>",
+            "<label class='control-label'><%-label%></label>",
+            "</div>"].join("\n")),
+          $gridBody =
+            $("<div class='pgadmin-control-group backgrid form-group col-xs-12 object subnode'></div>").append(
+              titleTmpl({label: data.label})
+            );
+
+      $gridBody.append(self.generateHeader(data));
+
+      var gridSchema = _.clone(this.gridSchema);
+
+      // Insert Delete Cell into Grid
+      if (data.disabled == false && data.canDelete) {
+          gridSchema.columns.unshift({
+            name: "pg-backform-delete", label: "",
+            cell: Backgrid.Extension.DeleteCell,
+            editable: false, cell_priority: -1
+          });
+      }
+
+      // Initialize a new Grid instance
+      var grid = self.grid = new Backgrid.Grid({
+        columns: gridSchema.columns,
+        collection: self.collection,
+        className: "backgrid table-bordered"
+      });
+      self.$grid = grid.render().$el;
+
+      $gridBody.append(self.$grid);
+
+      setTimeout(function() {
+        self.headerData.set({
+          'local_column':
+          self.$header.find(
+            'div[header="local_column"] select option:first'
+            ).val(),
+            'referenced':
+          self.$header.find(
+            'div[header="referenced"] select option:first'
+            ).val(),
+            'references':
+          self.$header.find(
+            'div[header="references"] select option:first'
+            ).val()
+            }, {silent:true}
+          );
+      }, 10);
+
+      // Render node grid
+      return $gridBody;
+    },
+
+    headerDataChanged: function() {
+      var self = this, val,
+          data = this.headerData.toJSON(),
+          inSelected = false,
+          checkVars = ['local_column', 'referenced'];
+
+      if (!self.$header) {
+        return;
+      }
+
+      if (self.control_data.canAdd) {
+        self.collection.each(function(m) {
+          if (!inSelected) {
+            _.each(checkVars, function(v) {
+              if (!inSelected) {
+                val = m.get(v);
+                inSelected = ((
+                  (_.isUndefined(val) || _.isNull(val)) &&
+                  (_.isUndefined(data[v]) || _.isNull(data[v]))
+                  ) ||
+                  (val == data[v]));
+              }
+            });
+          }
+        });
+      }
+      else {
+        inSelected = true;
+      }
+
+      self.$header.find('button.add').prop('disabled', inSelected);
+    },
+
+    addColumns: function(ev) {
+      ev.preventDefault();
+      var self = this,
+          local_column = self.headerData.get('local_column'),
+          referenced = self.headerData.get('referenced');
+
+      if (!local_column || local_column == '' ||
+          !referenced || referenced  =='') {
+        return false;
+      }
+
+      var m = new (self.field.get('model'))(
+                self.headerData.toJSON()),
+          coll = self.model.get(self.field.get('name'));
+
+      coll.add(m);
+
+      var idx = coll.indexOf(m);
+
+      // idx may not be always > -1 because our UniqueColCollection may
+      // remove 'm' if duplicate value found.
+      if (idx > -1) {
+        self.$grid.find('.new').removeClass('new');
+
+        var newRow = self.grid.body.rows[idx].$el;
+
+        newRow.addClass("new");
+        $(newRow).pgMakeVisible('backform-tab');
+      } else {
+        delete m;
+      }
+
+      return false;
+    },
+
+    onAddorRemoveColumns: function() {
+      var self = this;
+
+      // Wait for collection to be updated before checking for the button to be
+      // enabled, or not.
+      setTimeout(function() {
+        if (self.collection.length > 0) {
+          self.$header.find(
+            'div[header="references"] select'
+            ).prop('disabled', true);
+        } else {
+          self.$header.find(
+            'div[header="references"] select'
+            ).prop('disabled', false);
+        }
+
+        self.collection.trigger('pgadmin:columns:updated', self.collection);
+
+        self.headerDataChanged();
+
+        if ((!_.has(self.model, 'handler') || (_.has(self.model, 'handler') &&
+              _.isUndefined(self.model.handler))) ||
+            (_.has(self.model, 'handler') && !_.isUndefined(self.model.handler) &&
+            !_.isUndefined(self.model.handler.get('oid')))) {
+          self.getCoveringIndex();
+        }
+
+      }, 10);
+    },
+
+    getCoveringIndex: function() {
+
+      var self = this,
+          url = 'get_coveringindex',
+          m = self.model
+          cols = [],
+          coveringindex = null;
+
+          self.collection.each(function(m){
+            cols.push(m.get('local_column'));
+          })
+
+          if (cols.length > 0) {
+            var node = this.field.get('schema_node'),
+              node_info = this.field.get('node_info'),
+              full_url = node.generate_url.apply(
+                node, [
+                  null, url, this.field.get('node_data'),
+                  this.field.get('url_with_id') || false, node_info
+                ]);
+
+            if (this.field.get('version_compatible')) {
+              m.trigger('pgadmin:view:fetching', m, self.field);
+              $.ajax({
+                async: false,
+                data : {cols:JSON.stringify(cols)},
+                url: full_url,
+                success: function(res) {
+                  coveringindex = res.data;
+                },
+                error: function() {
+                  m.trigger('pgadmin:view:fetch:error', m, self.field);
+                }
+              });
+              m.trigger('pgadmin:view:fetched', m, self.field);
+            }
+          }
+
+          if (coveringindex) {
+            m.set('hasindex', true);
+            m.set('autoindex', false);
+            m.set('coveringindex', coveringindex);
+          } else {
+            m.set('coveringindex', null);
+            m.set('autoindex', true);
+            m.set('hasindex', false);
+          }
+    },
+
+    remove: function() {
+      /*
+       * Stop listening the events registered by this control.
+       */
+      this.stopListening(this.headerData, "change", this.headerDataChanged);
+      this.listenTo(this.headerData, "select2", this.headerDataChanged);
+      this.listenTo(this.collection, "remove", this.onRemoveVariable);
+      // Remove header controls.
+      _.each(this.controls, function(controls) {
+        controls.remove();
+      });
+
+      ForeignKeyColumnControl.__super__.remove.apply(this, arguments);
+
+      // Remove the header model
+      delete (this.headerData);
+
+    }
+  });
+
+  // Extend the browser's node class for foreign key node
+  if (!pgBrowser.Nodes['foreign_key']) {
+    pgAdmin.Browser.Nodes['foreign_key'] = pgBrowser.Node.extend({
+      type: 'foreign_key',
+      label: '{{ _('Foreign key') }}',
+      collection_type: 'coll-constraints',
+      sqlAlterHelp: 'ddl-alter.html',
+      sqlCreateHelp: 'ddl-constraints.html',
+      hasSQL: true,
+      hasDepends: false,
+      parent_type: 'table',
+      canDrop: true,
+      canDropCascade: true,
+      hasDepends: true,
+      Init: function() {
+        /* Avoid multiple registration of menus */
+        if (this.initialized)
+            return;
+
+        this.initialized = true;
+
+        pgBrowser.add_menus([{
+          name: 'create_foreign_key_on_coll', node: 'coll-constraints', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('Foreign key...') }}',
+          icon: 'wcTabIcon icon-foreign_key', data: {action: 'create', check: true},
+          enable: 'canCreate'
+        },{
+          name: 'validate_foreign_key', node: 'foreign_key', module: this,
+          applies: ['object', 'context'], callback: 'validate_foreign_key',
+          category: 'validate', priority: 4, label: '{{ _('Validate foreign key') }}',
+          icon: 'fa fa-link', enable : 'is_not_valid'
+        }
+        ]);
+      },
+      is_not_valid: function(node) {
+        return (node && !node.valid);
+      },
+      callbacks: {
+        validate_foreign_key: function(args) {
+          var input = args || {};
+          obj = this,
+          t = pgBrowser.tree,
+          i = input.item || t.selected(),
+          d = i && i.length == 1 ? t.itemData(i) : undefined;
+
+          if (!d) {
+            return false;
+          }
+          var data = d;
+          $.ajax({
+            url: obj.generate_url(i, 'validate', d, true),
+            type:'GET',
+            success: function(res) {
+              if (res.success == 1) {
+                Alertify.success("{{ _('" + res.info + "') }}");
+                t.removeIcon(i);
+                data.valid = true;
+                data.icon = 'icon-foreign_key';
+                t.addIcon(i, {icon: data.icon});
+                setTimeout(function() {t.deselect(i);}, 10);
+                setTimeout(function() {t.select(i);}, 100);
+              }
+            },
+            error: function(xhr, status, error) {
+              try {
+                var err = $.parseJSON(xhr.responseText);
+                if (err.success == 0) {
+                  msg = S('{{ _(' + err.errormsg + ')}}').value();
+                  Alertify.error("{{ _('" + err.errormsg + "') }}");
+                }
+              } catch (e) {}
+              t.unload(i);
+            }
+            });
+
+          return false;
+        }
+      },
+      // Define the model for foreign key node
+      model: pgAdmin.Browser.Node.Model.extend({
+        defaults: {
+          name: undefined,
+          oid: undefined,
+          comment: undefined,
+          condeferrable: undefined,
+          condeferred: undefined,
+          confmatchtype: undefined,
+          convalidated: undefined,
+          columns: undefined,
+          confupdtype: "a",
+          confdeltype: "a",
+          autoindex: true,
+          coveringindex: undefined,
+          hasindex:undefined
+        },
+        toJSON: function () {
+          var d = pgAdmin.Browser.Node.Model.prototype.toJSON.apply(this, arguments);
+          delete d.hasindex;
+          return d;
+        },
+        // Define the schema for the foreign key node
+        schema: [{
+          id: 'name', label: '{{ _('Name') }}', type: 'text',
+          mode: ['properties', 'create', 'edit'], editable:true,
+          headerCell: Backgrid.Extension.CustomHeaderCell, cellHeaderClasses: 'width_percent_50'
+        },{
+          id: 'oid', label:'{{ _('OID') }}', cell: 'string',
+          type: 'text' , mode: ['properties']
+        },{
+          id: 'comment', label:'{{ _('Comment') }}', cell: 'string',
+          type: 'multiline', mode: ['properties', 'create', 'edit'],
+          deps:['name'], disabled:function(m) {
+            var name = m.get('name');
+            if (!(name && name != '')) {
+              setTimeout(function(){
+                m.set('comment', null);
+              },10);
+              return true;
+            } else {
+              return false;
+            }
+          }
+        },{
+          id: 'condeferrable', label: '{{ _('Deferrable') }}',
+          type: 'switch', group: '{{ _('Definition') }}',
+          disabled: function(m) {
+            // If we are in table edit mode then
+            if (_.has(m, 'handler') && !_.isUndefined(m.handler)) {
+                // If OID is undefined then user is trying to add
+                // new constraint which should allowed for Unique
+                return !_.isUndefined(m.get('oid'));
+            }
+            // We can't update condeferrable of existing foreign key.
+            return !m.isNew();
+          }
+        },{
+          id: 'condeferred', label: '{{ _('Deferred') }}',
+          type: 'switch', group: '{{ _('Definition') }}',
+          deps: ['condeferrable'],
+          disabled: function(m) {
+            // If we are in table edit mode then
+            if (_.has(m, 'handler') && !_.isUndefined(m.handler)) {
+                // If OID is undefined then user is trying to add
+                // new constraint which should allowed for Unique
+                return !_.isUndefined(m.get('oid'));
+            } else if(!m.isNew()) {
+              return true;
+            }
+            // Disable if condeferred is false or unselected.
+            if(m.get('condeferrable') == true) {
+              return false;
+            } else {
+              setTimeout(function(){
+                m.set('condeferred', false);
+              },10);
+              return true;
+            }
+          }
+        },{
+          id: 'confmatchtype', label: '{{ _('Match type') }}',
+          type: 'switch', group: '{{ _('Definition') }}',
+          options: {
+            onText: 'FULL',
+            offText: 'SIMPLE',
+          },disabled: function(m) {
+            // If we are in table edit mode then
+            if (_.has(m, 'handler') && !_.isUndefined(m.handler)) {
+                // If OID is undefined then user is trying to add
+                // new constraint which should allowed for Unique
+                return !_.isUndefined(m.get('oid'));
+            }
+            // We can't update condeferred of existing foreign key.
+            return !m.isNew();
+          }
+        },{
+          id: 'convalidated', label: "{{ _("Validated?") }}",
+          type: 'switch', group: '{{ _('Definition') }}',
+          options: {
+            onText: 'Yes',
+            offText: 'No'
+          },disabled: function(m) {
+            // If we are in table edit mode then
+            if (_.has(m, 'handler') && !_.isUndefined(m.handler)) {
+                // If OID is undefined then user is trying to add
+                // new constraint which should allowed
+                return !(_.isUndefined(m.get('oid')) || m.get("convalidated"));
+            }
+            // We can't update condeferred of existing foreign key.
+            return !(m.isNew() || m.get("convalidated"));
+          }
+        },{
+          id: 'autoindex', label: '{{ _('Auto FK index') }}',
+          type: 'switch', group: '{{ _('Definition') }}',
+          deps: ['name', 'hasindex'],
+          options: {
+            onText: 'Yes',
+            offText: 'No',
+          },disabled: function(m) {
+            var index = m.get('coveringindex'),
+                autoindex = m.get('autoindex'),
+                setIndexName = function() {
+                  var name = m.get('name'),
+                  oldindex = 'fki_'+m.previous ('name');
+
+                  if (m.get('hasindex')) {
+                    return true;
+                  } else if (m.get('autoindex') && !_.isUndefined(name) && !_.isNull(name) &&
+                              name != '' && (_.isUndefined(index) || _.isNull(index) ||
+                              index == '' || index == oldindex)) {
+                    var newIndex = 'fki_' + name;
+                    m.set('coveringindex', newIndex);
+                    return false;
+                  } else {
+                    return false;
+                  }
+                };
+            // If we are in table edit mode then
+            if (_.has(m, 'handler') && !_.isUndefined(m.handler)) {
+                // If OID is undefined then user is trying to add
+                // new constraint which should allowed for Unique
+                if(_.isUndefined(m.get('oid')) && _.isUndefined(m.handler.get('oid'))) {
+                  setTimeout(function () {
+                    m.set('autoindex', false);
+                  }, 10);
+                  return true;
+                } else {
+                  return setIndexName();
+                }
+            } else {
+              if(!m.isNew() && autoindex && !_.isUndefined(index) &&
+                    !_.isNull(index) && index != '' && m.get('hasindex')) {
+                return true;
+              } else {
+                return setIndexName();
+              }
+            }
+          }
+        },{
+          id: 'coveringindex', label: '{{ _('Covering index') }}', type: 'text',
+          mode: ['properties', 'create', 'edit'], group: '{{ _('Definition') }}',
+          deps:['autoindex', 'hasindex'],
+          disabled: function(m) {
+            var index = m.get('coveringindex'),
+              setIndexName = function() {
+                if (m.get('hasindex')) {
+                  return true;
+                } else if (!m.get('autoindex')) {
+                  setTimeout(function () {
+                    m.set('coveringindex', null);
+                  });
+                  return true;
+                } else {
+                  setTimeout(function () {
+                    var name = m.get('name'),
+                      newIndex = 'fki_' + name;
+
+                      if (m.get('autoindex') && !_.isUndefined(name) && !_.isNull(name) &&
+                            name != '') {
+                        m.set('coveringindex', newIndex);
+                      }
+                  });
+
+                  return false;
+                }
+              };
+
+            // If we are in table edit mode then
+            if (_.has(m, 'handler') && !_.isUndefined(m.handler)) {
+                // If OID is undefined then user is trying to add
+                // new constraint which should allowed for Unique
+                if (_.isUndefined(m.get('oid')) && _.isUndefined(m.handler.get('oid'))) {
+                  return true;
+                } else {
+                  return setIndexName();
+                }
+
+            } else if (!m.isNew() && m.get('autoindex') && !_.isUndefined(index)
+                        && _.isNull(index) && index == '') {
+              return true;
+            }
+
+            return setIndexName();
+          }
+        },{
+          id: 'columns', label: '{{ _('Columns') }}',
+          type: 'collection', group: '{{ _('Columns') }}', disabled: false,
+          node: 'foreign_key', editable: false, headerCell: Backgrid.Extension.CustomHeaderCell,
+          cellHeaderClasses: 'width_percent_50',
+          cell: Backgrid.StringCell.extend({
+            initialize: function() {
+              Backgrid.StringCell.prototype.initialize.apply(this, arguments);
+              var self = this,
+                collection = this.model.get('columns');
+              // Do not listen for any event(s) for existing constraint.
+              if (_.isUndefined(self.model.get('oid'))) {
+                var tableCols = self.model.top.get('columns');
+                self.listenTo(tableCols, 'remove' , self.removeColumn);
+                self.listenTo(tableCols, 'change:name', self.resetColOptions);
+              }
+
+              self.model.get('columns').on('pgadmin:columns:updated', function() {
+                self.render.apply(self);
+              });
+              self.listenTo(collection, "add", self.render);
+              self.listenTo(collection, "remove", self.render);
+            },
+            removeColumn: function(m){
+              var self = this,
+                  removedCols = self.model.get('columns').where(
+                    {local_column: m.get('name')}
+                    );
+
+              self.model.get('columns').remove(removedCols);
+              setTimeout(function () {
+                self.render();
+              }, 10);
+
+              setTimeout(function () {
+                constraints = self.model.top.get("foreign_key");
+                var removed = [];
+                constraints.each(function(constraint) {
+                  if (constraint.get("columns").length == 0) {
+                     removed.push(constraint);
+                  }
+                });
+                constraints.remove(removed);
+              },100);
+            },
+            resetColOptions : function(m) {
+                var self = this,
+                  updatedCols = self.model.get('columns').where(
+                  {"local_column": m.previous('name')}
+                  );
+                if (updatedCols.length > 0) {
+                  /*
+                   * Table column name has changed so update
+                   * column name in foreign key as well.
+                   */
+                  updatedCols[0].set(
+                  {"local_column": m.get('name')});
+                }
+
+                setTimeout(function () {
+                  self.render();
+                }, 10);
+            },
+            formatter: {
+              fromRaw: function (rawValue, model) {
+                var cols = [],
+                    remote_cols = [];
+                if (rawValue.length > 0) {
+                  rawValue.each(function(col){
+                    cols.push(col.get('local_column'));
+                    remote_cols.push(col.get('referenced'))
+                  });
+                  return '('+cols.join(', ')+') -> ('+ remote_cols.join(', ')+')';
+                }
+                return "";
+              },
+              toRaw: function (val, model) {
+                return val;
+              }
+            },
+            render: function() {
+              return Backgrid.StringCell.prototype.render.apply(this, arguments);
+            },
+            remove: function() {
+              var tableCols = this.model.top.get('columns');
+
+              this.stopListening(tableCols, 'remove' , self.removeColumn);
+              this.stopListening(tableCols, 'change:name' , self.resetColOptions);
+
+              Backgrid.StringCell.prototype.remove.apply(this, arguments);
+            }
+          }),
+          canAdd: function(m) {
+            // We can't update columns of existing foreign key.
+            return m.isNew();
+          }, canDelete: true,
+          control: ForeignKeyColumnControl,
+          model: ForeignKeyColumnModel,
+          disabled: function(m) {
+            // If we are in table edit mode then
+            if (_.has(m, 'handler') && !_.isUndefined(m.handler)) {
+                // If OID is undefined then user is trying to add
+                // new constraint which should allowed for Unique
+                return !_.isUndefined(m.get('oid'));
+            }
+            // We can't update columns of existing foreign key.
+            return !m.isNew();
+            }
+        },{
+          id: 'confupdtype', label:'{{ _('On update') }}',
+          type:"select2", group: '{{ _('Action') }}', mode: ['edit','create'],
+          select2:{width:"50%", allowClear: false},
+          options: [
+            {label: "NO ACTION", value: "a"},
+            {label: "RESTRICT", value: "r"},
+            {label: "CASCADE", value: "c"},
+            {label: "SET NULL", value: "n"},
+            {label: "SET DEFAULT", value: "d"}
+          ],disabled: function(m) {
+            // If we are in table edit mode then
+            if (_.has(m, 'handler') && !_.isUndefined(m.handler)) {
+                // If OID is undefined then user is trying to add
+                // new constraint which should allowed for Unique
+                return !_.isUndefined(m.get('oid'));
+            }
+            // We can't update confupdtype of existing foreign key.
+            return !m.isNew();
+          }
+        },{
+          id: 'confdeltype', label:'{{ _('On delete') }}',
+          type:"select2", group: '{{ _('Action') }}', mode: ['edit','create'],
+          select2:{width:"50%", allowClear: false},
+          options: [
+            {label: "NO ACTION", value: "a"},
+            {label: "RESTRICT", value: "r"},
+            {label: "CASCADE", value: "c"},
+            {label: "SET NULL", value: "n"},
+            {label: "SET DEFAULT", value: "d"}
+          ],disabled: function(m) {
+            // If we are in table edit mode then
+            if (_.has(m, 'handler') && !_.isUndefined(m.handler)) {
+                // If OID is undefined then user is trying to add
+                // new constraint which should allowed for Unique
+                return !_.isUndefined(m.get('oid'));
+            }
+            // We can't update confdeltype of existing foreign key.
+            return !m.isNew();
+          }
+        }
+        ],
+        validate: function() {
+          this.errorModel.clear();
+
+          var columns = this.get('columns');
+          if ((_.isUndefined(columns) || _.isNull(columns) || columns.length < 1)) {
+            var msg = '{{ _('Please specify columns for Foreign key.') }}';
+            this.errorModel.set('columns', msg);
+            return msg;
+          }
+
+          var coveringindex = this.get('coveringindex'),
+              autoindex = this.get('autoindex');
+          if (autoindex && (_.isUndefined(coveringindex) || _.isNull(coveringindex) ||
+            String(coveringindex).replace(/^\s+|\s+$/g, '') == '')) {
+            var msg = '{{ _('Please specify covering index name.') }}';
+            this.errorModel.set('coveringindex', msg);
+            return msg;
+          }
+
+          return null;
+        }
+      }),
+
+      canCreate: function(itemData, item, data) {
+          // If check is false then , we will allow create menu
+          if (data && data.check == false)
+            return true;
+
+          var t = pgBrowser.tree, i = item, d = itemData, parents = [];
+          // To iterate over tree to check parent node
+          while (i) {
+            // If it is schema then allow user to c reate table
+            if (_.indexOf(['schema'], d._type) > -1)
+              return true;
+            parents.push(d._type);
+            i = t.hasParent(i) ? t.parent(i) : null;
+            d = i ? t.itemData(i) : null;
+          }
+          // If node is under catalog then do not allow 'create' menu
+          if (_.indexOf(parents, 'catalog') > -1) {
+            return false;
+          } else {
+            return true;
+          }
+      }
+    });
+  }
+
+  return pgBrowser.Nodes['foreign_key'];
+});
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/__init__.py
new file mode 100644
index 0000000..471a71e
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/__init__.py
@@ -0,0 +1,878 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+"""Implements Primary key constraint Node"""
+
+import json
+from flask import render_template, make_response, request, jsonify
+from flask.ext.babel import gettext as _
+from pgadmin.utils.ajax import make_json_response, \
+    make_response as ajax_response, internal_server_error
+from pgadmin.browser.utils import PGChildNodeView
+from pgadmin.utils.ajax import precondition_required
+from pgadmin.utils.driver import get_driver
+from config import PG_DEFAULT_DRIVER
+import pgadmin.browser.server_groups.servers.databases as database
+from functools import wraps
+from pgadmin.browser.server_groups.servers.databases.schemas.tables.constraints.type \
+    import ConstraintRegistry, ConstraintTypeModule
+
+
+class IndexConstraintModule(ConstraintTypeModule):
+    """
+    class IndexConstraintModule(CollectionNodeModule)
+
+        A module class for Primary key constraint node derived from ConstraintTypeModule.
+
+    Methods:
+    -------
+    * __init__(*args, **kwargs)
+      - Method is used to initialize the PrimaryKeyConstraintModule and it's base module.
+
+    * get_nodes(gid, sid, did)
+      - Method is used to generate the browser collection node.
+
+    * node_inode()
+      - Method is overridden from its base class to make the node as leaf node.
+
+    * script_load()
+      - Load the module script for language, when any of the database node is
+        initialized.
+    """
+
+    NODE_TYPE = 'Index constraint'
+    COLLECTION_LABEL = _('index_constraint')
+
+    def __init__(self, *args, **kwargs):
+        """
+        Method is used to initialize the PrimaryKeyConstraintModule and it's base module.
+
+        Args:
+          *args:
+          **kwargs:
+
+        Returns:
+
+        """
+        self.min_ver = None
+        self.max_ver = None
+        super(IndexConstraintModule, self).__init__(*args, **kwargs)
+
+    def get_nodes(self, gid, sid, did, scid, tid):
+        """
+        Generate the collection node
+        """
+        pass
+
+    @property
+    def node_inode(self):
+        """
+        Override this property to make the node a leaf node.
+
+        Returns: False as this is the leaf node
+        """
+        return False
+
+    @property
+    def script_load(self):
+        """
+        Load the module script for primary_key, when any of the table node is
+        initialized.
+
+        Returns: node type of the server module.
+        """
+        return database.DatabaseModule.NODE_TYPE
+
+
+class PrimaryKeyConstraintModule(IndexConstraintModule):
+    """
+     class PrimaryKeyConstraintModule(IndexConstraintModule)
+
+        A module class for the catalog schema node derived from IndexConstraintModule.
+    """
+
+    NODE_TYPE = 'primary_key'
+    COLLECTION_LABEL = _("Primary key")
+
+
+primary_key_blueprint = PrimaryKeyConstraintModule(__name__)
+
+
+class UniqueConstraintModule(IndexConstraintModule):
+    """
+     class UniqueConstraintModule(IndexConstraintModule)
+
+        A module class for the catalog schema node derived from IndexConstraintModule.
+    """
+
+    NODE_TYPE = 'unique_constraint'
+    COLLECTION_LABEL = _("Unique constraint")
+
+
+unique_constraint_blueprint = UniqueConstraintModule(__name__)
+
+
+class IndexConstraintView(PGChildNodeView):
+    """
+    class PrimaryKeyConstraintView(PGChildNodeView)
+
+        A view class for Primary key constraint node derived from PGChildNodeView. This class is
+        responsible for all the stuff related to view like creating, updating Primary key constraint
+        node, showing properties, showing sql in sql pane.
+
+    Methods:
+    -------
+    * __init__(**kwargs)
+      - Method is used to initialize the PrimaryKeyConstraintView and it's base view.
+
+    * module_js()
+      - This property defines (if javascript) exists for this node.
+        Override this property for your own logic
+
+    * check_precondition()
+      - This function will behave as a decorator which will checks
+        database connection before running view, it will also attaches
+        manager,conn & template_path properties to self
+
+    * list()
+      - This function returns primary key constraint nodes within that
+        collection as http response.
+
+    * get_list()
+      - This function is used to list all the language nodes within that collection
+        and return list of primary key constraint nodes.
+
+    * nodes()
+      - This function returns child node within that collection.
+        Here return all primary key constraint node as http response.
+
+    * get_nodes()
+      - returns all primary key constraint nodes' list.
+
+    * properties()
+      - This function will show the properties of the selected primary key.
+
+    * update()
+      - This function will update the data for the selected primary key.
+
+    * msql()
+      - This function is used to return modified SQL for the selected primary key.
+
+    * get_sql()
+      - This function will generate sql from model data.
+
+    * sql():
+      - This function will generate sql to show it in sql pane for the selected primary key.
+
+    * get_indices():
+        - This function returns indices for current table.
+
+    """
+
+    node_type = 'index_constraint'
+
+    node_label = _('Index constraint')
+
+    parent_ids = [
+            {'type': 'int', 'id': 'gid'},
+            {'type': 'int', 'id': 'sid'},
+            {'type': 'int', 'id': 'did'},
+            {'type': 'int', 'id': 'scid'},
+            {'type': 'int', 'id': 'tid'}
+            ]
+    ids = [{'type': 'int', 'id': 'cid'}
+            ]
+
+    operations = dict({
+        'obj': [
+            {'get': 'properties', 'delete': 'delete', 'put': 'update'},
+            {'get': 'list', 'post': 'create'}
+        ],
+        'delete': [{'delete': 'delete'}],
+        'children': [{'get': 'children'}],
+        'nodes': [{'get': 'node'}, {'get': 'nodes'}],
+        'sql': [{'get': 'sql'}],
+        'msql': [{'get': 'msql'}, {'get': 'msql'}],
+        'stats': [{'get': 'statistics'}],
+        'dependency': [{'get': 'dependencies'}],
+        'dependent': [{'get': 'dependents'}],
+        'module.js': [{}, {}, {'get': 'module_js'}]
+    })
+
+    def module_js(self):
+        """
+        This property defines (if javascript) exists for this node.
+        Override this property for your own logic.
+        """
+        return make_response(
+                render_template(
+                    "index_constraint/js/index_constraint.js",
+                    _=_,
+                    node_type=self.node_type,
+                    node_label=self.node_label
+                    ),
+                200, {'Content-Type': 'application/x-javascript'}
+                )
+
+    def check_precondition(f):
+        """
+        This function will behave as a decorator which will checks
+        database connection before running view, it will also attaches
+        manager,conn & template_path properties to self
+        """
+        @wraps(f)
+        def wrap(*args, **kwargs):
+            # Here args[0] will hold self & kwargs will hold gid,sid,did
+            self = args[0]
+            self.manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(
+                kwargs['sid']
+                )
+            self.conn = self.manager.connection(did=kwargs['did'])
+
+            # If DB not connected then return error to browser
+            if not self.conn.connected():
+                return precondition_required(
+                    _(
+                            "Connection to the server has been lost!"
+                    )
+                )
+
+            self.template_path = 'index_constraint/sql'
+            # We need parent's name eg table name and schema name
+            SQL = render_template("/".join([self.template_path,
+                                            'get_parent.sql']),
+                                  tid=kwargs['tid'])
+            status, rset = self.conn.execute_2darray(SQL)
+            if not status:
+                return internal_server_error(errormsg=rset)
+
+            for row in rset['rows']:
+                self.schema = row['schema']
+                self.table = row['table']
+            return f(*args, **kwargs)
+
+        return wrap
+
+    def end_transaction(self):
+        SQL = render_template(
+                "/".join([self.template_path, 'end.sql']))
+        # End transaction if any.
+        self.conn.execute_scalar(SQL)
+
+    @check_precondition
+    def properties(self, gid, sid, did, scid, tid, cid=None):
+        """
+        This function is used to list all the primary key
+        nodes within that collection.
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          cid: Primary key constraint ID
+
+        Returns:
+
+        """
+        sql = render_template("/".join([self.template_path, 'properties.sql']),
+                              tid=tid,
+                              cid=cid,
+                              constraint_type= self.constraint_type)
+        status, res = self.conn.execute_dict(sql)
+
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        result = res['rows'][0]
+
+        sql = render_template(
+            "/".join([self.template_path, 'get_constraint_cols.sql']),
+            cid=cid,
+            colcnt=result['indnatts'])
+        status, res = self.conn.execute_dict(sql)
+
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        columns = []
+        for row in res['rows']:
+            columns.append({"column":   row['column'].strip('"')})
+
+        result['columns'] = columns
+
+        return ajax_response(
+                response=result,
+                status=200
+                )
+
+    @check_precondition
+    def list(self, gid, sid, did, scid, tid, cid=None):
+        """
+        This function returns all primary keys
+        nodes within that collection as a http response.
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          cid: Primary key constraint ID
+
+        Returns:
+
+        """
+        try:
+            res = self.get_node_list(gid, sid, did, scid, tid, cid)
+            return ajax_response(
+                    response=res,
+                    status=200
+                    )
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def get_node_list(self, gid, sid, did, scid, tid, cid=None):
+        """
+        This function returns all primary keys
+        nodes within that collection as a list.
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          cid: Primary key constraint ID
+
+        Returns:
+
+        """
+        SQL = render_template("/".join([self.template_path, 'properties.sql']),
+                              tid=tid,
+                              constraint_type= self.constraint_type)
+        status, res = self.conn.execute_dict(SQL)
+
+        return res['rows']
+
+    @check_precondition
+    def nodes(self, gid, sid, did, scid, tid, cid=None):
+        """
+        This function returns all event trigger nodes as a
+        http response.
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          cid: Primary key constraint ID
+
+        Returns:
+
+        """
+        try:
+            res = self.get_nodes(gid, sid, did, scid, tid, cid)
+            return make_json_response(
+                    data=res,
+                    status=200
+                    )
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def get_nodes(self, gid, sid, did, scid, tid, cid=None):
+        """
+        This function returns all event trigger nodes as a list.
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          cid: Primary key constraint ID
+
+        Returns:
+
+        """
+        res = []
+        SQL = render_template("/".join([self.template_path, 'nodes.sql']),
+                              tid=tid,
+                              constraint_type=self.constraint_type)
+        status, rset = self.conn.execute_2darray(SQL)
+
+        for row in rset['rows']:
+            res.append(
+                    self.blueprint.generate_browser_node(
+                        row['oid'],
+                        tid,
+                        row['name'],
+                        icon="icon-%s" % self.node_type
+                    ))
+        return res
+
+    @check_precondition
+    def create(self, gid, sid, did, scid, tid, cid=None):
+        """
+        This function will create a primary key.
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          cid: Primary key constraint ID
+
+        Returns:
+
+        """
+        required_args = [
+            [u'columns', u'index']    # Either of one should be there.
+        ]
+
+        data = request.form if request.form else json.loads(request.data.decode())
+
+        for k, v in data.items():
+            try:
+                data[k] = json.loads(v)
+            except (ValueError, TypeError):
+                data[k] = v
+
+        for arg in required_args:
+            if isinstance(arg, list):
+                for param in arg:
+                    if (param in data and
+                            (not isinstance(data[param], list) or
+                                (isinstance(data[param], list) and
+                                    len(data[param]) > 0))):
+                        break
+                else:
+                    return make_json_response(
+                      status=400,
+                      success=0,
+                      errormsg=_(
+                          "Couldn't find at least one required parameter (%s)." % str(param)
+                      )
+                    )
+
+            elif arg not in data:
+                return make_json_response(
+                    status=400,
+                    success=0,
+                    errormsg=_(
+                        "Couldn't find the required parameter (%s)." % arg
+                    )
+                )
+
+        data['schema'] = self.schema
+        data['table'] = self.table
+        try:
+            if 'name' not in data or data['name'] == "":
+                SQL = render_template(
+                    "/".join([self.template_path, 'begin.sql']))
+                # Start transaction.
+                status, res = self.conn.execute_scalar(SQL)
+                if not status:
+                    self.end_transaction()
+                    return internal_server_error(errormsg=res)
+
+            # The below SQL will execute CREATE DDL only
+            SQL = render_template(
+                "/".join([self.template_path, 'create.sql']),
+                data=data, conn=self.conn,
+                constraint_name=self.constraint_name
+                )
+
+            status, msg = self.conn.execute_scalar(SQL)
+            if not status:
+                self.end_transaction()
+                return internal_server_error(errormsg=msg)
+
+            if 'name' not in data or data['name'] == "":
+                sql = render_template(
+                    "/".join([self.template_path,
+                              'get_oid_with_transaction.sql'],
+                             ),
+                    constraint_type=self.constraint_type,
+                    tid=tid)
+
+                status, res = self.conn.execute_dict(sql)
+                if not status:
+                    self.end_transaction()
+                    return internal_server_error(errormsg=res)
+
+                self.end_transaction()
+
+                data['name'] = res['rows'][0]['name']
+
+            else:
+                sql = render_template("/".join([self.template_path, 'get_oid.sql']),
+                                      tid=tid,
+                                      constraint_type=self.constraint_type,
+                                      name=data['name'])
+                status, res = self.conn.execute_dict(sql)
+                if not status:
+                    self.end_transaction()
+                    return internal_server_error(errormsg=res)
+
+            sql = render_template("/".join([self.template_path, 'alter.sql']),
+                                  data=data,
+                                  conn=self.conn)
+            sql = sql.strip('\n').strip(' ')
+
+            if sql != '':
+                status, result = self.conn.execute_scalar(sql)
+                if not status:
+                    self.end_transaction()
+                    return internal_server_error(errormsg=result)
+
+            return jsonify(
+                node=self.blueprint.generate_browser_node(
+                    res['rows'][0]['oid'],
+                    tid,
+                    data['name'],
+                    icon="icon-%s" % self.node_type
+                    )
+                )
+
+        except Exception as e:
+            self.end_transaction()
+            return make_json_response(
+                status=400,
+                success=0,
+                errormsg=e
+            )
+
+    @check_precondition
+    def update(self, gid, sid, did, scid, tid, cid=None):
+        """
+        This function will update the data for the selected
+        primary key.
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          cid: Primary key constraint ID
+
+        Returns:
+
+        """
+        data = request.form if request.form else json.loads(request.data.decode())
+
+        try:
+            data['schema'] = self.schema
+            data['table'] = self.table
+            sql = self.get_sql(data, tid, cid)
+            sql = sql.strip('\n').strip(' ')
+            if sql != "":
+                status, res = self.conn.execute_scalar(sql)
+                if not status:
+                    return internal_server_error(errormsg=res)
+
+                sql = render_template("/".join([self.template_path, 'get_oid.sql']),
+                                      tid=tid,
+                                      constraint_type=self.constraint_type,
+                                      name=data['name'])
+                status, res = self.conn.execute_dict(sql)
+                if not status:
+                    return internal_server_error(errormsg=res)
+
+                return make_json_response(
+                    success=1,
+                    info="Constraint updated",
+                    data={
+                        'id': cid,
+                        'tid': tid,
+                        'scid': scid,
+                        'sid': sid,
+                        'gid': gid,
+                        'did': did
+                    }
+                )
+            else:
+                return make_json_response(
+                    success=1,
+                    info="Nothing to update",
+                    data={
+                        'id': cid,
+                        'tid': tid,
+                        'scid': scid,
+                        'sid': sid,
+                        'gid': gid,
+                        'did': did
+                    }
+                )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def delete(self, gid, sid, did, scid, tid, cid=None):
+        """
+        This function will delete an existing primary key.
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          cid: Primary key constraint ID
+
+        Returns:
+
+        """
+        # Below code will decide if it's simple drop or drop with cascade call
+        if self.cmd == 'delete':
+            # This is a cascade operation
+            cascade = True
+        else:
+            cascade = False
+        try:
+            sql = render_template("/".join([self.template_path, 'get_name.sql']),
+                                  tid=tid,
+                                  constraint_type = self.constraint_type,
+                                  cid=cid)
+            status, res = self.conn.execute_dict(sql)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            data = res['rows'][0]
+            data['schema'] = self.schema
+            data['table'] = self.table
+
+            sql = render_template("/".join([self.template_path, 'delete.sql']),
+                                  data=data,
+                                  cascade=cascade)
+            status, res = self.conn.execute_scalar(sql)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            return make_json_response(
+                success=1,
+                info=_("{0} dropped.".format(self.node_label)),
+                data={
+                    'id': cid,
+                    'sid': sid,
+                    'gid': gid,
+                    'did': did
+                }
+            )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def msql(self, gid, sid, did, scid, tid, cid=None):
+        """
+        This function returns modified SQL for the selected
+        primary key.
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          cid: Primary key constraint ID
+
+        Returns:
+
+        """
+        data = {}
+        for k, v in request.args.items():
+            try:
+                data[k] = json.loads(v)
+            except ValueError:
+                data[k] = v
+
+        data['schema'] = self.schema
+        data['table'] = self.table
+        try:
+            sql = self.get_sql(data, tid, cid)
+            sql = sql.strip('\n').strip(' ')
+
+            return make_json_response(
+                    data=sql,
+                    status=200
+                    )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    def get_sql(self, data, tid, cid=None):
+        """
+        This function will generate sql from model data.
+
+        Args:
+          data: Contains the data of the selected primary key constraint.
+          tid: Table ID.
+          cid: Primary key constraint ID
+
+        Returns:
+
+        """
+        if cid is not None:
+            sql = render_template("/".join([self.template_path, 'properties.sql']),
+                                  tid=tid,
+                                  cid=cid,
+                                  constraint_type= self.constraint_type)
+            status, res = self.conn.execute_dict(sql)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            old_data = res['rows'][0]
+            required_args = [u'name']
+            for arg in required_args:
+                if arg not in data:
+                    data[arg] = old_data[arg]
+
+            sql = render_template("/".join([self.template_path, 'update.sql']),
+                                  data=data,
+                                  o_data=old_data)
+        else:
+            required_args = [
+                [u'columns', u'index']    # Either of one should be there.
+            ]
+
+            for arg in required_args:
+                if isinstance(arg, list):
+                    for param in arg:
+                        if (param in data and
+                                ((isinstance(data[param], str) and
+                                    data[param] != "") or
+                                    (isinstance(data[param], list) and
+                                        len(data[param]) > 0))):
+                            break
+                    else:
+                        return _('-- definition incomplete')
+
+                elif arg not in data:
+                    return _('-- definition incomplete')
+
+            sql = render_template("/".join([self.template_path, 'create.sql']),
+                                  data=data,
+                                  conn=self.conn,
+                                  constraint_name=self.constraint_name)
+            sql += "\n"
+            sql += render_template("/".join([self.template_path, 'alter.sql']),
+                                   data=data,
+                                   conn=self.conn)
+
+        return sql
+
+    @check_precondition
+    def sql(self, gid, sid, did, scid, tid, cid=None):
+        """
+        This function generates sql to show in the sql pane for the selected
+        primary key.
+
+        Args:
+          gid: Server Group ID
+          sid: Server ID
+          did: Database ID
+          scid: Schema ID
+          tid: Table ID
+          cid: Primary key constraint ID
+
+        Returns:
+
+        """
+        try:
+            SQL = render_template(
+                "/".join([self.template_path, 'properties.sql']),
+                tid=tid,
+                conn=self.conn,
+                cid=cid,
+                constraint_type=self.constraint_type)
+            status, res = self.conn.execute_dict(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            data = res['rows'][0]
+            data['schema'] = self.schema
+            data['table'] = self.table
+
+            sql = render_template(
+                "/".join([self.template_path, 'get_constraint_cols.sql']),
+                cid=cid, colcnt=data['indnatts'])
+
+            status, res = self.conn.execute_dict(sql)
+
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            columns = []
+            for row in res['rows']:
+                columns.append({"column":   row['column'].strip('"')})
+
+            data['columns'] = columns
+
+            SQL = render_template(
+                "/".join([self.template_path, 'create.sql']),
+                data=data,
+                constraint_name=self.constraint_name)
+            SQL += "\n"
+            SQL += render_template(
+                "/".join([self.template_path, 'alter.sql']),
+                data=data, conn=self.conn)
+
+            sql_header = "-- Constraint: {0}\n\n-- ".format(data['name'])
+
+            sql_header += render_template(
+                    "/".join([self.template_path, 'delete.sql']),
+                    data=data)
+            sql_header += "\n"
+
+            SQL = sql_header + SQL
+
+            return ajax_response(response=SQL)
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+
+class PrimaryKeyConstraintView(IndexConstraintView):
+    node_type = 'primary_key'
+
+    node_label = _('Primary key')
+
+    constraint_name = "PRIMARY KEY"
+
+    constraint_type = "p"
+
+
+class UniqueConstraintView(IndexConstraintView):
+    node_type = 'unique_constraint'
+
+    node_label = _('Unique constraint')
+
+    constraint_name = "UNIQUE"
+
+    constraint_type = "u"
+
+
+primary_key_constraint = ConstraintRegistry(
+    'primary_key', PrimaryKeyConstraintModule, PrimaryKeyConstraintView
+    )
+
+unique_constraint = ConstraintRegistry(
+    'unique_constraint', UniqueConstraintModule, UniqueConstraintView
+    )
+
+PrimaryKeyConstraintView.register_node_view(primary_key_blueprint)
+UniqueConstraintView.register_node_view(unique_constraint_blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/static/img/primary_key.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/static/img/primary_key.png
new file mode 100644
index 0000000000000000000000000000000000000000..b57f59778554c3b0ee1b872a4174cbe631ee64e2
GIT binary patch
literal 443
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbMf<N%)#S0Mf1eD~=McE?xh-aAwO
z?)k2F&$r(_Q+<4;&bQAOzI-_L>D`Vm@3!4NRdR5F#O>qdUq7Aw{C>xWm$N>;n)Uh3
z;xBI(e|bIY^Q(!UUNnAw(e(Yp+IP=)e*Jjj^V^Ldo=^DrV#4P)3vM4z`1*Fitz!|N
zUo?Mt)qC$u?bnY-Kfl}j@%4gFujk!8nS1w4)!Qd4-ac7$_f*mGm0D_V?`Q*^#aI&L
z7tG-B>_!@p!&%@FSq!8-z}W3%wjGcW@9E+gB5^r6VF6b{N>Y-`Gvm!0Hf=0cIJvo?
zsPOZLPmT=s%*?{88RjpTu%Tncj2$gYMC1b;qT2k!{Nfw~JtJL3mox?X#ySUk&+eD!
zaI9ft<CBfGtz|aJUirArf`Q@2TGkzB-UgQgtx_#<jVMV;EJ?LWE=mPb3`Pcq2D*ku
zx(0?JMg~?U##Sb#+6Jap1_txq>8(Q1kei>9nN|tWU|<Q>090*aWnc!;aB6z!8lVOS
MPgg&ebxsLQ07e(akpKVy

literal 0
HcmV?d00001

diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/static/img/unique_constraint.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/static/img/unique_constraint.png
new file mode 100644
index 0000000000000000000000000000000000000000..e82857235ed1d5bb351b981c447ec3370d495fa9
GIT binary patch
literal 422
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbK}V}MVHE0AtpdP65|Z{ONGc?&PK
z9lkT?%wyl?6GdCEg|9qcv+MTqD^L55-OJi^HFW8P+MRbYmt2Wha=CWfUF*U_tvl~U
zF1%W|<$g;4`J&}FqUK+(-}In$+k@yiHybuQDqDIhZuaelb&vDr-HMxer)=5dRj1!9
zI{IqDj_1wmp7v~dv0(q3HOJoP31mnB9l=-<<QL4~@a#q!ki%Kv5m^kRJ;2!QWVRiU
z5##CN7$R}Gx6hRCKmd<(eQa7<+K&H>+NGIBA*;;oEjPCQ(Bz!3V!CK3^T!Lkmz5Z{
zJ+895(X7z(qO)VNNwR|esV?<b%bs?wlaJ6nmU+y3!<yT5bHqK~Dx3X_HeV^s{Hn_4
zgbmOh)e_f;l9a@fRIB8oR3OD*WMF8ZYiOivU>IU#U}a)#Wn!vrU}|MxFz=n-DijU5
n`6-!cl@JXEmS7D))h1R3W)KahriZQpYGCkm^>bP0l+XkKGQ6yC

literal 0
HcmV?d00001

diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/js/index_constraint.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/js/index_constraint.js
new file mode 100644
index 0000000..b19d90f
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/js/index_constraint.js
@@ -0,0 +1,536 @@
+define(
+        ['jquery', 'underscore', 'underscore.string', 'pgadmin',
+        'pgadmin.browser', 'alertify', 'pgadmin.browser.collection'],
+function($, _, S, pgAdmin, pgBrowser, alertify) {
+
+  // Extend the browser's node class for index constraint node
+  if (!pgBrowser.Nodes['{{node_type}}']) {
+    pgAdmin.Browser.Nodes['{{node_type}}'] = pgBrowser.Node.extend({
+      type: '{{node_type}}',
+      label: '{{ node_label }}',
+      collection_type: 'coll-constraints',
+      sqlAlterHelp: 'ddl-alter.html',
+      sqlCreateHelp: 'ddl-constraints.html',
+      hasSQL: true,
+      hasDepends: false,
+      parent_type: 'table',
+      canDrop: true,
+      canDropCascade: true,
+      Init: function() {
+        /* Avoid multiple registration of menus */
+        if (this.initialized)
+            return;
+
+        this.initialized = true;
+
+        pgBrowser.add_menus([{
+          name: 'create_{{node_type}}_on_coll', node: 'coll-constraints', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ node_label }}',
+          icon: 'wcTabIcon icon-{{node_type}}', data: {action: 'create', check: true},
+          enable: 'canCreate'
+
+        }
+        ]);
+      },
+      canCreate: function(itemData, item, data) {
+        // If check is false then , we will allow create menu
+        if (data && data.check == false)
+          return true;
+
+        var t = pgBrowser.tree, i = item, d = itemData, parents = [];
+        // To iterate over tree to check parent node
+        while (i) {
+          // If it is schema then allow user to c reate table
+          if (_.indexOf(['schema'], d._type) > -1) {
+            {% if node_type == 'primary_key' %}
+            // There should be only one primary key per table.
+            var children = t.children(arguments[1], false),
+              primary_key_found = false;
+
+            _.each(children, function(child){
+              data = pgBrowser.tree.itemData($(child));
+              if (!primary_key_found && data._type == "primary_key") {
+                primary_key_found = true;
+              }
+            });
+            return !primary_key_found;
+            {% else %}
+            return true;
+            {% endif %}
+          }
+          parents.push(d._type);
+          i = t.hasParent(i) ? t.parent(i) : null;
+          d = i ? t.itemData(i) : null;
+        }
+        // If node is under catalog then do not allow 'create' menu
+        if (_.indexOf(parents, 'catalog') > -1) {
+          return false;
+        } else {
+            return true;
+        }
+      },
+
+      // Define the model for index constraint node
+      model: pgAdmin.Browser.Node.Model.extend({
+        defaults: {
+          name: undefined,
+          oid: undefined,
+          comment: undefined,
+          spcname: "pg_default",
+          index: undefined,
+          fillfactor: undefined,
+          condeferrable: undefined,
+          condeferred: undefined,
+          columns: []
+        },
+
+        // Define the schema for the index constraint node
+        schema: [{
+          id: 'name', label: '{{ _('Name') }}', type: 'text',
+          mode: ['properties', 'create', 'edit'], editable:true,
+          cellHeaderClasses:'width_percent_40',
+        },{
+          id: 'oid', label:'{{ _('OID') }}', cell: 'string',
+          type: 'text' , mode: ['properties'], editable: false,
+          cellHeaderClasses:'width_percent_20',
+        },{
+          id: 'comment', label:'{{ _('Comment') }}', cell: 'string',
+          type: 'multiline', mode: ['properties', 'create', 'edit'],
+          deps:['name'], disabled:function(m) {
+            var name = m.get('name');
+            if (!(name && name != '')) {
+              setTimeout(function(){
+                m.set('comment', null);
+              },10);
+              return true;
+            } else {
+              return false;
+            }
+          }
+        },{
+          id: 'columns', label: '{{ _('Columns') }}',
+          type: 'collection', group: '{{ _('Definition') }}',
+          editable: false,
+          cell: Backgrid.StringCell.extend({
+            initialize: function() {
+              Backgrid.StringCell.prototype.initialize.apply(this, arguments);
+
+              var self = this,
+                collection = this.model.get('columns');
+
+               // Do not listen for any event(s) for existing constraint.
+              if (_.isUndefined(self.model.get('oid'))) {
+                var tableCols = self.model.top.get('columns');
+                  self.listenTo(tableCols, 'remove' , self.removeColumn);
+                  self.listenTo(tableCols, 'change:name', self.resetColOptions);
+              }
+
+              collection.on('pgadmin:multicolumn:updated', function() {
+                self.render.apply(self);
+              });
+              self.listenTo(collection, "add", self.render);
+              self.listenTo(collection, "remove", self.render);
+            },
+            removeColumn: function(m) {
+              var self = this,
+                  removedCols = self.model.get('columns').where(
+                    {column: m.get('name')}
+                    );
+
+              self.model.get('columns').remove(removedCols);
+              setTimeout(function () {
+                self.render();
+              }, 10);
+
+              {% if node_type == 'primary_key' %}
+                var key = 'primary_key'
+              {% else %}
+                var key = 'unique_constraint'
+              {% endif %}
+
+              setTimeout(function () {
+                constraints = self.model.top.get(key);
+                var removed = [];
+                constraints.each(function(constraint) {
+                  if (constraint.get("columns").length == 0) {
+                     removed.push(constraint);
+                  }
+                });
+                constraints.remove(removed);
+              },100);
+
+            },
+            resetColOptions : function(m) {
+              var self = this,
+                updatedCols = self.model.get('columns').where(
+                {column: m.previous('name')}
+                );
+              if (updatedCols.length > 0) {
+                /*
+                 * Table column name has changed so update
+                 * column name in primary key as well.
+                 */
+                updatedCols[0].set(
+                {"column": m.get('name')},
+                {silent: true});
+              }
+
+              setTimeout(function () {
+                self.render();
+              }, 10);
+            },
+            formatter: {
+              fromRaw: function (rawValue, model) {
+                return rawValue.pluck("column").toString();
+              },
+              toRaw: function (val, model) {
+                return val;
+              }
+            },
+            render: function() {
+              return Backgrid.StringCell.prototype.render.apply(this, arguments);
+            },
+            remove: function() {
+              var tableCols = this.model.top.get('columns'),
+              primary_key_col = this.model.get('columns');
+
+              if (primary_key_col) {
+                primary_key_col.off('pgadmin:multicolumn:updated');
+              }
+
+              this.stopListening(tableCols, 'remove' , self.removeColumn);
+              this.stopListening(tableCols, 'change:name' , self.resetColOptions);
+
+              Backgrid.StringCell.prototype.remove.apply(this, arguments);
+            }
+          }),
+          canDelete: true, canAdd: true,
+          control: Backform.MultiSelectAjaxControl.extend({
+            formatter: {
+              fromRaw: function (rawData, model) {
+                var res = _.isObject(rawData) ?
+                      rawData : JSON.parse(rawData);
+
+                return _.pluck(res, 'column');
+              },
+              toRaw: function (formattedData, model) {
+                return formattedData;
+              }
+            },
+            defaults: _.extend(
+              {},
+              Backform.NodeListByNameControl.prototype.defaults,
+              {
+                select2: {
+                  multiple: true,
+                  allowClear: true,
+                  width: 'style',
+                  placeholder: '{{ _('Select the column(s)') }}',
+                }
+              }
+            ),
+            initialize: function() {
+            // Here we will decide if we need to call URL
+            // Or fetch the data from parent columns collection
+              var self = this;
+              if(this.model.handler) {
+                Backform.Select2Control.prototype.initialize.apply(this, arguments);
+                // Do not listen for any event(s) for existing constraint.
+                if (_.isUndefined(self.model.get('oid'))) {
+                  var tableCols = self.model.top.get('columns');
+                  self.listenTo(tableCols, 'remove' , self.resetColOptions);
+                  self.listenTo(tableCols, 'change:name', self.resetColOptions);
+                }
+
+                self.custom_options();
+              } else {
+                Backform.MultiSelectAjaxControl.prototype.initialize.apply(this, arguments);
+              }
+              self.model.get('columns').on('pgadmin:multicolumn:updated', function() {
+                  self.render.apply(self);
+                });
+            },
+            resetColOptions: function(m) {
+              var self = this;
+
+              setTimeout(function () {
+                self.custom_options();
+                self.render.apply(self);
+              }, 50);
+
+            },
+            custom_options: function() {
+              // We will add all the columns entered by user in table model
+              var columns = this.model.top.get('columns'),
+                added_columns_from_tables = [];
+
+              if (columns.length > 0) {
+                _.each(columns.models, function(m) {
+                    var col = m.get('name');
+                    if(!_.isUndefined(col) && !_.isNull(col)) {
+                      added_columns_from_tables.push(
+                        {label: col, value: col, image:'icon-column'}
+                      );
+                    }
+                });
+              }
+              // Set the values in to options so that user can select
+              this.field.set('options', added_columns_from_tables);
+            },
+            onChange: function(e) {
+              var self = this,
+                  model = this.model,
+                  $el = $(e.target),
+                  attrArr = this.field.get("name").split('.'),
+                  name = attrArr.shift(),
+                  path = attrArr.join('.'),
+                  vals = this.getValueFromDOM(),
+                  collection = model.get(name),
+                  removed = [];
+
+              this.stopListening(this.model, "change:" + name, this.render);
+
+              /*
+               * Iterate through all the values, and find out how many are already
+               * present in the collection.
+               */
+              collection.each(function(m) {
+                  var column = m.get('column'),
+                      idx = _.indexOf(vals, column);
+
+                  if (idx > -1) {
+                    vals.splice(idx, 1);
+                  } else {
+                    removed.push(column);
+                  }
+               });
+
+              /*
+               * Adding new values
+               */
+
+              _.each(vals, function(v) {
+                var m = new (self.field.get('model'))(
+                      {column: v}, { silent: true,
+                      top: self.model.top,
+                      collection: collection,
+                      handler: collection
+                    });
+
+                collection.add(m);
+              });
+
+              /*
+               * Removing unwanted!
+               */
+              _.each(removed, function(v) {
+                collection.remove(collection.where({column: v}));
+              });
+
+              this.listenTo(this.model, "change:" + name, this.render);
+            },
+            remove: function() {
+              if(this.model.handler) {
+                var self = this,
+                tableCols = self.model.top.get('columns');
+                self.stopListening(tableCols, 'remove' , self.resetColOptions);
+                self.stopListening(tableCols, 'change:name' , self.resetColOptions);
+                self.model.get('columns').off('pgadmin:multicolumn:updated');
+
+                Backform.Select2Control.prototype.remove.apply(this, arguments);
+
+              } else {
+                Backform.MultiSelectAjaxControl.prototype.remove.apply(this, arguments);
+              }
+            }
+          }),
+          deps: ['index'], node: 'column',
+          model: pgBrowser.Node.Model.extend({
+            defaults: {
+              column: undefined
+            },
+            validate: function() {
+              return null;
+           }
+          }),
+          transform : function(data){
+            var res = [];
+            if (data && _.isArray(data)) {
+              _.each(data, function(d) {
+                res.push({label: d.label, value: d.label, image:'icon-column'});
+              })
+            }
+            return res;
+          },
+          select2:{allowClear:false},
+          disabled: function(m) {
+            // If we are in table edit mode then
+            if (_.has(m, 'top') && !_.isUndefined(m.top)
+                                    && !m.top.isNew()) {
+                // If OID is undefined then user is trying to add
+                // new constraint which should be allowed for Unique
+                return !_.isUndefined(m.get('oid'));
+            }
+
+            // We can't update columns of existing index constraint.
+            if (!m.isNew()) {
+                return true;
+            }
+            // Disable if index is selected.
+            var index = m.get('index');
+              if(_.isUndefined(index) || index == '') {
+                return false;
+              } else {
+                var col = m.get('columns');
+                col.reset();
+                return true;
+              }
+            }
+          },{
+          id: 'spcname', label: '{{ _('Tablespace') }}',
+          type: 'text', group: '{{ _('Definition') }}',
+          control: 'node-list-by-name', node: 'tablespace',
+          deps: ['index'],
+          select2:{allowClear:false},
+          filter: function(m) {
+            // Don't show pg_global tablespace in selection.
+            if (m.label == "pg_global") return false;
+            else return true;
+          },
+          disabled: function(m) {
+            // Disable if index is selected.
+            m = m.top || m;
+            var index = m.get('index');
+              if(_.isUndefined(index) || index == '') {
+                return false;
+              } else {
+                setTimeout(function(){
+                  m.set('spcname', '');
+                },10);
+                return true;
+              }
+          }
+        },{
+          id: 'index', label: '{{ _('Index') }}',
+          type: 'text', group: '{{ _('Definition') }}',
+          control: Backform.NodeListByNameControl.extend({
+          initialize:function() {
+            if (_.isUndefined(this.model.top)) {
+              Backform.NodeListByNameControl.prototype.initialize.apply(this,arguments);
+            } else {
+              Backform.Control.prototype.initialize.apply(this,arguments);
+            }
+          }
+          }),
+          select2:{allowClear:true}, node: 'index',
+          disabled: function(m) {
+            // If we are in table edit mode then disable it
+            if (_.has(m, 'top') && !_.isUndefined(m.top)
+                                    && !m.top.isNew()) {
+                return true;
+            }
+
+            // We can't update index of existing index constraint.
+            return !m.isNew();
+          },
+          // We will not show this field in Create Table mode
+          visible: function(m) {
+            return !_.isUndefined(m.top.node_info['table']);
+          }
+        },{
+          id: 'fillfactor', label: '{{ _('Fill factor') }}', deps: ['index'],
+          type: 'int', group: '{{ _('Definition') }}', allowNull: true,
+          disabled: function(m) {
+            // Disable if index is selected.
+            var index = m.get('index');
+              if(_.isUndefined(index) || index == '') {
+                return false;
+              } else {
+                setTimeout(function(){
+                  m.set('fillfactor', null);
+                },10);
+                return true;
+              }
+            }
+        },{
+          id: 'condeferrable', label: '{{ _('Deferrable') }}',
+          type: 'switch', group: '{{ _('Definition') }}', deps: ['index'],
+          disabled: function(m) {
+            // If we are in table edit mode then
+            if (_.has(m, 'top') && !_.isUndefined(m.top)
+                                    && !m.top.isNew()) {
+                // If OID is undefined then user is trying to add
+                // new constraint which should allowed for Unique
+                return !_.isUndefined(m.get('oid'));
+            }
+
+            // We can't update condeferrable of existing index constraint.
+            if (!m.isNew()) {
+                return true;
+            }
+            // Disable if index is selected.
+            var index = m.get('index');
+            if(_.isUndefined(index) || index == '') {
+              return false;
+            } else {
+              setTimeout(function(){
+                m.set('condeferrable', false);
+              },10);
+              return true;
+            }
+          }
+        },{
+          id: 'condeferred', label: '{{ _('Deferred') }}',
+          type: 'switch', group: '{{ _('Definition') }}',
+          deps: ['condeferrable'],
+          disabled: function(m) {
+            // If we are in table edit mode then
+            if (_.has(m, 'top') && !_.isUndefined(m.top)
+                                    && !m.top.isNew()) {
+                // If OID is undefined then user is trying to add
+                // new constraint which should allowed for Unique
+                return !_.isUndefined(m.get('oid'));
+            }
+
+            // We can't update condeferred of existing index constraint.
+            if (!m.isNew()) {
+              return true;
+            }
+            // Disable if condeferred is false or unselected.
+            if(m.get('condeferrable') == true) {
+              return false;
+            } else {
+              setTimeout(function(){
+                m.set('condeferred', false);
+              },10);
+              return true;
+            }
+          }
+        }
+        ],
+        validate: function() {
+          this.errorModel.clear();
+          // Clear parent's error as well
+          if (_.has(this, 'top')) {
+            this.top.errorModel.clear();
+          }
+
+          var columns = this.get('columns'),
+            index = this.get('index');
+
+            if ((_.isUndefined(index) || String(index).replace(/^\s+|\s+$/g, '') == '') &&
+                (_.isUndefined(columns) || _.isNull(columns) || columns.length < 1)) {
+              var msg = '{{ _('Please specify columns for ') }}' + '{{ node_label }}';
+              this.errorModel.set('columns', msg);
+              return msg;
+            }
+
+          return null;
+        }
+      })
+  });
+  }
+
+  return pgBrowser.Nodes['{{node_type}}'];
+});
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/static/img/coll-constraints.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/static/img/coll-constraints.png
new file mode 100644
index 0000000000000000000000000000000000000000..d62e13705c50e6c0cf8f19d680053e8643e28751
GIT binary patch
literal 314
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFv3GfMV1=2TrO847{Jl`|t`Qpas
zn<hS+l=rMY>RGPqvlydizRJ&>B`Om#V}R-yOM?7@862M7NCR>>3p^r=fwTu0yPeFo
z12TL)T^vI=t|uoPU||ZF<tgaHG*QsQ!?m&Tq=?3mCu}J#Dx3x@mM}}^iE=5NIWXnk
zkpnC4ai%a>@;Gg7=uums=9bIK=Egd~(us-3g@Iv02gfsK^JP^)gH=mhBT7;dOH!?p
zi&B9UgOP!ufv%yEu7P2Qk%5(ov6YF5wt=aYfq}(LRXG$5x%nxXX_XKS29{tAAk|g|
XW)KahriZQpYGCkm^>bP0l+XkKyyRU}

literal 0
HcmV?d00001

diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/templates/constraints/js/constraints.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/templates/constraints/js/constraints.js
new file mode 100644
index 0000000..c8144fd
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/templates/constraints/js/constraints.js
@@ -0,0 +1,54 @@
+define(
+  [
+  'jquery', 'underscore', 'underscore.string', 'pgadmin', 'pgadmin.browser',
+  'pgadmin.browser.collection'{% for c in constraints %}, 'pgadmin.node.{{ c|safe }}'{%endfor%}
+  ],
+function($, _, S, pgAdmin, pgBrowser) {
+
+  if (!pgBrowser.Nodes['coll-constraints']) {
+    var databases = pgAdmin.Browser.Nodes['coll-constraints'] =
+      pgAdmin.Browser.Collection.extend({
+        node: 'constraints',
+        label: '{{ _('Constraints') }}',
+        type: 'coll-constraints',
+        columns: ['name', 'comment']
+      });
+  };
+
+  if (!pgBrowser.Nodes['constraints']) {
+    pgAdmin.Browser.Nodes['constraints'] = pgBrowser.Node.extend({
+      type: 'constraints',
+      label: '{{ _('Constraints') }}',
+      collection_type: 'coll-constraints',
+      parent_type: ['table'],
+      Init: function() {
+        /* Avoid mulitple registration of menus */
+        if (this.initialized)
+            return;
+
+        this.initialized = true;
+
+        pgBrowser.add_menus([]);
+      },
+      model: pgAdmin.Browser.Node.Model.extend({
+        defaults: {
+          name: undefined,
+          oid: undefined,
+          comment: undefined
+       },
+        schema: [{
+          id: 'name', label: '{{ _('Name') }}', type: 'text',
+          mode: ['properties', 'create', 'edit']
+        },{
+          id: 'oid', label:'{{ _('Oid') }}', cell: 'string',
+          type: 'text' , mode: ['properties']
+        },{
+          id: 'comment', label:'{{ _('Comment') }}', cell: 'string',
+          type: 'multiline', mode: ['properties', 'create', 'edit']
+        }]
+      })
+  });
+  }
+
+  return pgBrowser.Nodes['constraints'];
+});
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/type.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/type.py
new file mode 100644
index 0000000..d75bf2b
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/type.py
@@ -0,0 +1,42 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+from pgadmin.browser.collection import CollectionNodeModule
+from flask import Blueprint
+
+
+class ConstraintRegistry(object):
+    """
+    ConstraintTypeRegistry
+
+    It is more of a registry for difference type of constraints for the tables.
+    Its job is to initialize to different type of constraint blueprint and
+    register it with its respective NodeView.
+    """
+    registry = dict()
+
+    def __init__(self, name, con_blueprint, con_nodeview):
+        if name not in ConstraintRegistry.registry:
+
+            blueprint = con_blueprint(name)
+
+            # TODO:: register the view with the blueprint
+            con_nodeview.register_node_view(blueprint)
+
+            ConstraintRegistry.registry[name] = {
+                'blueprint': blueprint,
+                'nodeview': con_nodeview
+            }
+
+
+class ConstraintTypeModule(CollectionNodeModule):
+    register = Blueprint.register
+
+    def __init__(self, *args, **kwargs):
+        super(ConstraintTypeModule, self).__init__(*args, **kwargs)
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
new file mode 100644
index 0000000..4573a97
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/__init__.py
@@ -0,0 +1,874 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+""" Implements Index Node """
+
+from flask import render_template, make_response, request, jsonify
+from flask.ext.babel import gettext
+from pgadmin.utils.ajax import make_json_response, \
+    make_response as ajax_response, internal_server_error
+from pgadmin.browser.utils import PGChildNodeView
+from pgadmin.browser.collection import CollectionNodeModule
+import pgadmin.browser.server_groups.servers.databases as database
+from pgadmin.utils.ajax import precondition_required
+from pgadmin.utils.driver import get_driver
+from config import PG_DEFAULT_DRIVER
+from pgadmin.browser.server_groups.servers.utils import parse_priv_from_db, \
+    parse_priv_to_db
+from functools import wraps
+import json
+
+
+class IndexesModule(CollectionNodeModule):
+    """
+     class IndexesModule(CollectionNodeModule)
+
+        A module class for Index node derived from CollectionNodeModule.
+
+    Methods:
+    -------
+    * __init__(*args, **kwargs)
+      - Method is used to initialize the Index and it's base module.
+
+    * get_nodes(gid, sid, did, scid, tid)
+      - Method is used to generate the browser collection node.
+
+    * node_inode()
+      - Method is overridden from its base class to make the node as leaf node.
+
+    * script_load()
+      - Load the module script for schema, when any of the server node is
+        initialized.
+    """
+
+    NODE_TYPE = 'index'
+    COLLECTION_LABEL = gettext("Indexes")
+
+    def __init__(self, *args, **kwargs):
+        """
+        Method is used to initialize the IndexModule and it's base module.
+
+        Args:
+            *args:
+            **kwargs:
+        """
+        self.min_ver = None
+        self.max_ver = None
+        super(IndexesModule, self).__init__(*args, **kwargs)
+
+    def BackendSupported(self, manager, **kwargs):
+        """
+        Load this module if vid is view, we will not load it under
+        material view
+        """
+        if super(IndexesModule, self).BackendSupported(manager, **kwargs):
+            conn = manager.connection(did=kwargs['did'])
+            # If DB is not connected then return error to browser
+            if not conn.connected():
+                return precondition_required(
+                    gettext(
+                            "Connection to the server has been lost!"
+                    )
+                )
+
+            if 'vid' not in kwargs:
+                return True
+
+            template_path = 'index/sql/9.1_plus'
+            SQL = render_template("/".join(
+                  [template_path, 'backend_support.sql']), vid=kwargs['vid'])
+            status, res = conn.execute_scalar(SQL)
+
+            # check if any errors
+            if not status:
+                return internal_server_error(errormsg=res)
+            # Check vid is view not material view
+            # then true, othewise false
+            return res
+
+    def get_nodes(self, gid, sid, did, scid, **kwargs):
+        """
+        Generate the collection node
+        """
+        assert('tid' in kwargs or 'vid' in kwargs)
+        yield self.generate_browser_collection_node(
+            kwargs['tid'] if 'tid' in kwargs else kwargs['vid']
+        )
+
+    @property
+    def script_load(self):
+        """
+        Load the module script for server, when any of the server-group node is
+        initialized.
+        """
+        return database.DatabaseModule.NODE_TYPE
+
+    @property
+    def node_inode(self):
+        """
+        Load the module node as a leaf node
+        """
+        return False
+
+blueprint = IndexesModule(__name__)
+
+
+class IndexesView(PGChildNodeView):
+    """
+    This class is responsible for generating routes for Index node
+
+    Methods:
+    -------
+    * __init__(**kwargs)
+      - Method is used to initialize the IndexView and it's base view.
+
+    * module_js()
+      - This property defines (if javascript) exists for this node.
+        Override this property for your own logic
+
+    * check_precondition()
+      - This function will behave as a decorator which will checks
+        database connection before running view, it will also attaches
+        manager,conn & template_path properties to self
+
+    * list()
+      - This function is used to list all the Index nodes within that
+      collection.
+
+    * nodes()
+      - This function will used to create all the child node within that
+        collection, Here it will create all the Index node.
+
+    * properties(gid, sid, did, scid, tid, idx)
+      - This function will show the properties of the selected Index node
+
+    * create(gid, sid, did, scid, tid)
+      - This function will create the new Index object
+
+    * update(gid, sid, did, scid, tid, idx)
+      - This function will update the data for the selected Index node
+
+    * delete(self, gid, sid, scid, tid, idx):
+      - This function will drop the Index object
+
+    * msql(gid, sid, did, scid, tid, idx)
+      - This function is used to return modified SQL for the selected
+        Index node
+
+    * get_sql(data, scid, tid)
+      - This function will generate sql from model data
+
+    * sql(gid, sid, did, scid):
+      - This function will generate sql to show it in sql pane for the
+        selected Index node.
+
+    * dependency(gid, sid, did, scid):
+      - This function will generate dependency list show it in dependency
+        pane for the selected Index node.
+
+    * dependent(gid, sid, did, scid):
+      - This function will generate dependent list to show it in dependent
+        pane for the selected Index node.
+    """
+
+    node_type = blueprint.node_type
+
+    parent_ids = [
+            {'type': 'int', 'id': 'gid'},
+            {'type': 'int', 'id': 'sid'},
+            {'type': 'int', 'id': 'did'},
+            {'type': 'int', 'id': 'scid'},
+            {'type': 'int', 'id': 'tid'}
+            ]
+    ids = [
+            {'type': 'int', 'id': 'idx'}
+            ]
+
+    operations = dict({
+        'obj': [
+            {'get': 'properties', 'delete': 'delete', 'put': 'update'},
+            {'get': 'list', 'post': 'create'}
+        ],
+        'delete': [{'delete': 'delete'}],
+        'children': [{'get': 'children'}],
+        'nodes': [{'get': 'node'}, {'get': 'nodes'}],
+        'sql': [{'get': 'sql'}],
+        'msql': [{'get': 'msql'}, {'get': 'msql'}],
+        'stats': [{'get': 'statistics'}],
+        'dependency': [{'get': 'dependencies'}],
+        'dependent': [{'get': 'dependents'}],
+        'module.js': [{}, {}, {'get': 'module_js'}],
+        'get_collations': [{'get': 'get_collations'},
+                           {'get': 'get_collations'}],
+        'get_access_methods': [{'get': 'get_access_methods'},
+                               {'get': 'get_access_methods'}],
+        'get_op_class': [{'get': 'get_op_class'},
+                               {'get': 'get_op_class'}]
+    })
+
+    def check_precondition(f):
+        """
+        This function will behave as a decorator which will checks
+        database connection before running view, it will also attaches
+        manager,conn & template_path properties to self
+        """
+        @wraps(f)
+        def wrap(*args, **kwargs):
+            # Here args[0] will hold self & kwargs will hold gid,sid,did
+            self = args[0]
+            self.manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(
+                kwargs['sid']
+            )
+            self.conn = self.manager.connection(did=kwargs['did'])
+            # If DB not connected then return error to browser
+            if not self.conn.connected():
+                return precondition_required(
+                    gettext(
+                            "Connection to the server has been lost!"
+                    )
+                )
+
+            # We need datlastsysoid to check if current index is system index
+            self.datlastsysoid = self.manager.db_info[kwargs['did']]['datlastsysoid']
+
+            # we will set template path for sql scripts
+            self.template_path = 'index/sql/9.1_plus'
+
+            # We need parent's name eg table name and schema name
+            # when we create new index in update we can fetch it using
+            # property sql
+            SQL = render_template("/".join([self.template_path,
+                                            'get_parent.sql']),
+                                  tid=kwargs['tid'])
+            status, rset = self.conn.execute_2darray(SQL)
+            if not status:
+                return internal_server_error(errormsg=rset)
+
+            for row in rset['rows']:
+                self.schema = row['schema']
+                self.table = row['table']
+
+            return f(*args, **kwargs)
+
+        return wrap
+
+    @check_precondition
+    def get_collations(self, gid, sid, did, scid, tid, idx=None):
+        """
+        This function will return list of collation available
+        via AJAX response
+        """
+        res = [{'label': '', 'value': ''}]
+        try:
+            SQL = render_template("/".join([self.template_path,
+                                            'get_collations.sql']))
+            status, rset = self.conn.execute_2darray(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            for row in rset['rows']:
+                res.append(
+                            {'label': row['collation'],
+                             'value': row['collation']}
+                        )
+            return make_json_response(
+                    data=res,
+                    status=200
+                    )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def get_access_methods(self, gid, sid, did, scid, tid, idx=None):
+        """
+        This function will return list of access methods available
+        via AJAX response
+        """
+        res = [{'label': '', 'value': ''}]
+        try:
+            SQL = render_template("/".join([self.template_path,
+                                            'get_am.sql']))
+            status, rset = self.conn.execute_2darray(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            for row in rset['rows']:
+                res.append(
+                            {'label': row['amname'],
+                             'value': row['amname']}
+                        )
+            return make_json_response(
+                    data=res,
+                    status=200
+                    )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def get_op_class(self, gid, sid, did, scid, tid, idx=None):
+        """
+        This function will return list of op_class method
+        for each access methods available via AJAX response
+        """
+        res = dict()
+        try:
+            # Fetching all the access methods
+            SQL = render_template("/".join([self.template_path,
+                                            'get_am.sql']))
+            status, rset = self.conn.execute_2darray(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            for row in rset['rows']:
+                # Fetching all the op_classes for each access method
+                SQL = render_template("/".join([self.template_path,
+                                                'get_op_class.sql']),
+                                      oid=row['oid'])
+                status, result = self.conn.execute_2darray(SQL)
+                if not status:
+                    return internal_server_error(errormsg=res)
+
+                op_class_list = [{'label': '', 'value': ''}]
+
+                for r in result['rows']:
+                    op_class_list.append({'label': r['opcname'],
+                                          'value': r['opcname']})
+
+                # Append op_class list in main result as collection
+                res[row['amname']] = op_class_list
+
+            return make_json_response(
+                    data=res,
+                    status=200
+                    )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+
+    @check_precondition
+    def list(self, gid, sid, did, scid, tid):
+        """
+        This function is used to list all the schema nodes within that collection.
+
+        Args:
+            gid: Server group ID
+            sid: Server ID
+            did: Database ID
+            scid: Schema ID
+            tid: Table ID
+
+        Returns:
+            JSON of available schema nodes
+        """
+
+        SQL = render_template("/".join([self.template_path,
+                                        'nodes.sql']), tid=tid)
+        status, res = self.conn.execute_dict(SQL)
+
+        if not status:
+            return internal_server_error(errormsg=res)
+        return ajax_response(
+                response=res['rows'],
+                status=200
+                )
+
+    @check_precondition
+    def nodes(self, gid, sid, did, scid, tid):
+        """
+        This function will used to create all the child node within that collection.
+        Here it will create all the schema node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            scid: Schema ID
+            tid: Table ID
+
+        Returns:
+            JSON of available schema child nodes
+        """
+        res = []
+        SQL = render_template("/".join([self.template_path,
+                                        'nodes.sql']), tid=tid)
+        status, rset = self.conn.execute_2darray(SQL)
+        if not status:
+            return internal_server_error(errormsg=rset)
+
+        for row in rset['rows']:
+            res.append(
+                    self.blueprint.generate_browser_node(
+                        row['oid'],
+                        tid,
+                        row['name'],
+                        icon="icon-index"
+                    ))
+
+        return make_json_response(
+                data=res,
+                status=200
+                )
+
+    def _column_details(self, idx, data):
+        """
+        This functional will fetch list of column details for index
+
+        Args:
+            idx: Index OID
+            data: Properties data
+
+        Returns:
+            Updated properties data with column details
+        """
+
+        SQL = render_template("/".join([self.template_path,
+                                        'column_details.sql']), idx=idx)
+        status, rset = self.conn.execute_2darray(SQL)
+        if not status:
+            return internal_server_error(errormsg=rset)
+        # 'attdef' comes with quotes from query so we need to strip them
+        # 'options' we need true/false to render switch ASC(false)/DESC(true)
+        columns = []
+        cols = []
+        cnt = 1
+        for row in rset['rows']:
+            # We need all data as collection for ColumnsModel
+            cols_data = {
+                'colname': row['attdef'].strip('"'),
+                'collspcname': row['collnspname'],
+                'op_class': row['opcname'],
+            }
+            if row['options'][0] == 'DESC':
+                cols_data['sort_order'] = True
+            columns.append(cols_data)
+
+            # We need same data as string to display in properties window
+            # If multiple column then separate it by colon
+            cols_str = row['attdef']
+            if row['collnspname']:
+                cols_str += ' COLLATE ' + row['collnspname']
+            if row['opcname']:
+                cols_str += ' ' + row['opcname']
+            if row['options'][0] == 'DESC':
+                cols_str += ' DESC'
+            cols.append(cols_str)
+
+        # Push as collection
+        data['columns'] = columns
+        # Push as string
+        data['cols'] = ', '.join(cols)
+
+        return data
+
+
+    @check_precondition
+    def properties(self, gid, sid, did, scid, tid, idx):
+        """
+        This function will show the properties of the selected schema node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did:  Database ID
+            scid: Schema ID
+            scid: Schema ID
+            tid: Table ID
+            idx: Index ID
+
+        Returns:
+            JSON of selected schema node
+        """
+
+        SQL = render_template("/".join([self.template_path,
+                                        'properties.sql']),
+                              tid=tid, idx=idx,
+                              datlastsysoid=self.datlastsysoid)
+
+        status, res = self.conn.execute_dict(SQL)
+
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        # Making copy of output for future use
+        data = dict(res['rows'][0])
+
+        # Add column details for current index
+        data = self._column_details(idx, data)
+
+        return ajax_response(
+                response=data,
+                status=200
+                )
+
+    @check_precondition
+    def create(self, gid, sid, did, scid, tid):
+        """
+        This function will creates new the schema object
+
+         Args:
+           gid: Server Group ID
+           sid: Server ID
+           did: Database ID
+           scid: Schema ID
+           tid: Table ID
+        """
+        data = request.form if request.form else json.loads(
+            request.data.decode()
+        )
+
+        for k, v in data.items():
+            try:
+                data[k] = json.loads(v)
+            except (ValueError, TypeError):
+                data[k] = v
+
+        required_args = {
+            'name': 'Name',
+            'columns': 'Columns'
+        }
+
+        for arg in required_args:
+            err_msg = None
+            if arg == 'columns' and len(data['columns']) < 1:
+                err_msg = "You must provide one or more column to create index"
+
+            if arg not in data:
+                err_msg = "Couldn't find the required parameter (%s)." % \
+                          required_args[arg]
+                # Check if we have at least one column
+            if err_msg is not None:
+                return make_json_response(
+                    status=410,
+                    success=0,
+                    errormsg=gettext(err_msg)
+                )
+
+        # Adding parent into data dict, will be using it while creating sql
+        data['schema'] = self.schema
+        data['table'] = self.table
+
+        try:
+            SQL = render_template("/".join([self.template_path,
+                                            'create.sql']),
+                                  data=data, conn=self.conn)
+            status, res = self.conn.execute_scalar(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            # If user chooses concurrent index then we can not run it along
+            # with other alter statments so we will separate alter index part
+            SQL = render_template("/".join([self.template_path,
+                                            'alter.sql']),
+                                  data=data, conn=self.conn)
+            SQL = SQL.strip('\n').strip(' ')
+            if SQL != '':
+                status, res = self.conn.execute_scalar(SQL)
+                if not status:
+                    return internal_server_error(errormsg=res)
+
+            # we need oid to to add object in tree at browser
+            SQL = render_template("/".join([self.template_path,
+                                            'get_oid.sql']),
+                                  tid=tid, data=data)
+            status, idx = self.conn.execute_scalar(SQL)
+            if not status:
+                return internal_server_error(errormsg=tid)
+
+            return jsonify(
+                node=self.blueprint.generate_browser_node(
+                    idx,
+                    scid,
+                    data['name'],
+                    icon="icon-index"
+                )
+            )
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def delete(self, gid, sid, did, scid, tid, idx):
+        """
+        This function will updates existing the schema object
+
+         Args:
+           gid: Server Group ID
+           sid: Server ID
+           did: Database ID
+           scid: Schema ID
+           tid: Table ID
+           idx: Index ID
+        """
+        # Below will decide if it's simple drop or drop with cascade call
+        if self.cmd == 'delete':
+            # This is a cascade operation
+            cascade = True
+        else:
+            cascade = False
+
+        try:
+            # We will first fetch the index name for current request
+            # so that we create template for dropping index
+            SQL = render_template("/".join([self.template_path,
+                                            'properties.sql']),
+                                  tid=tid, idx=idx,
+                                  datlastsysoid=self.datlastsysoid)
+
+            status, res = self.conn.execute_dict(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            data = dict(res['rows'][0])
+
+            SQL = render_template("/".join([self.template_path,
+                                            'delete.sql']),
+                                  data=data, conn=self.conn, cascade=cascade)
+            status, res = self.conn.execute_scalar(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            return make_json_response(
+                success=1,
+                info=gettext("Index is dropped"),
+                data={
+                    'id': idx,
+                    'tid': tid
+                }
+            )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def update(self, gid, sid, did, scid, tid, idx):
+        """
+        This function will updates existing the schema object
+
+         Args:
+           gid: Server Group ID
+           sid: Server ID
+           did: Database ID
+           scid: Schema ID
+           tid: Table ID
+           idx: Index ID
+        """
+        data = request.form if request.form else json.loads(request.data.decode())
+        data['schema'] = self.schema
+        data['table'] = self.table
+        try:
+            SQL = self.get_sql(scid, tid, idx, data)
+            if SQL and SQL.strip('\n') and SQL.strip(' '):
+                status, res = self.conn.execute_scalar(SQL)
+                if not status:
+                    return internal_server_error(errormsg=res)
+
+                return make_json_response(
+                    success=1,
+                    info="Index updated",
+                    data={
+                        'id': idx,
+                        'tid': tid,
+                        'scid': scid
+                    }
+                )
+            else:
+                return make_json_response(
+                    success=1,
+                    info="Nothing to update",
+                    data={
+                        'id': idx,
+                        'tid': tid,
+                        'scid': scid
+                    }
+                )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+
+    @check_precondition
+    def msql(self, gid, sid, did, scid, tid, idx=None):
+        """
+        This function will generates modified sql for schema object
+
+         Args:
+           gid: Server Group ID
+           sid: Server ID
+           did: Database ID
+           scid: Schema ID
+           tid: Table ID
+           idx: Index ID (When working with existing index)
+        """
+        data = dict()
+        for k, v in request.args.items():
+            try:
+                data[k] = json.loads(v)
+            except ValueError:
+                data[k] = v
+
+        # Adding parent into data dict, will be using it while creating sql
+        data['schema'] = self.schema
+        data['table'] = self.table
+
+        try:
+            SQL = self.get_sql(scid, tid, idx, data)
+
+            if SQL and SQL.strip('\n') and SQL.strip(' '):
+                return make_json_response(
+                        data=SQL,
+                        status=200
+                        )
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    def get_sql(self, scid, tid, idx, data):
+        """
+        This function will genrate sql from model data
+        """
+        if idx is not None:
+            SQL = render_template("/".join([self.template_path,
+                                            'properties.sql']),
+                                  tid=tid, idx=idx,
+                                  datlastsysoid=self.datlastsysoid)
+
+            status, res = self.conn.execute_dict(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            old_data = dict(res['rows'][0])
+
+            # If name is not present in data then
+            # we will fetch it from old data, we also need schema & table name
+            if 'name' not in data:
+                data['name'] = old_data['name']
+
+            SQL = render_template(
+                "/".join([self.template_path, 'update.sql']),
+                data=data, o_data=old_data, conn=self.conn
+                )
+        else:
+            required_args = {
+                'name': 'Name',
+                'columns': 'Columns'
+            }
+            for arg in required_args:
+                err = False
+                if arg == 'columns' and len(data['columns']) < 1:
+                    err = True
+
+                if arg not in data:
+                    err = True
+                    # Check if we have at least one column
+                if err:
+                    return gettext('-- incomplete definition')
+
+            # If the request for new object which do not have did
+            SQL = render_template("/".join([self.template_path, 'create.sql']),
+                                  data=data, conn=self.conn)
+            SQL += "\n"
+            SQL += render_template("/".join([self.template_path, 'alter.sql']),
+                                   data=data, conn=self.conn)
+
+        return SQL
+
+    @check_precondition
+    def sql(self, gid, sid, did, scid, tid, idx):
+        """
+        This function will generates reverse engineered sql for schema object
+
+         Args:
+           gid: Server Group ID
+           sid: Server ID
+           did: Database ID
+           scid: Schema ID
+           tid: Table ID
+           idx: Index ID
+        """
+        try:
+            SQL = render_template("/".join([self.template_path,
+                                            'properties.sql']),
+                                  tid=tid, idx=idx,
+                                  datlastsysoid=self.datlastsysoid)
+
+            status, res = self.conn.execute_dict(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            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
+
+            # Add column details for current index
+            data = self._column_details(idx, data)
+
+            SQL = self.get_sql(scid, tid, None, data)
+
+            sql_header = "-- Index: {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
+
+            return ajax_response(response=SQL)
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def dependents(self, gid, sid, did, scid, tid, idx):
+        """
+        This function get the dependents and return ajax response
+        for the schema node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            scid: Schema ID
+            tid: Table ID
+            idx: Index ID
+        """
+        dependents_result = self.get_dependents(
+            self.conn, idx
+        )
+
+        return ajax_response(
+                response=dependents_result,
+                status=200
+                )
+
+    @check_precondition
+    def dependencies(self, gid, sid, did, scid, tid, idx):
+        """
+        This function get the dependencies and return ajax response
+        for the schema node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            scid: Schema ID
+            tid: Table ID
+            idx: Index ID
+
+        """
+        dependencies_result = self.get_dependencies(
+            self.conn, idx
+        )
+
+        return ajax_response(
+                response=dependencies_result,
+                status=200
+                )
+
+IndexesView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/static/img/coll-index.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/static/img/coll-index.png
new file mode 100644
index 0000000000000000000000000000000000000000..bb1513c8287e2ee5b39c36836fc01636ed35cf5f
GIT binary patch
literal 468
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbMfoB*E?S0LTF`o3ZPMa`Pi^5sX2
z>o4lmo>i<kCRV(kJ8wtFmZzrmmrp<ccKpfLLk~aix$|l3^$+VVy<2|v&4LrJidH^6
z@$Bo-$6pTI{~QpL<QJ9X6Op*>#s{~Mc;}!vhk&@*M_wFx^kv_@PdjdY*m&jL%JXj)
zpL#Xt=!@wGpZi26dW9#rhbFAP@YX3X&fY(E*X@s+uf1P$;qB7Xujd_mIpfgtu2Mf2
zp!*n0g8YIR9G=}s19CVEJR*yMv<Dcwoy@iaGV(oL977~7Cnp?W=<zwDqrtQ$=Z(x9
zj~cx^i3d#_1)o2B`1FyRgNw8HFpEpT)q?ItD<6tE2Ork$TgH~b9njmdWXhJFHFIoS
zgadk;7ERjJwQ82t5w!(UyuP}*vazK*qK|z2!pqa!lUTDOd#6MPBg0g2&X1Sx0WD@=
zP%UwdC`m~yNwrEYN(E93Mh1okx`sx&28JO<2397<Rwky}2Bua92J_zOtwPa|o1c=I
iRteEyU<uX$RBd8qU<T1}YI^7zkQJV;elF{r5}E-1(!&P;

literal 0
HcmV?d00001

diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/static/img/index.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/static/img/index.png
new file mode 100644
index 0000000000000000000000000000000000000000..a239c125109ca8d73b6afa840b5740a8bb06934e
GIT binary patch
literal 562
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbMf+W?;sS0LTF`o3ZPMa`Pi^5sX2
z>o4lmo>i<kCRV(kJ8y?+{pF4=PftJpcH-&RqmREFeDHbi-A_Aie%yTR{klu<R-Sva
z<kahcm?Zz`B)_OcpNPbrw?2A=CAfvey9CEM1;#Bn{_^Crug9KzJ@oL)zI&gxTz|j*
z^1D^%-z+`-dclcTbB@07i%Rl|O!SIK*l_usOK`kXP@F?RoSlE{j6=^4Kl-x&{^wn{
zKW@A6VZ)Vot1rA=cINfMldt9;eL3^c^Qi}(c}FC8h9$U%Cb)*gFF*UnF(A&~KX&Hf
z=X>sa+J5uHrmOGQUVOXa?3=}>Ud=o9a@OG&(+)g;b8MqB(8G)+L4Lsu4$p3+0Xdun
z9+AaB+5?Q;PG;Ky88x0Rjv*44lM@t}42%pnFW}g)X=8DL5_f?jgZYf}hYz1VuCJh>
zqN8+*RZu{9`h+QyrcInWxt&8pLrc?p<%(4+vooAnM7C}zT~hk>3olQv0@E?IWoggE
zriEQI+a|y$Y+cRnuAVL)&N097^x3<IFQ2}B{5pS<HnaIE?Gp?Pv%m0#sEbTm4|IoW
ziEBhjN@7W>RdP`(kYX@0Ff`CLG}1LN3^6jWGBLI?G1WFOwK6c6_fBsWiiX_$l+3hB
ihz0{oum+%N6DtEVh=x<sL)QQ`FnGH9xvX<aXaWG5fB2*T

literal 0
HcmV?d00001

diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/templates/index/js/index.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/templates/index/js/index.js
new file mode 100644
index 0000000..b49492a
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/templates/index/js/index.js
@@ -0,0 +1,409 @@
+define(
+        ['jquery', 'underscore', 'underscore.string', 'pgadmin', 'pgadmin.browser',
+        'backform', 'alertify', 'pgadmin.browser.collection'],
+function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
+
+  if (!pgBrowser.Nodes['coll-index']) {
+    var databases = pgAdmin.Browser.Nodes['coll-index'] =
+      pgAdmin.Browser.Collection.extend({
+        node: 'index',
+        label: '{{ _('Indexes') }}',
+        type: 'coll-index',
+        sqlAlterHelp: 'sql-alterindex.html',
+        sqlCreateHelp: 'sql-createindex.html',
+        columns: ['name', 'description']
+      });
+  };
+
+    // Model to create column collection control
+    var ColumnModel = pgAdmin.Browser.Node.Model.extend({
+        defaults: {
+          colname: undefined,
+          collspcname: undefined,
+          op_class: undefined,
+          sort_order: false,
+          nulls: false
+        },
+        schema: [
+          {
+            id: 'colname', label:'{{ _('Column') }}', cell: 'string',
+            type: 'text', disabled: 'inSchema', editable: false,
+            control: 'node-list-by-name', node: 'column'
+          },{
+            id: 'collspcname', label:'{{ _('Collation') }}', cell: 'string',
+            type: 'text', disabled: 'inSchema', editable: false,
+            control: 'node-ajax-options', url: 'get_collations', node: 'index'
+          },{
+            id: 'op_class', label:'{{ _('Operator class') }}', cell: 'string',
+            type: 'text', disabled: 'checkAccessMethod', editable: false,
+            control: 'node-ajax-options', url: 'get_op_class', node: 'index',
+            deps: ['amname'], transform: function(data) {
+             /* We need to extract data from collection according
+              * to access method selected by user if not selected
+              * send btree related op_class options
+              */
+             var amname = this.model.handler.get('amname'),
+                 options = data['btree'];
+
+             if(_.isUndefined(amname))
+               return options;
+
+             _.each(data, function(v, k) {
+                if(amname === k) {
+                  options = v;
+                }
+              });
+             return options;
+            }
+          },{
+            id: 'sort_order', label:'{{ _('Sort order') }}', cell: 'switch',
+            type: 'switch', disabled: 'checkAccessMethod', editable: false,
+            deps: ['amname'],
+            options: {
+             'onText': 'DESC', 'offText': 'ASC',
+             'onColor': 'success', 'offColor': 'default',
+             'size': 'small'
+            }
+          },{
+            id: 'nulls', label:'{{ _('NULLs') }}', cell: 'switch',
+            type: 'switch', disabled: 'checkAccessMethod', editable: false,
+            deps: ['amname', 'sort_order'],
+            options: {
+             'onText': 'FIRST', 'offText': 'LAST',
+             'onColor': 'success', 'offColor': 'default',
+             'size': 'small'
+            }
+          }
+        ],
+        validate: function() {
+          this.errorModel.clear();
+
+          if (_.isUndefined(this.get('colname'))
+              || String(this.get('colname')).replace(/^\s+|\s+$/g, '') == '') {
+            msg = '{{ _('Column Name can not be empty.') }}';
+            this.errorModel.set('colname', msg);
+            return msg;
+          }
+        },
+        // We will check if we are under schema node
+        inSchema: function() {
+          if(this.node_info &&  'catalog' in this.node_info) {
+            return true;
+          }
+          return false;
+        },
+        // We will check if we are under schema node & in 'create' mode
+        inSchemaWithModelCheck: function(m) {
+          if(this.node_info &&  'schema' in this.node_info) {
+            // We will disable control if it's in 'edit' mode
+            if (m.isNew()) {
+              return false;
+            } else {
+              return true;
+            }
+          }
+          return true;
+        },
+        // We will check if we are under schema node and added condition
+        checkAccessMethod: function(m) {
+        //Access method is empty or btree then do not disable field
+          var parent_model = m.handler;
+          if(!m.inSchema.apply(this, [m]) &&
+              (_.isUndefined(parent_model.get('amname')) ||
+               _.isNull(parent_model.get('amname')) ||
+               String(parent_model.get('amname')).replace(/^\s+|\s+$/g, '') == '' ||
+               parent_model.get('amname') === 'btree')) {
+            // We need to set nulls to true if sort_order is set to desc
+            // nulls first is default for desc
+            if(m.get('sort_order') == true) {
+               setTimeout(function() { m.set('nulls', true) }, 10);
+            } else {
+               setTimeout(function() { m.set('nulls', false) }, 10);
+            }
+            return false;
+          }
+          return true;
+        },
+    });
+
+  if (!pgBrowser.Nodes['index']) {
+    pgAdmin.Browser.Nodes['index'] = pgAdmin.Browser.Node.extend({
+      parent_type: ['table', 'view', 'mview'],
+      collection_type: ['coll-table', 'coll-view'],
+      type: 'index',
+      label: '{{ _('Index') }}',
+      hasSQL:  true,
+      hasDepends: true,
+      Init: function() {
+        /* Avoid mulitple registration of menus */
+        if (this.initialized)
+            return;
+
+        this.initialized = true;
+
+        pgBrowser.add_menus([{
+          name: 'create_index_on_coll', node: 'coll-index', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('Index...') }}',
+          icon: 'wcTabIcon icon-index', data: {action: 'create', check: true},
+          enable: 'canCreate'
+        },{
+          name: 'create_index', node: 'index', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('Index...') }}',
+          icon: 'wcTabIcon icon-index', data: {action: 'create', check: true},
+          enable: 'canCreate'
+        },{
+          name: 'create_index_onTable', node: 'table', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('Index...') }}',
+          icon: 'wcTabIcon icon-index', data: {action: 'create', check: true},
+          enable: 'canCreate'
+        },{
+          name: 'create_index_onMatView', node: 'mview', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 5, label: '{{ _('Index...') }}',
+          icon: 'wcTabIcon icon-index', data: {action: 'create', check: true},
+          enable: 'canCreate'
+        }
+        ]);
+      },
+      canDrop: pgBrowser.Nodes['schema'].canChildDrop,
+      canDropCascade: pgBrowser.Nodes['schema'].canChildDrop,
+      model: pgAdmin.Browser.Node.Model.extend({
+        defaults: {
+          name: undefined,
+          nspname: undefined,
+          tabname: undefined,
+          spcname: 'pg_default',
+          amname: 'btree'
+        },
+        schema: [{
+          id: 'name', label: '{{ _('Name') }}', cell: 'string',
+          type: 'text', disabled: 'inSchema'
+        },{
+          id: 'oid', label:'{{ _('OID') }}', cell: 'string',
+          type: 'int', disabled: true, mode: ['edit', 'properties']
+        },{
+          id: 'spcname', label:'{{ _('Tablespace') }}', cell: 'string',
+          control: 'node-list-by-name', node: 'tablespace',
+          select2: {'allowClear': true},
+          type: 'text', mode: ['properties', 'create', 'edit'],
+          disabled: 'inSchema', filter: function(d) {
+            // If tablespace name is not "pg_global" then we need to exclude them
+            if(d && d.label.match(/pg_global/))
+            {
+              return false;
+            }
+            return true;
+          }
+        },{
+          id: 'amname', label:'{{ _('Access Method') }}', cell: 'string',
+          type: 'text', mode: ['properties', 'create', 'edit'],
+          disabled: 'inSchemaWithModelCheck', url: 'get_access_methods',
+          group: '{{ _('Definition') }}', select2: {'allowClear': true},
+          control: Backform.NodeAjaxOptionsControl.extend({
+            // When access method changes we need to clear columns collection
+            onChange: function() {
+              Backform.NodeAjaxOptionsControl.prototype.onChange.apply(this, arguments);
+              var self = this,
+              // current access method
+              current_am = self.model.get('amname'),
+              // previous access method
+              previous_am = self.model.previous('amname');
+              if (current_am != previous_am && self.model.get('columns').length !== 0) {
+                var msg = '{{ _('Changing access method will clear columns collection') }}';
+                alertify.confirm(msg, function (e) {
+                    // User clicks Ok, lets clear collection
+                    var column_collection = self.model.get('columns');
+                    column_collection.reset();
+                  }, function() {
+                    // User clicks Cancel set previous value again in combo box
+                    setTimeout(function(){
+                      self.model.set('amname', previous_am);
+                    }, 10);
+                });
+              }
+            }
+          })
+        },{
+          id: 'cols', label:'{{ _('Columns') }}', cell: 'string',
+          type: 'text', disabled: 'inSchema', mode: ['properties']
+        },{
+          id: 'fillfactor', label:'{{ _('Fill factor') }}', cell: 'string',
+          type: 'int', disabled: 'inSchema', mode: ['create', 'edit', 'properties'],
+          min: 10, max:100, group: '{{ _('Definition') }}'
+        },{
+          id: 'indisunique', label:'{{ _('Unique?') }}', cell: 'string',
+          type: 'switch', disabled: 'inSchemaWithModelCheck',
+          group: '{{ _('Definition') }}'
+        },{
+          id: 'indisclustered', label:'{{ _('Clustered?') }}', cell: 'string',
+          type: 'switch', disabled: 'inSchema',
+          group: '{{ _('Definition') }}'
+        },{
+          id: 'indisvalid', label:'{{ _('Valid?') }}', cell: 'string',
+          type: 'switch', disabled: true, mode: ['properties'],
+
+        },{
+          id: 'indisprimary', label:'{{ _('Primary?') }}', cell: 'string',
+          type: 'switch', disabled: true, mode: ['properties'],
+
+        },{
+          id: 'is_sys_idx', label:'{{ _('System index?') }}', cell: 'string',
+          type: 'switch', disabled: true, mode: ['properties'],
+
+        },{
+          id: 'isconcurrent', label:'{{ _('Concurrent build?') }}', cell: 'string',
+          type: 'switch', disabled: 'inSchemaWithModelCheck',
+          mode: ['create', 'edit'], group: '{{ _('Definition') }}'
+        },{
+          id: 'indconstraint', label:'{{ _('Constraint') }}', cell: 'string',
+          type: 'text', disabled: 'inSchemaWithModelCheck', mode: ['create', 'edit'],
+          control: 'sql-field', visible: true, group: '{{ _('Definition') }}'
+        },{
+          id: 'columns', label: 'Columns', type: 'collection',
+          group: '{{ _('Definition') }}', model: ColumnModel, mode: ['edit', 'create'],
+          canAdd: function(m) {
+            // We will disable it if it's in 'edit' mode
+            if (m.isNew()) {
+              return true;
+            } else {
+              return false;
+            }
+          },
+          canEdit: function(m) {
+            // We will disable it if it's in 'edit' mode
+            if (m.isNew()) {
+              return true;
+            } else {
+              return false;
+            }
+          },
+          canDelete: function(m) {
+            // We will disable it if it's in 'edit' mode
+            if (m.isNew()) {
+              return true;
+            } else {
+              return false;
+            }
+          },
+          control: 'unique-col-collection', uniqueCol : ['colname']
+        },{
+          id: 'description', label:'{{ _('Comment') }}', cell: 'string',
+          type: 'multiline', mode: ['properties', 'create', 'edit'],
+          disabled: 'inSchema'
+        }
+        ],
+        validate: function(keys) {
+          var err = {},
+              changedAttrs = this.changed,
+              msg = undefined;
+
+          // Nothing to validate
+          if (keys && keys.length == 0) {
+            this.errorModel.clear();
+            return null;
+          } else {
+            this.errorModel.clear();
+          }
+
+          if (_.isUndefined(this.get('name'))
+              || String(this.get('name')).replace(/^\s+|\s+$/g, '') == '') {
+            msg = '{{ _('Name can not be empty.') }}';
+            this.errorModel.set('name', msg);
+            return msg;
+          }
+          if (_.isUndefined(this.get('spcname'))
+              || String(this.get('spcname')).replace(/^\s+|\s+$/g, '') == '') {
+            msg = '{{ _('Tablespace can not be empty.') }}';
+            this.errorModel.set('spcname', msg);
+            return msg;
+          }
+          if (_.isUndefined(this.get('amname'))
+              || String(this.get('amname')).replace(/^\s+|\s+$/g, '') == '') {
+            msg = '{{ _('Access method can not be empty.') }}';
+            this.errorModel.set('amname', msg);
+            return msg;
+          }
+          // Checks if all columns has names
+          var cols = this.get('columns');
+          if(cols && cols.length > 0) {
+             if(!_.every(cols.pluck('colname'))) {
+               msg = '{{ _('You must specify column name.') }}';
+               this.errorModel.set('columns', msg);
+               return msg;
+             }
+          } else if(cols){
+               msg = '{{ _('You must specify at least one column.') }}';
+               this.errorModel.set('columns', msg);
+               return msg;
+          }
+          return null;
+        },
+        // We will check if we are under schema node & in 'create' mode
+        inSchema: function() {
+          if(this.node_info &&  'catalog' in this.node_info) {
+            return true;
+          }
+          return false;
+        },
+        // We will check if we are under schema node & in 'create' mode
+        inSchemaWithModelCheck: function(m) {
+          if(this.node_info &&  'schema' in this.node_info) {
+            // We will disable control if it's in 'edit' mode
+            if (m.isNew()) {
+              return false;
+            } else {
+              return true;
+            }
+          }
+          return true;
+        },
+        // Checks weather to enable/disable control
+        inSchemaWithColumnCheck: function(m) {
+          if(this.node_info &&  'schema' in this.node_info) {
+            // We will disable control if it's system columns
+            // ie: it's position is less then 1
+            if (m.isNew()) {
+              return false;
+            } else {
+              // if we are in edit mode
+              if (!_.isUndefined(m.get('attnum')) && m.get('attnum') >= 1 ) {
+                return false;
+              } else {
+                return true;
+              }
+           }
+          }
+          return true;
+        }
+      }),
+      // Below function will enable right click menu for creating column
+      canCreate: function(itemData, item, data) {
+          // If check is false then , we will allow create menu
+          if (data && data.check == false)
+            return true;
+
+          var t = pgBrowser.tree, i = item, d = itemData, parents = [];
+          // To iterate over tree to check parent node
+          while (i) {
+            // If it is schema then allow user to c reate table
+            if (_.indexOf(['schema'], d._type) > -1)
+              return true;
+            parents.push(d._type);
+            i = t.hasParent(i) ? t.parent(i) : null;
+            d = i ? t.itemData(i) : null;
+          }
+          // If node is under catalog then do not allow 'create' menu
+          if (_.indexOf(parents, 'catalog') > -1) {
+            return false;
+          } else {
+            return true;
+          }
+      }
+  });
+ }
+
+  return pgBrowser.Nodes['index'];
+});
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
new file mode 100644
index 0000000..f442338
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/rules/__init__.py
@@ -0,0 +1,497 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+"""Implements Rule Node"""
+
+import json
+from flask import render_template, make_response, request, jsonify
+from flask.ext.babel import gettext
+from pgadmin.utils.ajax import make_json_response, \
+    make_response as ajax_response, internal_server_error
+from pgadmin.browser.utils import PGChildNodeView
+import pgadmin.browser.server_groups.servers.databases.schemas as schemas
+from pgadmin.browser.server_groups.servers.databases.schemas.utils import \
+    parse_rule_definition
+from pgadmin.browser.collection import CollectionNodeModule
+from pgadmin.utils.ajax import precondition_required
+from pgadmin.utils.driver import get_driver
+from config import PG_DEFAULT_DRIVER
+from functools import wraps
+
+
+class RuleModule(CollectionNodeModule):
+    """
+    class RuleModule(CollectionNodeModule):
+
+        A rule collection Node which inherits CollectionNodeModule
+        class and define methods:
+          get_nodes - To generate collection node.
+          script_load - tells when to load js file.
+          csssnppets - add css to page
+    """
+    NODE_TYPE = 'rule'
+    COLLECTION_LABEL = gettext("Rules")
+
+    def __init__(self, *args, **kwargs):
+        self.min_ver = None
+        self.max_ver = None
+
+        super(RuleModule, self).__init__(*args, **kwargs)
+
+    def BackendSupported(self, manager, **kwargs):
+        """
+        Load this module if tid is view, we will not load it under
+        material view
+        """
+        if super(RuleModule, self).BackendSupported(manager, **kwargs):
+            conn = manager.connection(did=kwargs['did'])
+            # If DB is not connected then return error to browser
+            if not conn.connected():
+                return precondition_required(
+                    gettext(
+                            "Connection to the server has been lost!"
+                    )
+                )
+
+            if 'vid' not in kwargs:
+                return True
+
+            self.template_path = 'rules/sql'
+            SQL = render_template("/".join(
+                    [self.template_path, 'backend_support.sql']
+                  ), vid=kwargs['vid'])
+            status, res = conn.execute_scalar(SQL)
+            # check if any errors
+            if not status:
+                return internal_server_error(errormsg=res)
+            # Check tid is view not material view
+            # then true, othewise false
+            if res is True:
+                return res
+            else:
+                return res
+
+    def get_nodes(self, gid, sid, did, scid, **kwargs):
+        """
+        Generate the collection node
+        """
+        assert('tid' in kwargs or 'vid' in kwargs)
+        yield self.generate_browser_collection_node(
+          kwargs['tid'] if 'tid' in kwargs else kwargs['vid']
+          )
+
+    @property
+    def node_inode(self):
+        """
+        If a node has children return True otherwise False
+        """
+        return False
+
+    @property
+    def script_load(self):
+        """
+        Load the module script for rule, when any of the database nodes are
+        initialized.
+        """
+        return schemas.SchemaModule.NODE_TYPE
+
+    @property
+    def csssnippets(self):
+        """
+        Returns a snippet of css to include in the page
+        """
+        snippets = [
+                render_template(
+                    "browser/css/collection.css",
+                    node_type=self.node_type,
+                    _=gettext
+                    ),
+                render_template(
+                    "rules/css/rule.css",
+                    node_type=self.node_type,
+                    _=gettext
+                    )
+                ]
+
+        for submodule in self.submodules:
+            snippets.extend(submodule.csssnippets)
+
+        return snippets
+
+
+# Create blueprint of RuleModule.
+blueprint = RuleModule(__name__)
+
+
+class RuleView(PGChildNodeView):
+    """
+    This is a class for rule node which inherits the
+    properties and methods from PGChildNodeView class and define
+    various methods to list, create, update and delete rule.
+
+    Variables:
+    ---------
+    * node_type - tells which type of node it is
+    * parent_ids - id with its type and name of parent nodes
+    * ids - id with type and name of extension module being used.
+    * operations - function routes mappings defined.
+    """
+    node_type = blueprint.node_type
+
+    parent_ids = [
+            {'type': 'int', 'id': 'gid'},
+            {'type': 'int', 'id': 'sid'},
+            {'type': 'int', 'id': 'did'},
+            {'type': 'int', 'id': 'scid'},
+            {'type': 'int', 'id': 'tid'}
+            ]
+    ids = [
+            {'type': 'int', 'id': 'rid'}
+            ]
+
+    operations = dict({
+        'obj': [
+            {'get': 'properties', 'delete': 'delete', 'put': 'update'},
+            {'get': 'list', 'post': 'create'}
+        ],
+        'children': [{
+            'get': 'children'
+        }],
+        'delete': [{'delete': 'delete'}],
+        'nodes': [{'get': 'node'}, {'get': 'nodes'}],
+        'sql': [{'get': 'sql'}],
+        'msql': [{'get': 'msql'}, {'get': 'msql'}],
+        'stats': [{'get': 'statistics'}],
+        'dependency': [{'get': 'dependencies'}],
+        'dependent': [{'get': 'dependents'}],
+        'module.js': [{}, {}, {'get': 'module_js'}],
+        'configs': [{'get': 'configs'}]
+    })
+
+    def module_js(self):
+        """
+        This property defines whether Javascript exists for this node.
+        """
+        return make_response(
+                render_template(
+                    "rules/js/rules.js",
+                    _=gettext
+                    ),
+                200, {'Content-Type': 'application/x-javascript'}
+                )
+
+    def check_precondition(f):
+        """
+        This function will behave as a decorator which will check the
+        database connection before running a view. It will also attach
+        manager, conn & template_path properties to self
+        """
+        @wraps(f)
+        def wrap(*args, **kwargs):
+
+            # Here args[0] will hold self & kwargs will hold gid,sid,did
+            self = args[0]
+            self.manager = get_driver(
+              PG_DEFAULT_DRIVER).connection_manager(kwargs['sid'])
+            self.conn = self.manager.connection(did=kwargs['did'])
+
+            # If DB not connected then return error to browser
+            if not self.conn.connected():
+                return precondition_required(
+                    gettext(
+                            "Connection to the server has been lost!"
+                    )
+                )
+
+            self.datlastsysoid = self.manager.db_info[kwargs['did']]['datlastsysoid']
+            self.template_path = 'rules/sql'
+            return f(*args, **kwargs)
+
+        return wrap
+
+    @check_precondition
+    def list(self, gid, sid, did, scid, tid):
+        """
+        Fetch all rule properties and render into properties tab
+        """
+
+        # fetch schema name by schema id
+        SQL = render_template("/".join(
+          [self.template_path, 'properties.sql']), tid=tid)
+        status, res = self.conn.execute_dict(SQL)
+
+        if not status:
+            return internal_server_error(errormsg=res)
+        return ajax_response(
+                response=res['rows'],
+                status=200
+                )
+
+    @check_precondition
+    def nodes(self, gid, sid, did, scid, tid):
+        """
+        List all the rules under the Rules Collection node
+        """
+        res = []
+        SQL = render_template("/".join(
+          [self.template_path, 'properties.sql']), tid=tid)
+
+        status, rset = self.conn.execute_2darray(SQL)
+        if not status:
+            return internal_server_error(errormsg=rset)
+
+        for row in rset['rows']:
+            res.append(
+                    self.blueprint.generate_browser_node(
+                        row['oid'],
+                        tid,
+                        row['name'],
+                        icon="icon-rule"
+                    ))
+
+        return make_json_response(
+                data=res,
+                status=200
+                )
+
+    @check_precondition
+    def properties(self, gid, sid, did, scid, tid, rid):
+        """
+        Fetch the properties of an individual rule and render in properties tab
+
+        """
+        SQL = render_template("/".join(
+            [self.template_path, 'properties.sql']
+          ), rid=rid, datlastsysoid=self.datlastsysoid)
+        status, res = self.conn.execute_dict(SQL)
+
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        return ajax_response(
+                response=parse_rule_definition(res),
+                status=200
+                )
+
+    @check_precondition
+    def create(self, gid, sid, did, scid, tid):
+        """
+        This function will create a new rule object
+        """
+        required_args = [
+            'name',
+        ]
+
+        data = request.form if request.form else \
+            json.loads(request.data.decode())
+        for arg in required_args:
+            if arg not in data:
+                return make_json_response(
+                    status=410,
+                    success=0,
+                    errormsg=gettext(
+                        "Couldn't find the required parameter (%s)." % arg
+                    )
+                )
+        try:
+            SQL = render_template("/".join(
+                [self.template_path, 'create.sql']), data=data)
+            status, res = self.conn.execute_scalar(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            # Fetch the rule id against rule name to display node
+            # in tree browser
+            SQL = render_template("/".join(
+                [self.template_path, 'rule_id.sql']), rule_name=data['name'])
+            status, rule_id = self.conn.execute_scalar(SQL)
+            if not status:
+                return internal_server_error(errormsg=rule_id)
+            return jsonify(
+                node=self.blueprint.generate_browser_node(
+                    rule_id,
+                    tid,
+                    data['name'],
+                    icon="icon-rule"
+                )
+            )
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def update(self, gid, sid, did, scid, tid, rid):
+        """
+        This function will update a rule object
+        """
+        data = request.form if request.form else \
+            json.loads(request.data.decode())
+        SQL = self.getSQL(gid, sid, data, tid, rid)
+        try:
+            if SQL and SQL.strip('\n') and SQL.strip(' '):
+                status, res = self.conn.execute_scalar(SQL)
+                if not status:
+                    return internal_server_error(errormsg=res)
+                return make_json_response(
+                    success=1,
+                    info=gettext("Rule updated"),
+                    data={
+                        'id': tid,
+                        'sid': sid,
+                        'gid': gid,
+                        'did': did
+                    }
+                )
+            else:
+                return make_json_response(
+                    success=1,
+                    info="Nothing to update",
+                    data={
+                        'id': tid,
+                        'scid': scid,
+                        'did': did
+                    }
+                )
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def delete(self, gid, sid, did, scid, tid, rid):
+        """
+        This function will drop a rule object
+        """
+        # Below will decide if it's simple drop or drop with cascade call
+        cascade = True if self.cmd == 'delete' else False
+
+        try:
+            # Get name for rule from did
+            SQL = render_template("/".join(
+              [self.template_path, 'delete.sql']), rid=rid)
+            status, res_data = self.conn.execute_dict(SQL)
+            if not status:
+                return internal_server_error(errormsg=res_data)
+            # drop rule
+            rset = res_data['rows'][0]
+            SQL = render_template("/".join(
+                [self.template_path, 'delete.sql']),
+                  rulename=rset['rulename'],
+                  relname=rset['relname'],
+                  nspname=rset['nspname'],
+                  cascade=cascade
+            )
+            status, res = self.conn.execute_scalar(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            return make_json_response(
+                success=1,
+                info=gettext("Rule dropped"),
+                data={
+                    'id': tid,
+                    'sid': sid,
+                    'gid': gid,
+                    'did': did
+                }
+            )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def msql(self, gid, sid, did, scid, tid, rid=None):
+        """
+        This function returns modified SQL
+        """
+        data = request.args
+        SQL = self.getSQL(gid, sid, data, tid, rid)
+        return make_json_response(
+                data=SQL,
+                status=200
+                )
+
+    @check_precondition
+    def sql(self, gid, sid, did, scid, tid, rid):
+        """
+        This function will generate sql to render into the sql panel
+        """
+        SQL = render_template("/".join(
+          [self.template_path, 'properties.sql']), rid=rid)
+        status, res = self.conn.execute_dict(SQL)
+        if not status:
+            return internal_server_error(errormsg=res)
+        res_data = parse_rule_definition(res)
+        SQL = render_template("/".join(
+            [self.template_path, 'create.sql']),
+            data=res_data, display_comments=True)
+
+        return ajax_response(response=SQL)
+
+    def getSQL(self, gid, sid, data, tid, rid):
+        """
+        This function will generate sql from model data
+        """
+        try:
+            if rid is not None:
+                SQL = render_template("/".join(
+                  [self.template_path, 'properties.sql']), rid=rid)
+                status, res = self.conn.execute_dict(SQL)
+                res_data = []
+                res_data = parse_rule_definition(res)
+                if not status:
+                    return internal_server_error(errormsg=res)
+                old_data = res_data
+                SQL = render_template(
+                    "/".join([self.template_path, 'update.sql']),
+                    data=data, o_data=old_data
+                    )
+            else:
+                SQL = render_template("/".join(
+                    [self.template_path, 'create.sql']), data=data)
+            return SQL
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def dependents(self, gid, sid, did, scid, tid, rid):
+        """
+        This function gets the dependents and returns an ajax response
+        for the rule node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            tid: View ID
+            rid: Rule ID
+        """
+        dependents_result = self.get_dependents(self.conn, rid)
+        return ajax_response(
+            response=dependents_result,
+            status=200
+            )
+
+    @check_precondition
+    def dependencies(self, gid, sid, did, scid, tid, rid):
+        """
+        This function gets the dependencies and returns sn ajax response
+        for the rule node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            tid: View ID
+            rid: Rule ID
+        """
+        dependencies_result = self.get_dependencies(self.conn, rid)
+        return ajax_response(
+            response=dependencies_result,
+            status=200
+            )
+
+RuleView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/rules/static/img/coll-rule.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/rules/static/img/coll-rule.png
new file mode 100644
index 0000000000000000000000000000000000000000..cfe6ed27d98351a03e98451fe83e785aeb51351f
GIT binary patch
literal 357
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!Q-Dv1E0BJDrt0oW+5b=H{C_&@
z|C4F|pG^AyxbOed8ULTo{{Ljk|Hl*lKkj*b(Es0~_J5B$|2=B`_pssL!=`@^>;65g
z`S+m8Y=`zEpec+cL4Lsu4$p3+0Xdun9+AaB+5?Q;PG;Ky8Bv}tjv*44r}laCH7M}7
zJY3k(rBU~;KGd5<=#Js+WtXq}O?@?enTE6ko10E>S;3Z`GiP+(9r|ThaVJc2?wlhg
z<wBFqmar9VnEKaN=E$TcORXQ5+JBvSzqq!FQQCtkVR^CB37{>iC9V-ADTyViR>?)F
zK#IZ0z|cU~&`8(7FvQ5f%EZ{p#8lhB)XKnM-aEZjC>nC}Q!>*kAsP%U!5V<7O{@&e
WAR10h4_yP)z~JfX=d#Wzp$P!7cZ;e3

literal 0
HcmV?d00001

diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/rules/static/img/rule.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/rules/static/img/rule.png
new file mode 100644
index 0000000000000000000000000000000000000000..8b4978090e33bbe3d5f7ed249fd93c2da34f52d6
GIT binary patch
literal 373
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbK}cz{ocE0DgsQug(ks{c>t{C_(0
z|C1^IANT%y)b{UT{r{)4{y&-e|8f7nNA3R}HvW51{r~Cg|4*j>e>~yeqt1U1oBlnh
z`S+mw|I-=&pG^AyxclFumVXax|2?Sq_n>kK%jYzp(TpWQe!&b5&u)M?oCO|{#X#Bv
zjNMLV+W{G&o-U3d5|`KZnTs_T@Hi`bDEDUl`g^`}GN)YjKDBz@O#-F|X1Becro3=L
zVnUz`J9~da#}rq6_MWOkIpP6gt8f32>#JDS-4zfcy)J)|(ya4dQ}_S3nP9`r$iw)~
zA83JUiEBhjN@7W>RdP`(kYX@0Ff`CLG}1LN3^6jWGBLI?G1WFOwK6c6_fBsWiiX_$
ml+3hBhz0{oum+%N6DtEVh=x<sL)QQ`FnGH9xvX<aXaWEjK9-vR

literal 0
HcmV?d00001

diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/rules/templates/rules/css/rule.css b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/rules/templates/rules/css/rule.css
new file mode 100644
index 0000000..3d21bcf
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/rules/templates/rules/css/rule.css
@@ -0,0 +1,16 @@
+.icon-rule{
+  background-image: url('{{ url_for('NODE-rule.static', filename='img/rule.png') }}') !important;
+  border-radius: 10px;
+  background-repeat: no-repeat;
+  align-content: center;
+  vertical-align: middle;
+  height: 1.3em;
+}
+
+.sql_field_height_140 {
+  height: 140px;
+}
+
+.sql_field_height_280 {
+  height: 280px;
+}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/rules/templates/rules/js/rules.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/rules/templates/rules/js/rules.js
new file mode 100644
index 0000000..1d00a38
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/rules/templates/rules/js/rules.js
@@ -0,0 +1,266 @@
+define(
+  ['jquery', 'underscore', 'underscore.string', 'pgadmin',
+    'pgadmin.browser', 'codemirror'],
+
+function($, _, S, pgAdmin, pgBrowser, CodeMirror) {
+
+  /**
+    Create and add a rule collection into nodes
+    @param {variable} label - Label for Node
+    @param {variable} type - Type of Node
+    @param {variable} columns - List of columns to
+      display under under properties.
+   */
+  if (!pgBrowser.Nodes['coll-rule']) {
+    var rules = pgAdmin.Browser.Nodes['coll-rule'] =
+      pgAdmin.Browser.Collection.extend({
+        node: 'rule',
+        label: '{{ _("Rules") }}',
+        type: 'coll-rule',
+        columns: ["name", "owner", "comment"]
+      });
+  }
+
+
+  /**
+    Create and Add an Rule Node into nodes
+    @param {variable} parent_type - The list of nodes
+    under which this node to display
+    @param {variable} type - Type of Node
+    @param {variable} hasSQL - To show SQL tab
+    @param {variable} canDrop - Adds drop rule option
+    in the context menu
+    @param {variable} canDropCascade - Adds drop Cascade
+    rule option in the context menu
+   */
+  if (!pgBrowser.Nodes['rule']) {
+    pgAdmin.Browser.Nodes['rule'] = pgAdmin.Browser.Node.extend({
+      parent_type: ['table','view'],
+      type: 'rule',
+      sqlAlterHelp: 'sql-alterrule.html',
+      sqlCreateHelp: 'sql-createrule.html',
+      label: '{{ _("rule") }}',
+      collection_type: 'coll-table',
+      hasSQL:  true,
+      hasDepends: true,
+      canDrop: function(itemData, item, data){
+        pgBrowser.Nodes['schema'].canChildDrop.apply(this, [itemData, item, data]);
+        if(_.has(itemData, 'label') && itemData.label === '_RETURN')
+          return false;
+        else {
+          return true;
+        }
+      },
+      canDropCascade: function(itemData, item, data){
+        pgBrowser.Nodes['schema'].canChildDrop.apply(this, [itemData, item, data]);
+        if(_.has(itemData, 'label') && itemData.label === '_RETURN')
+          return false;
+        else {
+          return true;
+        }
+      },
+      Init: function() {
+
+        /* Avoid mulitple registration of menus */
+        if (this.initialized)
+            return;
+
+        this.initialized = true;
+
+        /**
+          Add "create rule" menu option into context and object menu
+          for the following nodes:
+          coll-rule, rule and view and table.
+          @property {data} - Allow create rule option on schema node or
+          system rules node.
+         */
+        pgBrowser.add_menus([{
+          name: 'create_rule_on_coll', node: 'coll-rule', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 1, label: '{{ _("Rule...") }}',
+          icon: 'wcTabIcon icon-rule', data: {action: 'create', check: true},
+          enable: 'canCreate'
+        },{
+          name: 'create_rule_onView', node: 'view', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 5, label: '{{ _("Rule...") }}',
+          icon: 'wcTabIcon icon-rule', data: {action: 'create', check: true},
+          enable: 'canCreate'
+        },{
+          name: 'create_rule', node: 'rule', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 1, label: '{{ _("Rule...") }}',
+          icon: 'wcTabIcon icon-rule', data: {action: 'create', check: true},
+          enable: 'canCreate'
+        },{
+          name: 'create_rule', node: 'table', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _("Rule...") }}',
+          icon: 'wcTabIcon icon-rule', data: {action: 'create', check: true},
+          enable: 'canCreate'
+        }
+        ]);
+      },
+
+      /**
+        Define model for the rule node and specify the node
+        properties of the model in schema.
+       */
+      model: pgAdmin.Browser.Node.Model.extend({
+        schema: [{
+          id: 'name', label: '{{ _("Name") }}',
+          type: 'text', disabled: function(m) {
+            // disable name field it it is system rule
+            if (m && m.get('name') == "_RETURN") {
+              return true;
+            }
+            if (m.isNew()) {
+              return false;
+            } else if (m.node_info.server.version >= 90400) {
+              return false;
+            }
+            return true;
+          }
+        },
+        {
+          id: 'oid', label:'{{ _("OID") }}',
+          type: 'text', disabled: true, mode: ['properties']
+        },
+        {
+          id: 'schema', label:'{{ _("") }}',
+          type: 'text', visible: false, disabled: function(m) {
+            // It is used while generating sql
+            m.set('schema', m.node_info.schema.label);
+          }
+        },
+        {
+          id: 'view', label:'{{ _("") }}',
+          type: 'text', visible: false, disabled: function(m){
+
+            // It is used while generating sql
+            m.set('view', this.node_data.label);
+          }
+        },
+        {
+          id: 'event', label:'{{ _("Event") }}', control: 'select2',
+          group: '{{ _("Definition") }}', type: 'text',
+          select2: {
+            width: '100%',
+            allowClear: false
+          },
+          options:[
+            {label: 'Select', value: 'Select'},
+            {label: 'Insert', value: 'Insert'},
+            {label: 'Update', value: 'Update'},
+            {label: 'Delete', value: 'Delete'}
+          ]
+        },
+        {
+          id: 'do_instead', label:'{{ _("Do Instead") }}', group: '{{ _("Definition") }}',
+          type: 'switch'
+        },
+        {
+          id: 'condition', label:'{{ _("Condition") }}',
+          type: 'text', group: '{{ _("Definition") }}',
+          control: Backform.SqlFieldControl
+        },
+        {
+          id: 'statements', label:'{{ _("Commands") }}',
+          type: 'text', group: '{{ _("Definition") }}',
+          control: Backform.SqlFieldControl
+        },
+        {
+          id: 'system_rule', label:'{{ _("System rule?") }}',
+          type: 'switch', mode: ['properties']
+        },
+        {
+          id: 'enabled', label:'{{ _("Enabled?") }}',
+          type: 'switch', mode: ['properties']
+        },
+        {
+          id: 'comment', label:'{{ _("Comment") }}', cell: 'string', type: 'multiline'
+        }
+        ],
+        validate: function() {
+
+          // Triggers specific error messages for fields
+          var err = {},
+            errmsg,
+            field_name = this.get('name');
+          if (_.isUndefined(field_name) || _.isNull(field_name) ||
+            String(field_name).replace(/^\s+|\s+$/g, '') === '')
+          {
+            err['name'] = '{{ _("Please specify name.") }}';
+            errmsg = errmsg || err['name'];
+            this.errorModel.set('name', errmsg);
+            return errmsg;
+          }
+          else
+          {
+            this.errorModel.unset('name');
+          }
+          return null;
+        }
+      }),
+
+      // Show or hide create rule menu option on parent node
+      canCreate: function(itemData, item, data) {
+
+        // If check is false then , we will allow create menu
+        if (data && data.check === false)
+          return true;
+
+        var t = pgBrowser.tree, i = item, d = itemData;
+
+        // To iterate over tree to check parent node
+        while (i) {
+
+          // If it is schema then allow user to create rule
+          if (_.indexOf(['schema'], d._type) > -1)
+            return true;
+
+          if ('coll-rule' == d._type) {
+
+            //Check if we are not child of rule
+            prev_i = t.hasParent(i) ? t.parent(i) : null;
+            prev_d = prev_i ? t.itemData(prev_i) : null;
+            prev_j = t.hasParent(prev_i) ? t.parent(prev_i) : null;
+            prev_e = prev_j ? t.itemData(prev_j) : null;
+            prev_k = t.hasParent(prev_j) ? t.parent(prev_j) : null;
+            prev_f = prev_k ? t.itemData(prev_k) : null;
+            if( prev_f._type == 'catalog') {
+              return false;
+            } else {
+              return true;
+            }
+          }
+
+          /**
+            Check if it is view and its parent node is schema
+            then allow to create Rule
+           */
+          else if('view' == d._type){
+            prev_i = t.hasParent(i) ? t.parent(i) : null;
+            prev_d = prev_i ? t.itemData(prev_i) : null;
+            prev_j = t.hasParent(prev_i) ? t.parent(prev_i) : null;
+            prev_e = prev_j ? t.itemData(prev_j) : null;
+            if(prev_e._type == 'schema') {
+              return true;
+            }else{
+              return false;
+            }
+          }
+          i = t.hasParent(i) ? t.parent(i) : null;
+          d = i ? t.itemData(i) : null;
+        }
+
+        // By default we do not want to allow create menu
+        return true;
+
+      }
+
+  });
+  }
+
+  return pgBrowser.Nodes['coll-rule'];
+});
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/img/coll-table.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/img/coll-table.png
new file mode 100644
index 0000000000000000000000000000000000000000..680e86457e8c48cd01329f0303d663b0304ab44d
GIT binary patch
literal 555
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbMf-T<EvS0Jr8^?BF1e^bu?TzmD?
zsXMRkJ%0Y|`SWMbo*ljMtZe5CgE=oc&i)J9@M-haw|DQ}Z9e_4>e%o613!~@ehb_5
z*>m*=+of*}=e<^+`SRYqd(Ef+dI3e2yw#Zb^8Wq%j~+dG{P^+Hr%&4tJb&=u!SdzH
z*Q{Cd=FOXT@7}$9`SRhzhs%~NTd`ur+O=!fuV4S_)vF1oK0kl{{PpYCFJ8P@xpL+E
z_wPS`{P_0m+f}PpZP>73)22;No;>;R;X^gZ0Y5ZmzF7BH^&ij!j3q&S!3+-1ZlnP@
zoCO|{#X#BvjNMLV+W{F%JzX3_BreCEKQ7i}Akg}-$5cydO$Teo7MG=+N#Fm<pXSlA
zF*^OfrrVmO&iz!g+vcn9N;KboWe>g3_MdIbtj55z467wYr(8Tf`DM;NgJ}*2Ts9xt
za8DvyRL7)e=Crp3yMhn8I<I_gRVTnDsxoVD`Gh<6ZiW+79FuomTDG#o_)gn1l_K@t
zbJLlaXW8s861@8^@vEZ8?}M3QA`drnbuQa~?`a=@4deV=fh{M$if#frShd78q9i4;
zB-JXpC>2OC7#SEE=o%X78W@Hc8CaPZTbY<@8<<)d7|eU8w+cl=ZhlH;S|vn-fhAZ2
cP_>Dbff+=@sp+9>fEpM)UHx3vIVCg!0JlsKi2wiq

literal 0
HcmV?d00001

diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/img/table-repl-sm.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/img/table-repl-sm.png
new file mode 100644
index 0000000000000000000000000000000000000000..967bd937fb89c483a95146c88fb4c066f6da5711
GIT binary patch
literal 675
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47>xpaLR^7d#i`G`&i$Km{^#1O
zpHAI*b?@=>XV0HMd-m+;jb~*$Ul`1J(Q)=)^XY$8$A0G@_?f)(TiB-0o~u9DE`4h_
z@3s2Om(8dDdI7mh-fGNzx%ukbyLa#2yLa#Y{ris|J$n53@zbYI+YdaSw90wIwfqwo
z*FAoGfBDMAH*a5Fvu4ekH*em(d-w9?%PH&JH{32+bv<wDN}uk<R{dMu)~;Q<e*OAa
zuU>gH?KAH>pEkLwcYDb6lTnjSMzn9Td;a|S>({S~kKHdkaxd?|-Ppw^%jf&_9uI9h
z=v%+m{Qdj)A3uJ4`}S?Y;d{CJ?}SW0kv_e={eWNN9=GZpj#VoSH*DCjY15{heRqN;
z9}AyzI&#6O^#`_{y}aw(m0jnr?*8!ML;jpIsdLYCufG;M>s0K@OF`34WUhOff8dA4
z%okCUjx~DRx&#b0#*!evU<QY0H`0I{&H|6fVj%4S#%?FG?SPCGo-U3d5|@(`6xa-u
z7&{n*jk&d@t=ZYt#m!wB+Nbx&I|O({xQMK3a_3P|&{I_66rC_>+O&yNCx<@>XyMS%
zT)kq|%G22yS((l(B_&_K@bZY7^z`^PFfCiQEbW=tw6JS3X1CO~DKJ`Bv%9OOi-$`m
zo0s!XXjnddd;j|R^$pt!6DEjxC|IbN=-4P3oeI0`tSzM>AS^9Df5MC@JZ0`&N5tB$
zgxJ`zGT48TG(363Ckg0g)e_f;l9a@fRIB8oR3OD*WMF8ZYiOivU>IU#U}a)#Wn!vr
zU}|MxFz=n-DijU5`6-!cl@JXEmS7D))h1R3W)KahriZQpYGCkm^>bP0l+XkKRw_GR

literal 0
HcmV?d00001

diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/img/table-repl.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/img/table-repl.png
new file mode 100644
index 0000000000000000000000000000000000000000..2a082c67b8c307b673d32fc0df12fb5e857fc1f7
GIT binary patch
literal 839
zcmV-N1GxN&P)<h;3K|Lk000e1NJLTq000mG000mO0{{R3C@l|D0004@P)t-s0000X
zmFJDn|B}!9qSN)d*zM8Z>EGk$<>u$+=H}Yr<*d%<W3lKio9K(r|Aox{e#rcF!}@H#
z_+hyAR<iR;tnfgm?l++9Eu88mnCXSg{cFDXL8k6Dq3kZ4>a^DG-QC^Z-rnEe-{9cj
z;o;%p;^O1u<K^Y$hrj3O=;-O`>9WCpoxM|ysXD2tspRD3tgNi;?CkCB?eFjJ>gwu{
zsX?E@R<hi7k*`Civx26$XpXHyqqbtLt*x)Guj}jU(AB@Hy?3eBZjQ1*lCnpTy-be1
zOMaOmNP@miior~Y!B~lpo6TUB&0delR))7j@bK{R^78KP?sLZ9am3zk!QEuA)KrS3
zh_ynB#ZrX8OMkLFv9YnTva)c*-fqC%Xt>!@hogbGU53F;fxbw4x<YxcHu3TC^Yiod
z_4Q+})MvNZSDnjMiJhglYLB5*q_=92qE+_x_W1btVXV`1qR&u~#a^q^TBXo%l)1IF
zwYIjlxVX6Y_xF>v*<+N)Ih*5}x!G5j$xe;LSDnnO!`mg6=3t=LR+PtVpU^d$<Y+BQ
z_y7O^0d!JMQvg8b*k%9#010qNS#tmY07w7;07w8v$!k6U007-dL_t&-(_>&@U_=27
zKmjIZ7FITP4o*%kZXRBc03W}AppdYLsF=8fBv=KXlz^Z#P(Vgj4k940prELvtfH!>
z&Zz+wK=3uSzyjJjx|({b`UZwZ#wK6^Q!{f5ODk&|TRS^@uz-W3le3Gfo4b~Yp%Ej4
zho_g9m$#3vpTE0tKwuD1AUGs6EIcAID%w3JHZ}k#5Eq}2n3SB7n&zG!n2`w-h|kK-
z$<50z$Sce&DlP&Fl$4g0S5(FZq*qnf)YLLE)YUgMHZ`}jg47q))`G2VYwzgnf_WbR
zhg&kzn38;O0000bbVXQnWMOn=I%9HWVRU5xGB7bPEip1JFfmjzFgi3dIy5yaFf}?b
zFrMx%ssI20C3HntbYx+4WjbwdWNBu305UK!FfA}SEif@uGBY|fG&(RgD=;-WFfhuO
RRjdF2002ovPDHLkV1h^asowwq

literal 0
HcmV?d00001

diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/img/table.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/img/table.png
new file mode 100644
index 0000000000000000000000000000000000000000..37b2227d8fe0cf76bde23855676403c57ccfb569
GIT binary patch
literal 593
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbMfjR2nzS0Jr8^?C1w|C7%DUUd2E
zt{ZPJ-hX-j@$;w8o<Do`?AF7lYtB7S-uOaq_KWWG|69-et2^<h^zg5oeLoU+d<)z3
z*?Y|ghvo0g7rfD(^Ga>T%hof0v-kaQT=vdv;Tyd<ueMx!clYkyd-v|$zkmP1g9i^E
zK791((c{ODpFVxszW@1)7cXAEeEIzO^OY-CK6&zF&6+iD-n@DH_U-%k?_a%owS4*V
z6)RS(UAuPu`t`40zy9#y!>3Q5-o1ObdiClJ8#Zj*xN*~_O&>pg{QUXz*RNl<Zr%Fr
z+qWM-er(&eZO4us-@kt^zO}6y=r_iaAirP+hi5m^fE>;OkH}&m?E%JaC$sH<j18VH
zjv*44L(g9qYBCULeVEWMTP@D5z~~&PxFE^#;otincP*^m-2M4%e`HI`6~&eoAG7KD
zBHj|ywXfb{f7QF}MppT*z5fz8Tx+k09M7NOlP>dY(w2yI*ETJB#CxDVyM_6hsq?*{
z%bR2yj^^b{bb0Zwd(Bu=J=bCx>jtGG3nR*NpRqG!KlWJZ=J(tnh2i}T<FyU3e_r!C
zY?tI_F5B<g&(Uyv`fuYt;f8p5Rhdig_cLtbm*#(5whH7s)e_f;l9a@fRIB8oR3OD*
zWMF8ZYiOivU>IU#U}a)#Wn!vrU}|MxFz=n-DijU5`6-!cl@JXEmS7D))h1R3W)Kah
TriZQpYGCkm^>bP0l+XkKw!A9P

literal 0
HcmV?d00001

diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.1_plus/alter.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.1_plus/alter.sql
new file mode 100644
index 0000000..0fb0ea5
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.1_plus/alter.sql
@@ -0,0 +1,4 @@
+{% if data.comment %}
+COMMENT ON CONSTRAINT {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(data.schema, data.table) }}
+    IS {{ data.comment|qtLiteral }};
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.1_plus/create.sql
new file mode 100644
index 0000000..8d8c10a
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.1_plus/create.sql
@@ -0,0 +1,4 @@
+{% if data %}
+ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }}
+    ADD{% if data.name %} CONSTRAINT {{ conn|qtIdent(data.name) }}{% endif%} CHECK ({{ data.consrc }});
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.1_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.1_plus/delete.sql
new file mode 100644
index 0000000..5a85b4f
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.1_plus/delete.sql
@@ -0,0 +1,3 @@
+{% if data %}
+ALTER TABLE {{ conn|qtIdent(data.nspname, data.relname) }} DROP CONSTRAINT {{ conn|qtIdent(data.name) }};
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.1_plus/get_name.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.1_plus/get_name.sql
new file mode 100644
index 0000000..12dfa15
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.1_plus/get_name.sql
@@ -0,0 +1,4 @@
+SELECT conname as name
+FROM pg_constraint ct
+WHERE contype = 'c'
+AND  ct.oid = {{cid}}::oid
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.1_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.1_plus/get_oid.sql
new file mode 100644
index 0000000..fa521e6
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.1_plus/get_oid.sql
@@ -0,0 +1,7 @@
+SELECT
+    oid, conname as name
+FROM
+    pg_constraint
+WHERE
+    conrelid = {{tid}}::oid
+    AND conname={{ name|qtLiteral }};
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.1_plus/get_oid_with_transaction.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.1_plus/get_oid_with_transaction.sql
new file mode 100644
index 0000000..0f2e29f
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.1_plus/get_oid_with_transaction.sql
@@ -0,0 +1,5 @@
+SELECT ct.oid,
+    ct.conname as name
+FROM pg_constraint ct
+WHERE contype='c' AND
+    conrelid = {{tid}}::oid LIMIT 1;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.1_plus/get_parent.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.1_plus/get_parent.sql
new file mode 100644
index 0000000..a652857
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.1_plus/get_parent.sql
@@ -0,0 +1,7 @@
+SELECT nsp.nspname AS schema,
+    rel.relname AS table
+FROM
+    pg_class rel
+JOIN pg_namespace nsp
+ON rel.relnamespace = nsp.oid::int
+WHERE rel.oid = {{tid}}::int
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.1_plus/nodes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.1_plus/nodes.sql
new file mode 100644
index 0000000..0701c9f
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.1_plus/nodes.sql
@@ -0,0 +1,6 @@
+SELECT c.oid, conname as name
+    FROM pg_constraint c
+WHERE contype = 'c'
+{% if tid %}
+    AND conrelid = {{ tid }}::oid
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.1_plus/properties.sql
new file mode 100644
index 0000000..18cdb35
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.1_plus/properties.sql
@@ -0,0 +1,13 @@
+SELECT c.oid, conname as name, relname, nspname, description as comment ,
+       pg_get_expr(conbin, conrelid, true) as consrc
+    FROM pg_constraint c
+    JOIN pg_class cl ON cl.oid=conrelid
+    JOIN pg_namespace nl ON nl.oid=relnamespace
+LEFT OUTER JOIN
+    pg_description des ON (des.objoid=c.oid AND
+                           des.classoid='pg_constraint'::regclass)
+WHERE contype = 'c'
+    AND conrelid = {{ tid }}::oid
+{% if cid %}
+    AND c.oid = {{ cid }}::oid
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.1_plus/update.sql
new file mode 100644
index 0000000..57d81c7
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.1_plus/update.sql
@@ -0,0 +1,4 @@
+{% if data.comment is defined and data.comment != o_data.comment %}
+COMMENT ON CONSTRAINT {{ conn|qtIdent(o_data.name) }} ON {{ conn|qtIdent(o_data.nspname, o_data.relname) }}
+    IS {{ data.comment|qtLiteral }};
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.2_plus/alter.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.2_plus/alter.sql
new file mode 100644
index 0000000..0fb0ea5
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.2_plus/alter.sql
@@ -0,0 +1,4 @@
+{% if data.comment %}
+COMMENT ON CONSTRAINT {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(data.schema, data.table) }}
+    IS {{ data.comment|qtLiteral }};
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.2_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.2_plus/create.sql
new file mode 100644
index 0000000..2c7a57f
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.2_plus/create.sql
@@ -0,0 +1,6 @@
+{% if data %}
+ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }}
+    ADD{% if data.name %} CONSTRAINT {{ conn|qtIdent(data.name) }}{% endif%} CHECK ({{ data.consrc }}){% if data.convalidated %}
+
+    NOT VALID{% endif %}{% if data.connoinherit %} NO INHERIT{% endif %};
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.2_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.2_plus/delete.sql
new file mode 100644
index 0000000..5a85b4f
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.2_plus/delete.sql
@@ -0,0 +1,3 @@
+{% if data %}
+ALTER TABLE {{ conn|qtIdent(data.nspname, data.relname) }} DROP CONSTRAINT {{ conn|qtIdent(data.name) }};
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.2_plus/get_name.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.2_plus/get_name.sql
new file mode 100644
index 0000000..a92f893
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.2_plus/get_name.sql
@@ -0,0 +1,5 @@
+SELECT conname as name,
+    NOT convalidated as convalidated
+FROM pg_constraint ct
+WHERE contype = 'c'
+AND  ct.oid = {{cid}}::oid
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.2_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.2_plus/get_oid.sql
new file mode 100644
index 0000000..46f32c9
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.2_plus/get_oid.sql
@@ -0,0 +1,8 @@
+SELECT
+    oid, conname as name,
+    NOT convalidated as convalidated
+FROM
+    pg_constraint
+WHERE
+    conrelid = {{tid}}::oid
+    AND conname={{ name|qtLiteral }};
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.2_plus/get_oid_with_transaction.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.2_plus/get_oid_with_transaction.sql
new file mode 100644
index 0000000..b497e3f
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.2_plus/get_oid_with_transaction.sql
@@ -0,0 +1,6 @@
+SELECT ct.oid,
+    ct.conname as name,
+    NOT convalidated as convalidated
+FROM pg_constraint ct
+WHERE contype='c' AND
+    conrelid = {{tid}}::oid LIMIT 1;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.2_plus/get_parent.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.2_plus/get_parent.sql
new file mode 100644
index 0000000..a652857
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.2_plus/get_parent.sql
@@ -0,0 +1,7 @@
+SELECT nsp.nspname AS schema,
+    rel.relname AS table
+FROM
+    pg_class rel
+JOIN pg_namespace nsp
+ON rel.relnamespace = nsp.oid::int
+WHERE rel.oid = {{tid}}::int
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.2_plus/nodes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.2_plus/nodes.sql
new file mode 100644
index 0000000..6fdc3c1
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.2_plus/nodes.sql
@@ -0,0 +1,7 @@
+SELECT c.oid, conname as name,
+    NOT convalidated as convalidated
+    FROM pg_constraint c
+WHERE contype = 'c'
+{% if tid %}
+    AND conrelid = {{ tid }}::oid
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.2_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.2_plus/properties.sql
new file mode 100644
index 0000000..509d317
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.2_plus/properties.sql
@@ -0,0 +1,14 @@
+SELECT c.oid, conname as name, relname, nspname, description as comment,
+       pg_get_expr(conbin, conrelid, true) as consrc,
+       connoinherit, NOT convalidated as convalidated
+    FROM pg_constraint c
+    JOIN pg_class cl ON cl.oid=conrelid
+    JOIN pg_namespace nl ON nl.oid=relnamespace
+LEFT OUTER JOIN
+    pg_description des ON (des.objoid=c.oid AND
+                           des.classoid='pg_constraint'::regclass)
+WHERE contype = 'c'
+    AND conrelid = {{ tid }}::oid
+{% if cid %}
+    AND c.oid = {{ cid }}::oid
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.2_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.2_plus/update.sql
new file mode 100644
index 0000000..6c27923
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.2_plus/update.sql
@@ -0,0 +1,13 @@
+{% if data %}
+{% if data.name != o_data.name %}
+ALTER TABLE {{ conn|qtIdent(o_data.nspname, o_data.relname) }}
+    RENAME CONSTRAINT {{ conn|qtIdent(o_data.name) }} TO {{ conn|qtIdent(data.name) }};{% endif -%}
+{% if 'convalidated' in data and o_data.convalidated != data.convalidated and not data.convalidated %}
+
+ALTER TABLE {{ conn|qtIdent(o_data.nspname, o_data.relname) }}
+    VALIDATE CONSTRAINT {{ conn|qtIdent(data.name) }};{% endif -%}
+{% if data.comment is defined and data.comment != o_data.comment %}
+
+COMMENT ON CONSTRAINT {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(o_data.nspname, o_data.relname) }}
+    IS {{ data.comment|qtLiteral }};{% endif %}
+{% endif -%}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.2_plus/validate.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.2_plus/validate.sql
new file mode 100644
index 0000000..5a62c80
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/check_constraint/sql/9.2_plus/validate.sql
@@ -0,0 +1,2 @@
+ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }}
+    VALIDATE CONSTRAINT {{ conn|qtIdent(data.name) }};
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/macros/privilege.macros b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/macros/privilege.macros
new file mode 100644
index 0000000..7eafd60
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/macros/privilege.macros
@@ -0,0 +1,13 @@
+{% macro APPLY(conn, schema_name, table_object, column_object, role, privs, with_grant_privs) -%}
+{% if privs %}
+GRANT {% for p in privs %}{% if loop.index != 1 %}, {% endif %}{{p}}({{conn|qtIdent(column_object)}}){% endfor %}
+ ON {{ conn|qtIdent(schema_name, table_object) }} TO {{ conn|qtIdent(role) }};
+{% endif %}
+{% if with_grant_privs %}
+GRANT {% for p in with_grant_privs %}{% if loop.index != 1 %}, {% endif %}{{p}}({{conn|qtIdent(column_object)}}){% endfor %}
+ ON {{ conn|qtIdent(schema_name, table_object) }} TO {{ conn|qtIdent(role) }} WITH GRANT OPTION;
+{% endif %}
+{%- endmacro %}
+{% macro RESETALL(conn, schema_name, table_object, column_object, role) -%}
+REVOKE ALL({{ conn|qtIdent(column_object) }}) ON {{ conn|qtIdent(schema_name, table_object) }} FROM {{ conn|qtIdent(role) }};
+{%- endmacro %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/macros/security.macros b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/macros/security.macros
new file mode 100644
index 0000000..39587c3
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/macros/security.macros
@@ -0,0 +1,6 @@
+{% macro APPLY(conn, type, schema_name, parent_object, child_object, provider, label) -%}
+SECURITY LABEL FOR {{ conn|qtIdent(provider) }} ON {{ type }} {{ conn|qtIdent(schema_name, parent_object, child_object) }} IS {{ label|qtLiteral }};
+{%- endmacro %}
+{% macro DROP(conn, type, schema_name, parent_object, child_object, provider) -%}
+SECURITY LABEL FOR {{ conn|qtIdent(provider) }} ON {{ type }} {{ conn|qtIdent(schema_name, parent_object, child_object) }} IS NULL;
+{%- endmacro %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/acl.sql
new file mode 100644
index 0000000..5c44a96
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/acl.sql
@@ -0,0 +1,34 @@
+SELECT 'attacl' as deftype, COALESCE(gt.rolname, 'public') grantee, g.rolname grantor, array_agg(privilege_type) as privileges, array_agg(is_grantable) as grantable
+FROM
+  (SELECT
+    d.grantee, d.grantor, d.is_grantable,
+    CASE d.privilege_type
+        WHEN 'CONNECT' THEN 'c'
+        WHEN 'CREATE' THEN 'C'
+        WHEN 'DELETE' THEN 'd'
+        WHEN 'EXECUTE' THEN 'X'
+        WHEN 'INSERT' THEN 'a'
+        WHEN 'REFERENCES' THEN 'x'
+        WHEN 'SELECT' THEN 'r'
+        WHEN 'TEMPORARY' THEN 'T'
+        WHEN 'TRIGGER' THEN 't'
+        WHEN 'TRUNCATE' THEN 'D'
+        WHEN 'UPDATE' THEN 'w'
+        WHEN 'USAGE' THEN 'U'
+        ELSE 'UNKNOWN'
+    END AS privilege_type
+  FROM
+    (SELECT attacl
+        FROM pg_attribute att
+        WHERE att.attrelid = {{tid}}::oid
+        AND att.attnum = {{clid}}::int
+    ) acl,
+    (SELECT (d).grantee AS grantee, (d).grantor AS grantor, (d).is_grantable
+        AS is_grantable, (d).privilege_type AS privilege_type FROM (SELECT
+        aclexplode(attacl) as d FROM pg_attribute att
+        WHERE att.attrelid = {{tid}}::oid
+        AND att.attnum = {{clid}}::int) a) d
+    ) d
+  LEFT JOIN pg_catalog.pg_roles g ON (d.grantor = g.oid)
+  LEFT JOIN pg_catalog.pg_roles gt ON (d.grantee = gt.oid)
+GROUP BY g.rolname, gt.rolname
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/create.sql
new file mode 100644
index 0000000..51eea52
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/create.sql
@@ -0,0 +1,38 @@
+{% import 'column/macros/security.macros' as SECLABLE %}
+{% import 'column/macros/privilege.macros' as PRIVILEGE %}
+{% import 'macros/variable.macros' as VARIABLE %}
+{###  Add column ###}
+{% if data.name and  data.cltype %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
+    ADD COLUMN {{conn|qtIdent(data.name)}} {{data.cltype}}{% if data.attlen %}
+({{data.attlen}}{% if data.attprecision%}, {{data.attprecision}}{% endif %}){% endif %}{% if data.hasSqrBracket %}
+[]{% endif %}{% if data.collspcname %}
+ COLLATE {{data.collspcname}}{% endif %}{% if data.attnotnull %}
+ NOT NULL{% endif %}{% if data.defval %}
+ DEFAULT {{data.defval}}{% endif %};
+
+{% endif %}
+{###  Add comments ###}
+{% if data and data.description %}
+COMMENT ON COLUMN {{conn|qtIdent(data.schema, data.table, data.name)}}
+    IS {{data.description|qtLiteral}};
+
+{% endif %}
+{###  Add variables to column ###}
+{% if data.attoptions %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
+    {{ VARIABLE.SET(conn, 'COLUMN', data.name, data.attoptions) }}
+
+{% endif %}
+{###  ACL ###}
+{% if data.attacl %}
+{% for priv in data.attacl %}
+{{ PRIVILEGE.APPLY(conn, data.schema, data.table, data.name, priv.grantee, priv.without_grant, priv.with_grant) }}
+{% endfor %}
+{% endif %}
+{###  Security Lables ###}
+{% if data.seclabels %}
+{% for r in data.seclabels %}
+{{ SECLABLE.APPLY(conn, 'COLUMN',data.schema, data.table, data.name, r.provider, r.label) }}
+{% endfor %}
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/delete.sql
new file mode 100644
index 0000000..0e16251
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/delete.sql
@@ -0,0 +1 @@
+ALTER TABLE {{conn|qtIdent(data.schema, data.table)}} DROP COLUMN {{conn|qtIdent(data.name)}};
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/depend.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/depend.sql
new file mode 100644
index 0000000..f5f39e7
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/depend.sql
@@ -0,0 +1,9 @@
+SELECT
+    ref.relname AS refname, d2.refclassid, dep.deptype AS deptype
+FROM pg_depend dep
+    LEFT JOIN pg_depend d2 ON dep.objid=d2.objid AND dep.refobjid != d2.refobjid
+    LEFT JOIN pg_class ref ON ref.oid=d2.refobjid
+    LEFT JOIN pg_attribute att ON d2.refclassid=att.attrelid AND d2.refobjsubid=att.attnum
+    {{ where }} AND
+    dep.classid=(SELECT oid FROM pg_class WHERE relname='pg_attrdef') AND
+    dep.refobjid NOT IN (SELECT d3.refobjid FROM pg_depend d3 WHERE d3.objid=d2.refobjid)
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/edit_mode_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/edit_mode_types.sql
new file mode 100644
index 0000000..8bc6385
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/edit_mode_types.sql
@@ -0,0 +1,5 @@
+SELECT tt.oid, format_type(tt.oid,NULL) AS typname
+  FROM pg_cast
+  JOIN pg_type tt ON tt.oid=casttarget
+WHERE castsource={{type_id}}
+   AND castcontext IN ('i', 'a')
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/get_collations.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/get_collations.sql
new file mode 100644
index 0000000..803c4d4
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/get_collations.sql
@@ -0,0 +1,7 @@
+SELECT --nspname, collname,
+	CASE WHEN length(nspname) > 0 AND length(collname) > 0  THEN
+	  concat(quote_ident(nspname), '.', quote_ident(collname))
+	ELSE '' END AS collation
+FROM pg_collation c, pg_namespace n
+    WHERE c.collnamespace=n.oid
+ORDER BY nspname, collname;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/get_inherited_tables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/get_inherited_tables.sql
new file mode 100644
index 0000000..37934b8
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/get_inherited_tables.sql
@@ -0,0 +1,12 @@
+SELECT array_to_string(array_agg(inhrelname), ', ') inhrelname, attrname
+FROM
+ (SELECT
+   inhparent::regclass AS inhrelname,
+   a.attname AS attrname
+  FROM pg_inherits i
+  LEFT JOIN pg_attribute a ON
+   (attrelid = inhparent AND attnum > 0)
+  WHERE inhrelid = {{tid}}::oid
+  ORDER BY inhseqno
+ ) a
+GROUP BY attrname;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/get_parent.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/get_parent.sql
new file mode 100644
index 0000000..5dd5d3c
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/get_parent.sql
@@ -0,0 +1,5 @@
+SELECT nsp.nspname AS schema ,rel.relname AS table
+FROM pg_class rel
+    JOIN pg_namespace nsp
+    ON rel.relnamespace = nsp.oid::int
+    WHERE rel.oid = {{tid}}::int
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/get_position.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/get_position.sql
new file mode 100644
index 0000000..cea5721
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/get_position.sql
@@ -0,0 +1,4 @@
+SELECT att.attnum
+FROM pg_attribute att
+    WHERE att.attrelid = {{tid}}::oid
+    AND att.attname = {{data.name|qtLiteral}}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/get_types.sql
new file mode 100644
index 0000000..469096c
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/get_types.sql
@@ -0,0 +1,14 @@
+SELECT * FROM
+    (SELECT format_type(t.oid,NULL) AS typname,
+    CASE WHEN typelem > 0 THEN typelem ELSE t.oid END AS elemoid
+    ,typlen, typtype, t.oid, nspname,
+    (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup
+FROM pg_type t
+    JOIN pg_namespace nsp ON typnamespace=nsp.oid
+WHERE (NOT (typname = 'unknown' AND nspname = 'pg_catalog'))
+    AND typisdefined AND typtype IN ('b', 'c', 'd', 'e', 'r')
+    AND NOT EXISTS (select 1 from pg_class where relnamespace=typnamespace and relname = typname and relkind != 'c')
+    AND (typname not like '_%' OR NOT EXISTS (select 1 from pg_class where relnamespace=typnamespace and relname = substring(typname from 2)::name and relkind != 'c'))
+    AND nsp.nspname != 'information_schema'
+    ) AS dummy
+    ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/is_referenced.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/is_referenced.sql
new file mode 100644
index 0000000..7d0bfc3
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/is_referenced.sql
@@ -0,0 +1,5 @@
+SELECT COUNT(1)
+FROM pg_depend dep
+    JOIN pg_class cl ON dep.classid=cl.oid AND relname='pg_rewrite'
+    WHERE refobjid= {{tid}}::oid
+    AND refobjsubid= {{clid|qtLiteral}};
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/nodes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/nodes.sql
new file mode 100644
index 0000000..36ed8f6
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/nodes.sql
@@ -0,0 +1,18 @@
+SELECT att.attname as name, att.attnum as OID, format_type(ty.oid,NULL) AS datatype
+FROM pg_attribute att
+    JOIN pg_type ty ON ty.oid=atttypid
+    JOIN pg_namespace tn ON tn.oid=ty.typnamespace
+    JOIN pg_class cl ON cl.oid=att.attrelid
+    JOIN pg_namespace na ON na.oid=cl.relnamespace
+    LEFT OUTER JOIN pg_type et ON et.oid=ty.typelem
+    LEFT OUTER JOIN pg_attrdef def ON adrelid=att.attrelid AND adnum=att.attnum
+    LEFT OUTER JOIN (pg_depend JOIN pg_class cs ON objid=cs.oid AND cs.relkind='S') ON refobjid=att.attrelid AND refobjsubid=att.attnum
+    LEFT OUTER JOIN pg_namespace ns ON ns.oid=cs.relnamespace
+    LEFT OUTER JOIN pg_index pi ON pi.indrelid=att.attrelid AND indisprimary
+WHERE att.attrelid = {{tid}}::oid
+{### To show system objects ###}
+{% if not show_sys_objects %}
+    AND att.attnum > 0
+{% endif %}
+    AND att.attisdropped IS FALSE
+    ORDER BY att.attnum
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/properties.sql
new file mode 100644
index 0000000..d536906
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/properties.sql
@@ -0,0 +1,45 @@
+SELECT att.attname as name, att.*, def.*, pg_catalog.pg_get_expr(def.adbin, def.adrelid) AS defval,
+        CASE WHEN att.attndims > 0 THEN 1 ELSE 0 END AS isarray,
+        format_type(ty.oid,NULL) AS typname,
+        format_type(ty.oid,att.atttypmod) AS displaytypname,
+        tn.nspname as typnspname, et.typname as elemtypname,
+        ty.typstorage AS defaultstorage, cl.relname, na.nspname,
+        concat(quote_ident(na.nspname) ,'.', quote_ident(cl.relname)) AS parent_tbl,
+	att.attstattarget, description, cs.relname AS sername,
+	ns.nspname AS serschema,
+	(SELECT count(1) FROM pg_type t2 WHERE t2.typname=ty.typname) > 1 AS isdup,
+	indkey, coll.collname, nspc.nspname as collnspname , attoptions,
+	-- Start pgAdmin4, added to save time on client side parsing
+	CASE WHEN length(coll.collname) > 0 AND length(nspc.nspname) > 0  THEN
+	  concat(quote_ident(coll.collname),'.',quote_ident(nspc.nspname))
+	ELSE '' END AS collspcname,
+	CASE WHEN strpos(format_type(ty.oid,att.atttypmod), '.') > 0 THEN
+	  split_part(format_type(ty.oid,att.atttypmod), '.', 2)
+	ELSE format_type(ty.oid,att.atttypmod) END AS cltype,
+	-- End pgAdmin4
+	EXISTS(SELECT 1 FROM pg_constraint WHERE conrelid=att.attrelid AND contype='f' AND att.attnum=ANY(conkey)) As is_fk,
+	(SELECT array_agg(provider || '=' || label) FROM pg_seclabels sl1 WHERE sl1.objoid=att.atttypid AND sl1.objsubid=0) AS seclabels,
+	(CASE WHEN (att.attnum < 1) THEN true ElSE false END) AS is_sys_column
+FROM pg_attribute att
+  JOIN pg_type ty ON ty.oid=atttypid
+  JOIN pg_namespace tn ON tn.oid=ty.typnamespace
+  JOIN pg_class cl ON cl.oid=att.attrelid
+  JOIN pg_namespace na ON na.oid=cl.relnamespace
+  LEFT OUTER JOIN pg_type et ON et.oid=ty.typelem
+  LEFT OUTER JOIN pg_attrdef def ON adrelid=att.attrelid AND adnum=att.attnum
+  LEFT OUTER JOIN pg_description des ON (des.objoid=att.attrelid AND des.objsubid=att.attnum AND des.classoid='pg_class'::regclass)
+  LEFT OUTER JOIN (pg_depend JOIN pg_class cs ON objid=cs.oid AND cs.relkind='S') ON refobjid=att.attrelid AND refobjsubid=att.attnum
+  LEFT OUTER JOIN pg_namespace ns ON ns.oid=cs.relnamespace
+  LEFT OUTER JOIN pg_index pi ON pi.indrelid=att.attrelid AND indisprimary
+  LEFT OUTER JOIN pg_collation coll ON att.attcollation=coll.oid
+  LEFT OUTER JOIN pg_namespace nspc ON coll.collnamespace=nspc.oid
+WHERE att.attrelid = {{tid}}::oid
+{% if clid %}
+    AND att.attnum = {{clid}}::int
+{% endif %}
+{### To show system objects ###}
+{% if not show_sys_objects %}
+    AND att.attnum > 0
+{% endif %}
+    AND att.attisdropped IS FALSE
+    ORDER BY att.attnum
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/update.sql
new file mode 100644
index 0000000..a36c6fc
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.1_plus/update.sql
@@ -0,0 +1,107 @@
+{% import 'column/macros/security.macros' as SECLABLE %}
+{% import 'column/macros/privilege.macros' as PRIVILEGE %}
+{% import 'macros/variable.macros' as VARIABLE %}
+{###  Rename column name ###}
+{% if 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 %}
+{###  Alter column type and collation ###}
+{% if (data.cltype and data.cltype != o_data.cltype) or (data.attlen and data.attlen != o_data.attlen) or (data.attprecision and data.attprecision != o_data.attprecision) %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
+    ALTER COLUMN {{conn|qtIdent(data.name)}} TYPE {% if data.cltype %}{{data.cltype}} {% else %}{{o_data.cltype}} {% endif %}{% if data.attlen %}
+({{data.attlen}}{% if data.attprecision%}, {{data.attprecision}}{% endif %}){% endif %}{% if data.hasSqrBracket %}
+[]{% endif %}{% if data.collspcname and data.collspcname != o_data.collspcname %}
+ COLLATE {{data.collspcname}}{% endif %};
+
+{% endif %}
+{###  Alter column default value ###}
+{% if data.defval and data.defval != o_data.defval %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
+    ALTER COLUMN {{conn|qtIdent(data.name)}} SET DEFAULT {{data.defval}};
+
+{% endif %}
+{###  Alter column not null value ###}
+{% if 'attnotnull' in data and data.attnotnull != o_data.attnotnull %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
+    ALTER COLUMN {{conn|qtIdent(data.name)}} {% if data.attnotnull %}SET{% else %}DROP{% endif %} NOT NULL;
+
+{% endif %}
+{###  Alter column statistics value ###}
+{% if data.attstattarget and data.attstattarget != o_data.attstattarget %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
+    ALTER COLUMN {{conn|qtIdent(data.name)}} SET STATISTICS {{data.attstattarget}};
+
+{% endif %}
+{###  Alter column storage value ###}
+{% if data.attstorage and data.attstorage != o_data.attstorage %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
+    ALTER COLUMN {{conn|qtIdent(data.name)}} SET STORAGE {%if data.attstorage == 'p' %}
+PLAIN{% elif data.attstorage == 'm'%}MAIN{% elif data.attstorage == 'e'%}
+EXTERNAL{% elif data.attstorage == 'x'%}EXTENDED{% endif %};
+
+{% endif %}
+{% if data.description %}
+COMMENT ON COLUMN {{conn|qtIdent(data.schema, data.table, data.name)}}
+    IS {{data.description|qtLiteral}};
+
+{% endif %}
+{### Update column variables ###}
+{% if 'attoptions' in data 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)}}
+    {{ VARIABLE.UNSET(conn, 'COLUMN', data.name, variables.deleted) }}
+{% endif %}
+{% if 'added' in variables and variables.added|length > 0 %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
+    {{ VARIABLE.SET(conn, 'COLUMN', data.name, variables.added) }}
+{% endif %}
+{% if 'changed' in variables and variables.changed|length > 0 %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
+    {{ VARIABLE.SET(conn, 'COLUMN', data.name, variables.changed) }}
+{% endif %}
+
+{% endif %}
+{### Update column privileges ###}
+{# Change the privileges #}
+{% if data.attacl %}
+{% if 'deleted' in data.attacl %}
+{% for priv in data.attacl.deleted %}
+{{ PRIVILEGE.RESETALL(conn, data.schema, data.table, data.name, priv.grantee) }}
+{% endfor %}
+{% endif %}
+{% if 'changed' in data.attacl %}
+{% for priv in data.attacl.changed %}
+{{ PRIVILEGE.RESETALL(conn, data.schema, data.table, data.name, priv.grantee) }}
+{{ PRIVILEGE.APPLY(conn, data.schema, data.table, data.name, priv.grantee, priv.without_grant, priv.with_grant) }}
+{% endfor %}
+{% endif %}
+{% if 'added' in data.attacl %}
+{% for priv in data.attacl.added %}
+{{ PRIVILEGE.APPLY(conn, data.schema, data.table, data.name, priv.grantee, priv.without_grant, priv.with_grant) }}
+{% endfor %}
+{% endif %}
+{% endif %}
+{### Uppdate tablespace securitylabel ###}
+{# The SQL generated below will change Security Label #}
+{% if data.seclabels and data.seclabels|length > 0 %}
+{% set seclabels = data.seclabels %}
+{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %}
+{% for r in seclabels.deleted %}
+{{ SECLABLE.DROP(conn, 'COLUMN', data.schema, data.table, data.name, r.provider) }}
+{% endfor %}
+{% endif %}
+{% if 'added' in seclabels and seclabels.added|length > 0 %}
+{% for r in seclabels.added %}
+{{ SECLABLE.APPLY(conn, 'COLUMN',data.schema, data.table, data.name, r.provider, r.label) }}
+{% endfor %}
+{% endif %}
+{% if 'changed' in seclabels and seclabels.changed|length > 0 %}
+{% for r in seclabels.changed %}
+{{ SECLABLE.APPLY(conn, 'COLUMN',data.schema, data.table, data.name, r.provider, r.label) }}
+{% endfor %}
+{% endif %}
+
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/acl.sql
new file mode 100644
index 0000000..5c44a96
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/acl.sql
@@ -0,0 +1,34 @@
+SELECT 'attacl' as deftype, COALESCE(gt.rolname, 'public') grantee, g.rolname grantor, array_agg(privilege_type) as privileges, array_agg(is_grantable) as grantable
+FROM
+  (SELECT
+    d.grantee, d.grantor, d.is_grantable,
+    CASE d.privilege_type
+        WHEN 'CONNECT' THEN 'c'
+        WHEN 'CREATE' THEN 'C'
+        WHEN 'DELETE' THEN 'd'
+        WHEN 'EXECUTE' THEN 'X'
+        WHEN 'INSERT' THEN 'a'
+        WHEN 'REFERENCES' THEN 'x'
+        WHEN 'SELECT' THEN 'r'
+        WHEN 'TEMPORARY' THEN 'T'
+        WHEN 'TRIGGER' THEN 't'
+        WHEN 'TRUNCATE' THEN 'D'
+        WHEN 'UPDATE' THEN 'w'
+        WHEN 'USAGE' THEN 'U'
+        ELSE 'UNKNOWN'
+    END AS privilege_type
+  FROM
+    (SELECT attacl
+        FROM pg_attribute att
+        WHERE att.attrelid = {{tid}}::oid
+        AND att.attnum = {{clid}}::int
+    ) acl,
+    (SELECT (d).grantee AS grantee, (d).grantor AS grantor, (d).is_grantable
+        AS is_grantable, (d).privilege_type AS privilege_type FROM (SELECT
+        aclexplode(attacl) as d FROM pg_attribute att
+        WHERE att.attrelid = {{tid}}::oid
+        AND att.attnum = {{clid}}::int) a) d
+    ) d
+  LEFT JOIN pg_catalog.pg_roles g ON (d.grantor = g.oid)
+  LEFT JOIN pg_catalog.pg_roles gt ON (d.grantee = gt.oid)
+GROUP BY g.rolname, gt.rolname
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/create.sql
new file mode 100644
index 0000000..51eea52
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/create.sql
@@ -0,0 +1,38 @@
+{% import 'column/macros/security.macros' as SECLABLE %}
+{% import 'column/macros/privilege.macros' as PRIVILEGE %}
+{% import 'macros/variable.macros' as VARIABLE %}
+{###  Add column ###}
+{% if data.name and  data.cltype %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
+    ADD COLUMN {{conn|qtIdent(data.name)}} {{data.cltype}}{% if data.attlen %}
+({{data.attlen}}{% if data.attprecision%}, {{data.attprecision}}{% endif %}){% endif %}{% if data.hasSqrBracket %}
+[]{% endif %}{% if data.collspcname %}
+ COLLATE {{data.collspcname}}{% endif %}{% if data.attnotnull %}
+ NOT NULL{% endif %}{% if data.defval %}
+ DEFAULT {{data.defval}}{% endif %};
+
+{% endif %}
+{###  Add comments ###}
+{% if data and data.description %}
+COMMENT ON COLUMN {{conn|qtIdent(data.schema, data.table, data.name)}}
+    IS {{data.description|qtLiteral}};
+
+{% endif %}
+{###  Add variables to column ###}
+{% if data.attoptions %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
+    {{ VARIABLE.SET(conn, 'COLUMN', data.name, data.attoptions) }}
+
+{% endif %}
+{###  ACL ###}
+{% if data.attacl %}
+{% for priv in data.attacl %}
+{{ PRIVILEGE.APPLY(conn, data.schema, data.table, data.name, priv.grantee, priv.without_grant, priv.with_grant) }}
+{% endfor %}
+{% endif %}
+{###  Security Lables ###}
+{% if data.seclabels %}
+{% for r in data.seclabels %}
+{{ SECLABLE.APPLY(conn, 'COLUMN',data.schema, data.table, data.name, r.provider, r.label) }}
+{% endfor %}
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/delete.sql
new file mode 100644
index 0000000..0e16251
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/delete.sql
@@ -0,0 +1 @@
+ALTER TABLE {{conn|qtIdent(data.schema, data.table)}} DROP COLUMN {{conn|qtIdent(data.name)}};
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/depend.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/depend.sql
new file mode 100644
index 0000000..f5f39e7
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/depend.sql
@@ -0,0 +1,9 @@
+SELECT
+    ref.relname AS refname, d2.refclassid, dep.deptype AS deptype
+FROM pg_depend dep
+    LEFT JOIN pg_depend d2 ON dep.objid=d2.objid AND dep.refobjid != d2.refobjid
+    LEFT JOIN pg_class ref ON ref.oid=d2.refobjid
+    LEFT JOIN pg_attribute att ON d2.refclassid=att.attrelid AND d2.refobjsubid=att.attnum
+    {{ where }} AND
+    dep.classid=(SELECT oid FROM pg_class WHERE relname='pg_attrdef') AND
+    dep.refobjid NOT IN (SELECT d3.refobjid FROM pg_depend d3 WHERE d3.objid=d2.refobjid)
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/edit_mode_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/edit_mode_types.sql
new file mode 100644
index 0000000..0c112c5
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/edit_mode_types.sql
@@ -0,0 +1,5 @@
+SELECT tt.oid, format_type(tt.oid,NULL) AS typname
+FROM pg_cast
+    JOIN pg_type tt ON tt.oid=casttarget
+WHERE castsource={{type_id}}
+    AND castcontext IN ('i', 'a')
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/get_collations.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/get_collations.sql
new file mode 100644
index 0000000..7418742
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/get_collations.sql
@@ -0,0 +1,7 @@
+SELECT --nspname, collname,
+	CASE WHEN length(nspname) > 0 AND length(collname) > 0  THEN
+	  concat(quote_ident(nspname), '.', quote_ident(collname))
+	ELSE '' END AS collation
+FROM pg_collation c, pg_namespace n
+    WHERE c.collnamespace=n.oid
+    ORDER BY nspname, collname;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/get_inherited_tables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/get_inherited_tables.sql
new file mode 100644
index 0000000..37934b8
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/get_inherited_tables.sql
@@ -0,0 +1,12 @@
+SELECT array_to_string(array_agg(inhrelname), ', ') inhrelname, attrname
+FROM
+ (SELECT
+   inhparent::regclass AS inhrelname,
+   a.attname AS attrname
+  FROM pg_inherits i
+  LEFT JOIN pg_attribute a ON
+   (attrelid = inhparent AND attnum > 0)
+  WHERE inhrelid = {{tid}}::oid
+  ORDER BY inhseqno
+ ) a
+GROUP BY attrname;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/get_parent.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/get_parent.sql
new file mode 100644
index 0000000..5dd5d3c
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/get_parent.sql
@@ -0,0 +1,5 @@
+SELECT nsp.nspname AS schema ,rel.relname AS table
+FROM pg_class rel
+    JOIN pg_namespace nsp
+    ON rel.relnamespace = nsp.oid::int
+    WHERE rel.oid = {{tid}}::int
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/get_position.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/get_position.sql
new file mode 100644
index 0000000..cea5721
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/get_position.sql
@@ -0,0 +1,4 @@
+SELECT att.attnum
+FROM pg_attribute att
+    WHERE att.attrelid = {{tid}}::oid
+    AND att.attname = {{data.name|qtLiteral}}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/get_types.sql
new file mode 100644
index 0000000..469096c
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/get_types.sql
@@ -0,0 +1,14 @@
+SELECT * FROM
+    (SELECT format_type(t.oid,NULL) AS typname,
+    CASE WHEN typelem > 0 THEN typelem ELSE t.oid END AS elemoid
+    ,typlen, typtype, t.oid, nspname,
+    (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup
+FROM pg_type t
+    JOIN pg_namespace nsp ON typnamespace=nsp.oid
+WHERE (NOT (typname = 'unknown' AND nspname = 'pg_catalog'))
+    AND typisdefined AND typtype IN ('b', 'c', 'd', 'e', 'r')
+    AND NOT EXISTS (select 1 from pg_class where relnamespace=typnamespace and relname = typname and relkind != 'c')
+    AND (typname not like '_%' OR NOT EXISTS (select 1 from pg_class where relnamespace=typnamespace and relname = substring(typname from 2)::name and relkind != 'c'))
+    AND nsp.nspname != 'information_schema'
+    ) AS dummy
+    ORDER BY nspname <> 'pg_catalog', nspname <> 'public', nspname, 1
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/is_referenced.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/is_referenced.sql
new file mode 100644
index 0000000..7d0bfc3
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/is_referenced.sql
@@ -0,0 +1,5 @@
+SELECT COUNT(1)
+FROM pg_depend dep
+    JOIN pg_class cl ON dep.classid=cl.oid AND relname='pg_rewrite'
+    WHERE refobjid= {{tid}}::oid
+    AND refobjsubid= {{clid|qtLiteral}};
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/nodes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/nodes.sql
new file mode 100644
index 0000000..7a15333
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/nodes.sql
@@ -0,0 +1,18 @@
+SELECT att.attname as name, att.attnum as OID, format_type(ty.oid,NULL) AS datatype
+FROM pg_attribute att
+  JOIN pg_type ty ON ty.oid=atttypid
+  JOIN pg_namespace tn ON tn.oid=ty.typnamespace
+  JOIN pg_class cl ON cl.oid=att.attrelid
+  JOIN pg_namespace na ON na.oid=cl.relnamespace
+  LEFT OUTER JOIN pg_type et ON et.oid=ty.typelem
+  LEFT OUTER JOIN pg_attrdef def ON adrelid=att.attrelid AND adnum=att.attnum
+  LEFT OUTER JOIN (pg_depend JOIN pg_class cs ON objid=cs.oid AND cs.relkind='S') ON refobjid=att.attrelid AND refobjsubid=att.attnum
+  LEFT OUTER JOIN pg_namespace ns ON ns.oid=cs.relnamespace
+  LEFT OUTER JOIN pg_index pi ON pi.indrelid=att.attrelid AND indisprimary
+WHERE att.attrelid = {{tid}}::oid
+    {### To show system objects ###}
+    {% if not show_sys_objects %}
+    AND att.attnum > 0
+    {% endif %}
+    AND att.attisdropped IS FALSE
+    ORDER BY att.attnum
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/properties.sql
new file mode 100644
index 0000000..d536906
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/properties.sql
@@ -0,0 +1,45 @@
+SELECT att.attname as name, att.*, def.*, pg_catalog.pg_get_expr(def.adbin, def.adrelid) AS defval,
+        CASE WHEN att.attndims > 0 THEN 1 ELSE 0 END AS isarray,
+        format_type(ty.oid,NULL) AS typname,
+        format_type(ty.oid,att.atttypmod) AS displaytypname,
+        tn.nspname as typnspname, et.typname as elemtypname,
+        ty.typstorage AS defaultstorage, cl.relname, na.nspname,
+        concat(quote_ident(na.nspname) ,'.', quote_ident(cl.relname)) AS parent_tbl,
+	att.attstattarget, description, cs.relname AS sername,
+	ns.nspname AS serschema,
+	(SELECT count(1) FROM pg_type t2 WHERE t2.typname=ty.typname) > 1 AS isdup,
+	indkey, coll.collname, nspc.nspname as collnspname , attoptions,
+	-- Start pgAdmin4, added to save time on client side parsing
+	CASE WHEN length(coll.collname) > 0 AND length(nspc.nspname) > 0  THEN
+	  concat(quote_ident(coll.collname),'.',quote_ident(nspc.nspname))
+	ELSE '' END AS collspcname,
+	CASE WHEN strpos(format_type(ty.oid,att.atttypmod), '.') > 0 THEN
+	  split_part(format_type(ty.oid,att.atttypmod), '.', 2)
+	ELSE format_type(ty.oid,att.atttypmod) END AS cltype,
+	-- End pgAdmin4
+	EXISTS(SELECT 1 FROM pg_constraint WHERE conrelid=att.attrelid AND contype='f' AND att.attnum=ANY(conkey)) As is_fk,
+	(SELECT array_agg(provider || '=' || label) FROM pg_seclabels sl1 WHERE sl1.objoid=att.atttypid AND sl1.objsubid=0) AS seclabels,
+	(CASE WHEN (att.attnum < 1) THEN true ElSE false END) AS is_sys_column
+FROM pg_attribute att
+  JOIN pg_type ty ON ty.oid=atttypid
+  JOIN pg_namespace tn ON tn.oid=ty.typnamespace
+  JOIN pg_class cl ON cl.oid=att.attrelid
+  JOIN pg_namespace na ON na.oid=cl.relnamespace
+  LEFT OUTER JOIN pg_type et ON et.oid=ty.typelem
+  LEFT OUTER JOIN pg_attrdef def ON adrelid=att.attrelid AND adnum=att.attnum
+  LEFT OUTER JOIN pg_description des ON (des.objoid=att.attrelid AND des.objsubid=att.attnum AND des.classoid='pg_class'::regclass)
+  LEFT OUTER JOIN (pg_depend JOIN pg_class cs ON objid=cs.oid AND cs.relkind='S') ON refobjid=att.attrelid AND refobjsubid=att.attnum
+  LEFT OUTER JOIN pg_namespace ns ON ns.oid=cs.relnamespace
+  LEFT OUTER JOIN pg_index pi ON pi.indrelid=att.attrelid AND indisprimary
+  LEFT OUTER JOIN pg_collation coll ON att.attcollation=coll.oid
+  LEFT OUTER JOIN pg_namespace nspc ON coll.collnamespace=nspc.oid
+WHERE att.attrelid = {{tid}}::oid
+{% if clid %}
+    AND att.attnum = {{clid}}::int
+{% endif %}
+{### To show system objects ###}
+{% if not show_sys_objects %}
+    AND att.attnum > 0
+{% endif %}
+    AND att.attisdropped IS FALSE
+    ORDER BY att.attnum
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/update.sql
new file mode 100644
index 0000000..bcfb90c
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/column/sql/9.2_plus/update.sql
@@ -0,0 +1,105 @@
+{% import 'column/macros/security.macros' as SECLABLE %}
+{% import 'column/macros/privilege.macros' as PRIVILEGE %}
+{% import 'macros/variable.macros' as VARIABLE %}
+{###  Rename column name ###}
+{% if 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 %}
+{###  Alter column type and collation ###}
+{% if (data.cltype and data.cltype != o_data.cltype) or (data.attlen and data.attlen != o_data.attlen) or (data.attprecision and data.attprecision != o_data.attprecision) %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
+    ALTER COLUMN {{conn|qtIdent(data.name)}} TYPE {% if data.cltype %}{{data.cltype}} {% else %}{{o_data.cltype}} {% endif %}{% if data.attlen %}
+({{data.attlen}}{% if data.attprecision%}, {{data.attprecision}}{% endif %}){% endif %}{% if data.hasSqrBracket %}
+[]{% endif %}{% if data.collspcname and data.collspcname != o_data.collspcname %}
+ COLLATE {{data.collspcname}}{% endif %};
+
+{% endif %}
+{###  Alter column default value ###}
+{% if data.defval and data.defval != o_data.defval %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
+    ALTER COLUMN {{conn|qtIdent(data.name)}} SET DEFAULT {{data.defval}};
+
+{% endif %}
+{###  Alter column not null value ###}
+{% if 'attnotnull' in data and data.attnotnull != o_data.attnotnull %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
+    ALTER COLUMN {{conn|qtIdent(data.name)}} {% if data.attnotnull %}SET{% else %}DROP{% endif %} NOT NULL;
+
+{% endif %}
+{###  Alter column statistics value ###}
+{% if data.attstattarget and data.attstattarget != o_data.attstattarget %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
+    ALTER COLUMN {{conn|qtIdent(data.name)}} SET STATISTICS {{data.attstattarget}};
+
+{% endif %}
+{###  Alter column storage value ###}
+{% if data.attstorage and data.attstorage != o_data.attstorage %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
+    ALTER COLUMN {{conn|qtIdent(data.name)}} SET STORAGE {%if data.attstorage == 'p' %}
+PLAIN{% elif data.attstorage == 'm'%}MAIN{% elif data.attstorage == 'e'%}
+EXTERNAL{% elif data.attstorage == 'x'%}EXTENDED{% endif %};
+
+{% endif %}
+{% if data.description %}
+COMMENT ON COLUMN {{conn|qtIdent(data.schema, data.table, data.name)}}
+    IS {{data.description|qtLiteral}};
+
+{% endif %}
+{### Update column variables ###}
+{% if 'attoptions' in data 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)}}
+    {{ VARIABLE.UNSET(conn, 'COLUMN', data.name, variables.deleted) }}
+{% endif %}
+{% if 'added' in variables and variables.added|length > 0 %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
+    {{ VARIABLE.SET(conn, 'COLUMN', data.name, variables.added) }}
+{% endif %}
+{% if 'changed' in variables and variables.changed|length > 0 %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
+    {{ VARIABLE.SET(conn, 'COLUMN', data.name, variables.changed) }}
+{% endif %}
+{% endif %}
+{### Update column privileges ###}
+{# Change the privileges #}
+{% if data.attacl %}
+{% if 'deleted' in data.attacl %}
+{% for priv in data.attacl.deleted %}
+{{ PRIVILEGE.RESETALL(conn, data.schema, data.table, data.name, priv.grantee) }}
+{% endfor %}
+{% endif %}
+{% if 'changed' in data.attacl %}
+{% for priv in data.attacl.changed %}
+{{ PRIVILEGE.RESETALL(conn, data.schema, data.table, data.name, priv.grantee) }}
+{{ PRIVILEGE.APPLY(conn, data.schema, data.table, data.name, priv.grantee, priv.without_grant, priv.with_grant) }}
+{% endfor %}
+{% endif %}
+{% if 'added' in data.attacl %}
+{% for priv in data.attacl.added %}
+{{ PRIVILEGE.APPLY(conn, data.schema, data.table, data.name, priv.grantee, priv.without_grant, priv.with_grant) }}
+{% endfor %}
+{% endif %}
+{% endif %}
+{### Uppdate tablespace securitylabel ###}
+{# The SQL generated below will change Security Label #}
+{% if data.seclabels and data.seclabels|length > 0 %}
+{% set seclabels = data.seclabels %}
+{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %}
+{% for r in seclabels.deleted %}
+{{ SECLABLE.DROP(conn, 'COLUMN', data.schema, data.table, data.name, r.provider) }}
+{% endfor %}
+{% endif %}
+{% if 'added' in seclabels and seclabels.added|length > 0 %}
+{% for r in seclabels.added %}
+{{ SECLABLE.APPLY(conn, 'COLUMN',data.schema, data.table, data.name, r.provider, r.label) }}
+{% endfor %}
+{% endif %}
+{% if 'changed' in seclabels and seclabels.changed|length > 0 %}
+{% for r in seclabels.changed %}
+{{ SECLABLE.APPLY(conn, 'COLUMN',data.schema, data.table, data.name, r.provider, r.label) }}
+{% endfor %}
+{% endif %}
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/alter.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/alter.sql
new file mode 100644
index 0000000..0fb0ea5
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/alter.sql
@@ -0,0 +1,4 @@
+{% if data.comment %}
+COMMENT ON CONSTRAINT {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(data.schema, data.table) }}
+    IS {{ data.comment|qtLiteral }};
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/begin.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/begin.sql
new file mode 100644
index 0000000..58bfee1
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/begin.sql
@@ -0,0 +1 @@
+BEGIN;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/create.sql
new file mode 100644
index 0000000..c6a53cd
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/create.sql
@@ -0,0 +1,12 @@
+ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }}
+    ADD{% if data.name %} CONSTRAINT {{ conn|qtIdent(data.name) }}{% endif%} EXCLUDE {% if data.amname and data.amname != '' %}USING {{data.amname}}{% endif %} (
+    {% for col in data.columns %}{% if loop.index != 1 %},
+    {% endif %}{{ conn|qtIdent(col.column)}} {% if col.oper_class and col.oper_class != '' %}{{col.oper_class}} {% endif%}{% if col.order %}ASC{% else %}DESC{% endif %} NULLS {% if col.nulls_order %}FIRST{% else %}LAST{% endif %} WITH {{col.operator}}{% endfor %}){% if data.fillfactor %}
+    WITH (FILLFACTOR={{data.fillfactor}}){% endif %}{% if data.spcname and data.spcname != "pg_default" %}
+
+    USING INDEX TABLESPACE {{ conn|qtIdent(data.spcname) }}{% endif %}
+{% if data.condeferrable %}
+
+    DEFERRABLE{% if data.condeferred %}
+ INITIALLY DEFERRED{% endif%}
+{% endif%}{% if data.constraint %} WHERE ({{data.constraint}}){% endif%};
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/delete.sql
new file mode 100644
index 0000000..2096795
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/delete.sql
@@ -0,0 +1,3 @@
+{% if data %}
+ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }} DROP CONSTRAINT {{ conn|qtIdent(data.name) }}{% if cascade%} CASCADE{% endif %};
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/end.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/end.sql
new file mode 100644
index 0000000..92d09d5
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/end.sql
@@ -0,0 +1 @@
+END;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/get_access_methods.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/get_access_methods.sql
new file mode 100644
index 0000000..5d74057
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/get_access_methods.sql
@@ -0,0 +1,6 @@
+SELECT amname
+FROM pg_am
+WHERE EXISTS (SELECT 1
+              FROM pg_proc
+              WHERE oid=amgettuple)
+ORDER BY amname;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/get_constraint_cols.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/get_constraint_cols.sql
new file mode 100644
index 0000000..cc1a902
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/get_constraint_cols.sql
@@ -0,0 +1,22 @@
+{% for n in range(colcnt|int) %}
+{% if loop.index != 1 %}
+UNION
+{% endif %}
+SELECT
+  i.indoption[{{loop.index -1}}] AS options,
+  pg_get_indexdef(i.indexrelid, {{loop.index}}, true) AS coldef,
+  op.oprname,
+  CASE WHEN (o.opcdefault = FALSE) THEN o.opcname ELSE null END AS opcname
+,
+  coll.collname,
+  nspc.nspname as collnspname,
+  format_type(ty.oid,NULL) AS col_type
+FROM pg_index i
+JOIN pg_attribute a ON (a.attrelid = i.indexrelid AND attnum = {{loop.index}})
+JOIN pg_type ty ON ty.oid=a.atttypid
+LEFT OUTER JOIN pg_opclass o ON (o.oid = i.indclass[{{loop.index -1}}])
+LEFT OUTER JOIN pg_constraint c ON (c.conindid = i.indexrelid) LEFT OUTER JOIN pg_operator op ON (op.oid = c.conexclop[{{loop.index}}])
+LEFT OUTER JOIN pg_collation coll ON a.attcollation=coll.oid
+LEFT OUTER JOIN pg_namespace nspc ON coll.collnamespace=nspc.oid
+WHERE i.indexrelid = {{cid}}::oid
+{% endfor %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/get_name.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/get_name.sql
new file mode 100644
index 0000000..7aaa522
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/get_name.sql
@@ -0,0 +1,3 @@
+SELECT conname as name
+FROM pg_constraint ct
+WHERE ct.conindid = {{cid}}::oid
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/get_oid.sql
new file mode 100644
index 0000000..168e13b
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/get_oid.sql
@@ -0,0 +1,4 @@
+SELECT ct.oid
+FROM pg_constraint ct
+WHERE contype='x' AND
+ct.conname = {{ name|qtLiteral }};
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/get_oid_with_transaction.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/get_oid_with_transaction.sql
new file mode 100644
index 0000000..abe636a
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/get_oid_with_transaction.sql
@@ -0,0 +1,6 @@
+SELECT ct.oid,
+    ct.conname as name,
+    NOT convalidated as convalidated
+FROM pg_constraint ct
+WHERE contype='f' AND
+    conrelid = {{tid}}::oid LIMIT 1;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/get_oper_class.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/get_oper_class.sql
new file mode 100644
index 0000000..c6739d0
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/get_oper_class.sql
@@ -0,0 +1,7 @@
+SELECT opcname
+FROM pg_opclass opc,
+pg_am am
+WHERE opcmethod=am.oid AND
+      am.amname ={{indextype|qtLiteral}} AND
+      NOT opcdefault
+ORDER BY 1
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/get_operator.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/get_operator.sql
new file mode 100644
index 0000000..9978b96
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/get_operator.sql
@@ -0,0 +1,29 @@
+SELECT DISTINCT op.oprname as oprname
+FROM pg_operator op,
+( SELECT oid
+  FROM (SELECT format_type(t.oid,NULL) AS typname,
+      t.oid as oid
+      FROM pg_type t
+      JOIN pg_namespace nsp ON typnamespace=nsp.oid
+      WHERE (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) AND
+      typisdefined AND
+      typtype IN ('b', 'c', 'd', 'e', 'r') AND
+      NOT EXISTS (SELECT 1
+                  FROM pg_class
+                  WHERE relnamespace=typnamespace AND
+                  relname = typname AND
+                  relkind != 'c') AND
+      (typname NOT LIKE '_%' OR
+      NOT EXISTS (SELECT 1
+                  FROM pg_class
+                  WHERE relnamespace=typnamespace AND
+                    relname = SUBSTRING(typname FROM 2)::name AND
+                    relkind != 'c'))
+    {% if not show_sysobj %}
+      AND nsp.nspname != 'information_schema'
+    {% endif %}
+      UNION SELECT 'bigserial', 0
+      UNION SELECT 'serial', 0) t1
+      WHERE typname = {{type|qtLiteral}}) AS types
+WHERE oprcom > 0 AND
+      (op.oprleft=types.oid OR op.oprright=types.oid)
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/get_parent.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/get_parent.sql
new file mode 100644
index 0000000..a652857
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/get_parent.sql
@@ -0,0 +1,7 @@
+SELECT nsp.nspname AS schema,
+    rel.relname AS table
+FROM
+    pg_class rel
+JOIN pg_namespace nsp
+ON rel.relnamespace = nsp.oid::int
+WHERE rel.oid = {{tid}}::int
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/nodes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/nodes.sql
new file mode 100644
index 0000000..c67c40d
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/nodes.sql
@@ -0,0 +1,7 @@
+SELECT conindid as oid,
+    conname as name,
+    NOT convalidated as convalidated
+FROM pg_constraint ct
+WHERE contype='x' AND
+    conrelid = {{tid}}::oid
+ORDER BY conname
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/properties.sql
new file mode 100644
index 0000000..3a1c897
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/properties.sql
@@ -0,0 +1,30 @@
+SELECT cls.oid,
+    cls.relname as name,
+    indnatts,
+    amname,
+    COALESCE(spcname, 'pg_default') as spcname,
+    CASE contype
+        WHEN 'p' THEN desp.description
+        WHEN 'u' THEN desp.description
+        WHEN 'x' THEN desp.description
+        ELSE des.description
+    END AS comment,
+    condeferrable,
+    condeferred,
+    substring(array_to_string(cls.reloptions, ',') from 'fillfactor=([0-9]*)') AS fillfactor
+FROM pg_index idx
+JOIN pg_class cls ON cls.oid=indexrelid
+JOIN pg_class tab ON tab.oid=indrelid
+LEFT OUTER JOIN pg_tablespace ta on ta.oid=cls.reltablespace
+JOIN pg_namespace n ON n.oid=tab.relnamespace
+JOIN pg_am am ON am.oid=cls.relam
+LEFT JOIN pg_depend dep ON (dep.classid = cls.tableoid AND dep.objid = cls.oid AND dep.refobjsubid = '0' AND dep.refclassid=(SELECT oid FROM pg_class WHERE relname='pg_constraint') AND dep.deptype='i')
+LEFT OUTER JOIN pg_constraint con ON (con.tableoid = dep.refclassid AND con.oid = dep.refobjid)
+LEFT OUTER JOIN pg_description des ON (des.objoid=cls.oid AND des.classoid='pg_class'::regclass)
+LEFT OUTER JOIN pg_description desp ON (desp.objoid=con.oid AND desp.objsubid = 0 AND desp.classoid='pg_constraint'::regclass)
+WHERE indrelid = {{tid}}::oid
+{% if cid %}
+AND cls.oid = {{cid}}::oid
+{% endif %}
+AND contype='x'
+ORDER BY cls.relname
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/update.sql
new file mode 100644
index 0000000..4d70f21
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.1_plus/update.sql
@@ -0,0 +1,22 @@
+{### SQL to update exclusion constraint object ###}
+{% if data %}
+{# ==== To update exclusion constraint name ==== #}
+{% if data.name != o_data.name %}
+ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }}
+    RENAME CONSTRAINT {{ conn|qtIdent(o_data.name) }} TO {{ conn|qtIdent(data.name) }};
+{% endif %}
+{# ==== To update exclusion constraint tablespace ==== #}
+{% if data.spcname and data.spcname != o_data.spcname %}
+ALTER INDEX {{ conn|qtIdent(data.schema, data.name) }}
+    SET TABLESPACE {{ conn|qtIdent(data.spcname) }};
+{% endif %}
+{% if data.fillfactor and data.fillfactor != o_data.fillfactor %}
+ALTER INDEX {{ conn|qtIdent(data.schema, data.name) }}
+    SET (FILLFACTOR={{ data.fillfactor }});
+{% endif %}
+{# ==== To update exclusion constraint comments ==== #}
+{% if data.comment is defined and data.comment != o_data.comment %}
+COMMENT ON CONSTRAINT {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(data.schema, data.table) }}
+    IS {{ data.comment|qtLiteral }};
+{% endif %}
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/alter.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/alter.sql
new file mode 100644
index 0000000..0fb0ea5
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/alter.sql
@@ -0,0 +1,4 @@
+{% if data.comment %}
+COMMENT ON CONSTRAINT {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(data.schema, data.table) }}
+    IS {{ data.comment|qtLiteral }};
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/begin.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/begin.sql
new file mode 100644
index 0000000..58bfee1
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/begin.sql
@@ -0,0 +1 @@
+BEGIN;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/create.sql
new file mode 100644
index 0000000..c6a53cd
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/create.sql
@@ -0,0 +1,12 @@
+ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }}
+    ADD{% if data.name %} CONSTRAINT {{ conn|qtIdent(data.name) }}{% endif%} EXCLUDE {% if data.amname and data.amname != '' %}USING {{data.amname}}{% endif %} (
+    {% for col in data.columns %}{% if loop.index != 1 %},
+    {% endif %}{{ conn|qtIdent(col.column)}} {% if col.oper_class and col.oper_class != '' %}{{col.oper_class}} {% endif%}{% if col.order %}ASC{% else %}DESC{% endif %} NULLS {% if col.nulls_order %}FIRST{% else %}LAST{% endif %} WITH {{col.operator}}{% endfor %}){% if data.fillfactor %}
+    WITH (FILLFACTOR={{data.fillfactor}}){% endif %}{% if data.spcname and data.spcname != "pg_default" %}
+
+    USING INDEX TABLESPACE {{ conn|qtIdent(data.spcname) }}{% endif %}
+{% if data.condeferrable %}
+
+    DEFERRABLE{% if data.condeferred %}
+ INITIALLY DEFERRED{% endif%}
+{% endif%}{% if data.constraint %} WHERE ({{data.constraint}}){% endif%};
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/delete.sql
new file mode 100644
index 0000000..2096795
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/delete.sql
@@ -0,0 +1,3 @@
+{% if data %}
+ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }} DROP CONSTRAINT {{ conn|qtIdent(data.name) }}{% if cascade%} CASCADE{% endif %};
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/end.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/end.sql
new file mode 100644
index 0000000..92d09d5
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/end.sql
@@ -0,0 +1 @@
+END;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/get_access_methods.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/get_access_methods.sql
new file mode 100644
index 0000000..5d74057
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/get_access_methods.sql
@@ -0,0 +1,6 @@
+SELECT amname
+FROM pg_am
+WHERE EXISTS (SELECT 1
+              FROM pg_proc
+              WHERE oid=amgettuple)
+ORDER BY amname;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/get_constraint_cols.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/get_constraint_cols.sql
new file mode 100644
index 0000000..c119ccb
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/get_constraint_cols.sql
@@ -0,0 +1,22 @@
+{% for n in range(colcnt|int) %}
+{% if loop.index != 1 %}
+UNION
+{% endif %}
+SELECT
+  i.indoption[{{loop.index -1}}] AS options,
+  pg_get_indexdef(i.indexrelid, {{loop.index}}, true) AS coldef,
+  op.oprname,
+  CASE WHEN (o.opcdefault = FALSE) THEN o.opcname ELSE null END AS opcname
+,
+  coll.collname,
+  nspc.nspname as collnspname,
+  format_type(ty.oid,NULL) AS datatype
+FROM pg_index i
+JOIN pg_attribute a ON (a.attrelid = i.indexrelid AND attnum = {{loop.index}})
+JOIN pg_type ty ON ty.oid=a.atttypid
+LEFT OUTER JOIN pg_opclass o ON (o.oid = i.indclass[{{loop.index -1}}])
+LEFT OUTER JOIN pg_constraint c ON (c.conindid = i.indexrelid) LEFT OUTER JOIN pg_operator op ON (op.oid = c.conexclop[{{loop.index}}])
+LEFT OUTER JOIN pg_collation coll ON a.attcollation=coll.oid
+LEFT OUTER JOIN pg_namespace nspc ON coll.collnamespace=nspc.oid
+WHERE i.indexrelid = {{cid}}::oid
+{% endfor %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/get_name.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/get_name.sql
new file mode 100644
index 0000000..7aaa522
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/get_name.sql
@@ -0,0 +1,3 @@
+SELECT conname as name
+FROM pg_constraint ct
+WHERE ct.conindid = {{cid}}::oid
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/get_oid.sql
new file mode 100644
index 0000000..168e13b
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/get_oid.sql
@@ -0,0 +1,4 @@
+SELECT ct.oid
+FROM pg_constraint ct
+WHERE contype='x' AND
+ct.conname = {{ name|qtLiteral }};
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/get_oid_with_transaction.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/get_oid_with_transaction.sql
new file mode 100644
index 0000000..abe636a
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/get_oid_with_transaction.sql
@@ -0,0 +1,6 @@
+SELECT ct.oid,
+    ct.conname as name,
+    NOT convalidated as convalidated
+FROM pg_constraint ct
+WHERE contype='f' AND
+    conrelid = {{tid}}::oid LIMIT 1;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/get_oper_class.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/get_oper_class.sql
new file mode 100644
index 0000000..c6739d0
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/get_oper_class.sql
@@ -0,0 +1,7 @@
+SELECT opcname
+FROM pg_opclass opc,
+pg_am am
+WHERE opcmethod=am.oid AND
+      am.amname ={{indextype|qtLiteral}} AND
+      NOT opcdefault
+ORDER BY 1
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/get_operator.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/get_operator.sql
new file mode 100644
index 0000000..675a7de
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/get_operator.sql
@@ -0,0 +1,30 @@
+SELECT DISTINCT op.oprname as oprname
+FROM pg_operator op,
+( SELECT oid
+  FROM (SELECT format_type(t.oid,NULL) AS typname,
+      t.oid as oid
+      FROM pg_type t
+      JOIN pg_namespace nsp ON typnamespace=nsp.oid
+      WHERE (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) AND
+      typisdefined AND
+      typtype IN ('b', 'c', 'd', 'e', 'r') AND
+      NOT EXISTS (SELECT 1
+                  FROM pg_class
+                  WHERE relnamespace=typnamespace AND
+                  relname = typname AND
+                  relkind != 'c') AND
+      (typname NOT LIKE '_%' OR
+      NOT EXISTS (SELECT 1
+                  FROM pg_class
+                  WHERE relnamespace=typnamespace AND
+                    relname = SUBSTRING(typname FROM 2)::name AND
+                    relkind != 'c'))
+    {% if not show_sysobj %}
+      AND nsp.nspname != 'information_schema'
+    {% endif %}
+      UNION SELECT 'smallserial', 0
+      UNION SELECT 'bigserial', 0
+      UNION SELECT 'serial', 0) t1
+      WHERE typname = {{type|qtLiteral}}) AS types
+WHERE oprcom > 0 AND
+      (op.oprleft=types.oid OR op.oprright=types.oid)
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/get_parent.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/get_parent.sql
new file mode 100644
index 0000000..a652857
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/get_parent.sql
@@ -0,0 +1,7 @@
+SELECT nsp.nspname AS schema,
+    rel.relname AS table
+FROM
+    pg_class rel
+JOIN pg_namespace nsp
+ON rel.relnamespace = nsp.oid::int
+WHERE rel.oid = {{tid}}::int
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/nodes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/nodes.sql
new file mode 100644
index 0000000..c67c40d
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/nodes.sql
@@ -0,0 +1,7 @@
+SELECT conindid as oid,
+    conname as name,
+    NOT convalidated as convalidated
+FROM pg_constraint ct
+WHERE contype='x' AND
+    conrelid = {{tid}}::oid
+ORDER BY conname
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/properties.sql
new file mode 100644
index 0000000..3a1c897
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/properties.sql
@@ -0,0 +1,30 @@
+SELECT cls.oid,
+    cls.relname as name,
+    indnatts,
+    amname,
+    COALESCE(spcname, 'pg_default') as spcname,
+    CASE contype
+        WHEN 'p' THEN desp.description
+        WHEN 'u' THEN desp.description
+        WHEN 'x' THEN desp.description
+        ELSE des.description
+    END AS comment,
+    condeferrable,
+    condeferred,
+    substring(array_to_string(cls.reloptions, ',') from 'fillfactor=([0-9]*)') AS fillfactor
+FROM pg_index idx
+JOIN pg_class cls ON cls.oid=indexrelid
+JOIN pg_class tab ON tab.oid=indrelid
+LEFT OUTER JOIN pg_tablespace ta on ta.oid=cls.reltablespace
+JOIN pg_namespace n ON n.oid=tab.relnamespace
+JOIN pg_am am ON am.oid=cls.relam
+LEFT JOIN pg_depend dep ON (dep.classid = cls.tableoid AND dep.objid = cls.oid AND dep.refobjsubid = '0' AND dep.refclassid=(SELECT oid FROM pg_class WHERE relname='pg_constraint') AND dep.deptype='i')
+LEFT OUTER JOIN pg_constraint con ON (con.tableoid = dep.refclassid AND con.oid = dep.refobjid)
+LEFT OUTER JOIN pg_description des ON (des.objoid=cls.oid AND des.classoid='pg_class'::regclass)
+LEFT OUTER JOIN pg_description desp ON (desp.objoid=con.oid AND desp.objsubid = 0 AND desp.classoid='pg_constraint'::regclass)
+WHERE indrelid = {{tid}}::oid
+{% if cid %}
+AND cls.oid = {{cid}}::oid
+{% endif %}
+AND contype='x'
+ORDER BY cls.relname
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/update.sql
new file mode 100644
index 0000000..4d70f21
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/exclusion_constraint/sql/9.2_plus/update.sql
@@ -0,0 +1,22 @@
+{### SQL to update exclusion constraint object ###}
+{% if data %}
+{# ==== To update exclusion constraint name ==== #}
+{% if data.name != o_data.name %}
+ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }}
+    RENAME CONSTRAINT {{ conn|qtIdent(o_data.name) }} TO {{ conn|qtIdent(data.name) }};
+{% endif %}
+{# ==== To update exclusion constraint tablespace ==== #}
+{% if data.spcname and data.spcname != o_data.spcname %}
+ALTER INDEX {{ conn|qtIdent(data.schema, data.name) }}
+    SET TABLESPACE {{ conn|qtIdent(data.spcname) }};
+{% endif %}
+{% if data.fillfactor and data.fillfactor != o_data.fillfactor %}
+ALTER INDEX {{ conn|qtIdent(data.schema, data.name) }}
+    SET (FILLFACTOR={{ data.fillfactor }});
+{% endif %}
+{# ==== To update exclusion constraint comments ==== #}
+{% if data.comment is defined and data.comment != o_data.comment %}
+COMMENT ON CONSTRAINT {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(data.schema, data.table) }}
+    IS {{ data.comment|qtLiteral }};
+{% endif %}
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/alter.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/alter.sql
new file mode 100644
index 0000000..0fb0ea5
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/alter.sql
@@ -0,0 +1,4 @@
+{% if data.comment %}
+COMMENT ON CONSTRAINT {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(data.schema, data.table) }}
+    IS {{ data.comment|qtLiteral }};
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/begin.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/begin.sql
new file mode 100644
index 0000000..58bfee1
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/begin.sql
@@ -0,0 +1 @@
+BEGIN;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/create.sql
new file mode 100644
index 0000000..7a4eda4
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/create.sql
@@ -0,0 +1,27 @@
+ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }}
+    ADD{% if data.name %} CONSTRAINT {{ conn|qtIdent(data.name) }}{% endif%} FOREIGN KEY ({% for columnobj in data.columns %}{% if loop.index != 1 %}
+, {% endif %}{{ conn|qtIdent(columnobj.local_column)}}{% endfor %})
+    REFERENCES {{ conn|qtIdent(data.remote_schema, data.remote_table) }} ({% for columnobj in data.columns %}{% if loop.index != 1 %}
+, {% endif %}{{ conn|qtIdent(columnobj.referenced)}}{% endfor %}) {% if data.confmatchtype %}MATCH FULL{% else %}MATCH SIMPLE{% endif%}
+
+    ON UPDATE{% if data.confupdtype  == 'a' %}
+ NO ACTION{% elif data.confupdtype  == 'r' %}
+ RESTRICT{% elif data.confupdtype  == 'c' %}
+ CASCADE{% elif data.confupdtype  == 'n' %}
+ SET NULL{% elif data.confupdtype  == 'd' %}
+ SET DEFAULT{% endif %}
+
+    ON DELETE{% if data.confdeltype  == 'a' %}
+ NO ACTION{% elif data.confdeltype  == 'r' %}
+ RESTRICT{% elif data.confdeltype  == 'c' %}
+ CASCADE{% elif data.confdeltype  == 'n' %}
+ SET NULL{% elif data.confdeltype  == 'd' %}
+ SET DEFAULT{% endif %}
+{% if data.condeferrable %}
+
+    DEFERRABLE{% if data.condeferred %}
+ INITIALLY DEFERRED{% endif%}
+{% endif%}
+{% if data.convalidated %}
+
+    NOT VALID{% endif%};
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/create_index.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/create_index.sql
new file mode 100644
index 0000000..f9c1e88
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/create_index.sql
@@ -0,0 +1,5 @@
+{% if data.autoindex %}
+CREATE INDEX {{ conn|qtIdent(data.coveringindex) }}
+    ON {{ conn|qtIdent(data.schema, data.table) }}({% for columnobj in data.columns %}{% if loop.index != 1 %}
+, {% endif %}{{ conn|qtIdent(columnobj.local_column)}}{% endfor %});
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/delete.sql
new file mode 100644
index 0000000..2096795
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/delete.sql
@@ -0,0 +1,3 @@
+{% if data %}
+ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }} DROP CONSTRAINT {{ conn|qtIdent(data.name) }}{% if cascade%} CASCADE{% endif %};
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/end.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/end.sql
new file mode 100644
index 0000000..92d09d5
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/end.sql
@@ -0,0 +1 @@
+END;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/get_cols.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/get_cols.sql
new file mode 100644
index 0000000..4b2fee2
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/get_cols.sql
@@ -0,0 +1,7 @@
+{% for n in range(colcnt|int) %}
+{% if loop.index != 1 %}
+UNION SELECT  pg_get_indexdef({{ cid|string }}, {{ loop.index|string }}, true) AS column
+{% else %}
+SELECT  pg_get_indexdef({{ cid|string }} , {{ loop.index|string }} , true) AS column
+{% endif %}
+{% endfor %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/get_constraint_cols.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/get_constraint_cols.sql
new file mode 100644
index 0000000..a96e575
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/get_constraint_cols.sql
@@ -0,0 +1,13 @@
+{% for keypair in keys %}
+{% if loop.index != 1 %}
+UNION
+{% endif %}
+SELECT a1.attname as conattname,
+    a2.attname as confattname
+FROM pg_attribute a1,
+    pg_attribute a2
+WHERE a1.attrelid={{tid}}::oid
+    AND a1.attnum={{keypair[1]}}
+    AND a2.attrelid={{confrelid}}::oid
+    AND a2.attnum={{keypair[0]}}
+{% endfor %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/get_constraints.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/get_constraints.sql
new file mode 100644
index 0000000..d2f358c
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/get_constraints.sql
@@ -0,0 +1,37 @@
+SELECT   cls.oid, cls.relname as idxname, indnatts
+  FROM pg_index idx
+  JOIN pg_class cls ON cls.oid=indexrelid
+  LEFT JOIN pg_depend dep ON (dep.classid = cls.tableoid AND dep.objid = cls.oid AND dep.refobjsubid = '0' AND dep.refclassid=(SELECT oid FROM pg_class WHERE relname='pg_constraint') AND dep.deptype='i')
+  LEFT OUTER JOIN pg_constraint con ON (con.tableoid = dep.refclassid AND con.oid = dep.refobjid)
+WHERE idx.indrelid = {{tid}}::oid
+    AND con.contype='p'
+
+UNION
+
+SELECT  cls.oid, cls.relname as idxname, indnatts
+    FROM pg_index idx
+    JOIN pg_class cls ON cls.oid=indexrelid
+    LEFT JOIN pg_depend dep ON (dep.classid = cls.tableoid AND dep.objid = cls.oid AND dep.refobjsubid = '0' AND dep.refclassid=(SELECT oid FROM pg_class WHERE relname='pg_constraint') AND dep.deptype='i')
+    LEFT OUTER JOIN pg_constraint con ON (con.tableoid = dep.refclassid AND con.oid = dep.refobjid)
+WHERE idx.indrelid = {{tid}}::oid
+    AND con.contype='x'
+
+UNION
+
+SELECT  cls.oid, cls.relname as idxname, indnatts
+    FROM pg_index idx
+    JOIN pg_class cls ON cls.oid=indexrelid
+    LEFT JOIN pg_depend dep ON (dep.classid = cls.tableoid AND dep.objid = cls.oid AND dep.refobjsubid = '0' AND dep.refclassid=(SELECT oid FROM pg_class WHERE relname='pg_constraint') AND dep.deptype='i')
+    LEFT OUTER JOIN pg_constraint con ON (con.tableoid = dep.refclassid AND con.oid = dep.refobjid)
+WHERE idx.indrelid = {{tid}}::oid
+    AND con.contype='u'
+
+UNION
+
+SELECT  cls.oid, cls.relname as idxname, indnatts
+    FROM pg_index idx
+    JOIN pg_class cls ON cls.oid=indexrelid
+    LEFT JOIN pg_depend dep ON (dep.classid = cls.tableoid AND dep.objid = cls.oid AND dep.refobjsubid = '0' AND dep.refclassid=(SELECT oid FROM pg_class WHERE relname='pg_constraint') AND dep.deptype='i')
+    LEFT OUTER JOIN pg_constraint con ON (con.tableoid = dep.refclassid AND con.oid = dep.refobjid)
+WHERE idx.indrelid = {{tid}}::oid
+   AND conname IS NULL
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/get_name.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/get_name.sql
new file mode 100644
index 0000000..07fdae2
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/get_name.sql
@@ -0,0 +1,3 @@
+SELECT conname as name
+FROM pg_constraint ct
+WHERE ct.oid = {{fkid}}::oid
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/get_oid.sql
new file mode 100644
index 0000000..576c976
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/get_oid.sql
@@ -0,0 +1,5 @@
+SELECT ct.oid,
+    NOT convalidated as convalidated
+FROM pg_constraint ct
+WHERE contype='f' AND
+ct.conname = {{ name|qtLiteral }};
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/get_oid_with_transaction.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/get_oid_with_transaction.sql
new file mode 100644
index 0000000..abe636a
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/get_oid_with_transaction.sql
@@ -0,0 +1,6 @@
+SELECT ct.oid,
+    ct.conname as name,
+    NOT convalidated as convalidated
+FROM pg_constraint ct
+WHERE contype='f' AND
+    conrelid = {{tid}}::oid LIMIT 1;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/get_parent.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/get_parent.sql
new file mode 100644
index 0000000..a652857
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/get_parent.sql
@@ -0,0 +1,7 @@
+SELECT nsp.nspname AS schema,
+    rel.relname AS table
+FROM
+    pg_class rel
+JOIN pg_namespace nsp
+ON rel.relnamespace = nsp.oid::int
+WHERE rel.oid = {{tid}}::int
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/nodes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/nodes.sql
new file mode 100644
index 0000000..9667588
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/nodes.sql
@@ -0,0 +1,7 @@
+SELECT ct.oid,
+    conname as name,
+    NOT convalidated as convalidated
+FROM pg_constraint ct
+WHERE contype='f' AND
+    conrelid = {{tid}}::oid
+ORDER BY conname
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/properties.sql
new file mode 100644
index 0000000..1f506ee
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/properties.sql
@@ -0,0 +1,31 @@
+SELECT ct.oid,
+      conname as name,
+      condeferrable,
+      condeferred,
+      confupdtype,
+      confdeltype,
+      CASE confmatchtype
+        WHEN 's' THEN FALSE
+        WHEN 'f' THEN TRUE
+      END AS confmatchtype,
+      conkey,
+      confkey,
+      confrelid,
+      nl.nspname as fknsp,
+      cl.relname as fktab,
+      nr.nspname as refnsp,
+      cr.relname as reftab,
+      description as comment,
+      NOT convalidated as convalidated
+FROM pg_constraint ct
+JOIN pg_class cl ON cl.oid=conrelid
+JOIN pg_namespace nl ON nl.oid=cl.relnamespace
+JOIN pg_class cr ON cr.oid=confrelid
+JOIN pg_namespace nr ON nr.oid=cr.relnamespace
+LEFT OUTER JOIN pg_description des ON (des.objoid=ct.oid AND des.classoid='pg_constraint'::regclass)
+WHERE contype='f' AND
+conrelid = {{tid}}::oid
+{% if cid %}
+AND ct.oid = {{cid}}::oid
+{% endif %}
+ORDER BY conname
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/update.sql
new file mode 100644
index 0000000..ee8f8a9
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/update.sql
@@ -0,0 +1,18 @@
+{### SQL to update foreign key object ###}
+{% if data %}
+{# ==== To update foreign key name ==== #}
+{% if data.name != o_data.name %}
+ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }}
+    RENAME CONSTRAINT {{ conn|qtIdent(o_data.name) }} TO {{ conn|qtIdent(data.name) }};
+{% endif %}
+{# ==== To update foreign key validate ==== #}
+{% if 'convalidated' in data and o_data.convalidated != data.convalidated and not data.convalidated %}
+ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }}
+    VALIDATE CONSTRAINT {{ conn|qtIdent(data.name) }};
+{% endif %}
+{# ==== To update foreign key comments ==== #}
+{% if data.comment is defined and data.comment != o_data.comment %}
+COMMENT ON CONSTRAINT {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(data.schema, data.table) }}
+    IS {{ data.comment|qtLiteral }};
+{% endif %}
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/validate.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/validate.sql
new file mode 100644
index 0000000..5a62c80
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/validate.sql
@@ -0,0 +1,2 @@
+ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }}
+    VALIDATE CONSTRAINT {{ conn|qtIdent(data.name) }};
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/alter.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/alter.sql
new file mode 100644
index 0000000..68a4444
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/alter.sql
@@ -0,0 +1,11 @@
+{## Alter index to use cluster type ##}
+{% if data.indisclustered %}
+
+ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
+    CLUSTER ON {{conn|qtIdent(data.name)}};
+{% endif %}
+{## Changes description ##}
+{% if data.description is defined %}
+
+COMMENT ON INDEX {{conn|qtIdent(data.schema, data.name)}}
+    IS {{data.description|qtLiteral}};{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/backend_support.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/backend_support.sql
new file mode 100644
index 0000000..6f66ed1
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/backend_support.sql
@@ -0,0 +1,9 @@
+{#=============Checks if it is materialized view========#}
+{% if vid %}
+SELECT
+    CASE WHEN c.relkind = 'm' THEN True ELSE False END As m_view
+FROM
+    pg_class c
+WHERE
+    c.oid = {{ vid }}::oid
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/column_details.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/column_details.sql
new file mode 100644
index 0000000..2cf540a
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/column_details.sql
@@ -0,0 +1,30 @@
+SELECT
+    i.indexrelid,
+    CASE i.indoption[i.attnum - 1]
+    WHEN 0 THEN ARRAY['ASC', 'NULLS LAST']
+    WHEN 1 THEN ARRAY['DESC', 'NULLS FIRST']
+    WHEN 2 THEN ARRAY['ASC', 'NULLS FIRST']
+    WHEN 3 THEN ARRAY['DESC', 'NULLS  ']
+    ELSE ARRAY['UNKNOWN OPTION' || i.indoption[i.attnum - 1], '']
+    END::text[] AS options,
+    i.attnum,
+    pg_get_indexdef(i.indexrelid, i.attnum, true) as attdef,
+    CASE WHEN (o.opcdefault = FALSE) THEN o.opcname ELSE null END AS opcname,
+    op.oprname AS oprname,
+	CASE WHEN length(nspc.nspname) > 0 AND length(coll.collname) > 0  THEN
+	  concat(quote_ident(nspc.nspname), '.', quote_ident(coll.collname))
+	ELSE '' END AS collnspname
+FROM (
+      SELECT
+          indexrelid, i.indoption, i.indclass,
+          unnest(ARRAY(SELECT generate_series(1, i.indnatts) AS n)) AS attnum
+      FROM
+          pg_index i
+      WHERE i.indexrelid = {{idx}}::OID
+) i
+    LEFT JOIN pg_opclass o ON (o.oid = i.indclass[i.attnum - 1])
+    LEFT OUTER JOIN pg_constraint c ON (c.conindid = i.indexrelid)
+    LEFT OUTER JOIN pg_operator op ON (op.oid = c.conexclop[i.attnum])
+    LEFT JOIN pg_attribute a ON (a.attrelid = i.indexrelid AND a.attnum = i.attnum)
+    LEFT OUTER JOIN pg_collation coll ON a.attcollation=coll.oid
+    LEFT OUTER JOIN pg_namespace nspc ON coll.collnamespace=nspc.oid;
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/create.sql
new file mode 100644
index 0000000..b31c827
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/create.sql
@@ -0,0 +1,12 @@
+CREATE {% if data.indisunique %}UNIQUE {% endif %}INDEX {% if data.isconcurrent %}CONCURRENTLY {% endif %}{{conn|qtIdent(data.name)}}
+    ON {{conn|qtIdent(data.schema, data.table)}} {% if data.amname %}USING {{conn|qtIdent(data.amname)}}{% endif %}
+
+    ({% for c in data.columns %}{% if loop.index != 1 %}, {% endif %}{{conn|qtIdent(c.colname)}}{% if c.collspcname %} COLLATE {{c.collspcname}} {% endif %}{% if c.op_class %}
+ {{c.op_class}}{% endif %}{% if c.sort_order is defined %}{% if c.sort_order %} DESC{% else %} ASC{% endif %}{% endif %}{% if c.nulls is defined %} NULLS {% if c.nulls %}
+FIRST{% else %}LAST{% endif %}{% endif %}{% endfor %}){% if data.fillfactor %}
+
+    WITH (FILLFACTOR={{data.fillfactor}}){% endif %}{% if data.spcname %}
+
+    TABLESPACE {{conn|qtIdent(data.spcname)}}{% endif %}{% if data.indconstraint %}
+
+    WHERE {{data.indconstraint}}{% endif %};
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/delete.sql
new file mode 100644
index 0000000..f3808fa
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/delete.sql
@@ -0,0 +1 @@
+DROP INDEX {{conn|qtIdent(data.nspname, data.name)}}{% if cascade %} cascade{% endif %};
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/get_am.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/get_am.sql
new file mode 100644
index 0000000..5bb579b
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/get_am.sql
@@ -0,0 +1,3 @@
+-- Fetches access methods
+SELECT oid, amname
+FROM pg_am
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/get_collations.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/get_collations.sql
new file mode 100644
index 0000000..7418742
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/get_collations.sql
@@ -0,0 +1,7 @@
+SELECT --nspname, collname,
+	CASE WHEN length(nspname) > 0 AND length(collname) > 0  THEN
+	  concat(quote_ident(nspname), '.', quote_ident(collname))
+	ELSE '' END AS collation
+FROM pg_collation c, pg_namespace n
+    WHERE c.collnamespace=n.oid
+    ORDER BY nspname, collname;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/get_oid.sql
new file mode 100644
index 0000000..c32402f
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/get_oid.sql
@@ -0,0 +1,7 @@
+SELECT DISTINCT ON(cls.relname) cls.oid
+FROM pg_index idx
+    JOIN pg_class cls ON cls.oid=indexrelid
+    JOIN pg_class tab ON tab.oid=indrelid
+    JOIN pg_namespace n ON n.oid=tab.relnamespace
+WHERE indrelid = {{tid}}::OID
+    AND cls.relname = {{data.name|qtLiteral}};
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/get_op_class.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/get_op_class.sql
new file mode 100644
index 0000000..af0133a
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/get_op_class.sql
@@ -0,0 +1,5 @@
+SELECT opcname,  opcmethod
+FROM pg_opclass
+    WHERE opcmethod = {{oid}}::OID
+    AND NOT opcdefault
+    ORDER BY 1;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/get_parent.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/get_parent.sql
new file mode 100644
index 0000000..5dd5d3c
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/get_parent.sql
@@ -0,0 +1,5 @@
+SELECT nsp.nspname AS schema ,rel.relname AS table
+FROM pg_class rel
+    JOIN pg_namespace nsp
+    ON rel.relnamespace = nsp.oid::int
+    WHERE rel.oid = {{tid}}::int
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/nodes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/nodes.sql
new file mode 100644
index 0000000..9e9c948
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/nodes.sql
@@ -0,0 +1,12 @@
+SELECT DISTINCT ON(cls.relname) cls.oid, cls.relname as name
+FROM pg_index idx
+    JOIN pg_class cls ON cls.oid=indexrelid
+    JOIN pg_class tab ON tab.oid=indrelid
+    LEFT OUTER JOIN pg_tablespace ta on ta.oid=cls.reltablespace
+    JOIN pg_namespace n ON n.oid=tab.relnamespace
+    JOIN pg_am am ON am.oid=cls.relam
+    LEFT JOIN pg_depend dep ON (dep.classid = cls.tableoid AND dep.objid = cls.oid AND dep.refobjsubid = '0' AND dep.refclassid=(SELECT oid FROM pg_class WHERE relname='pg_constraint') AND dep.deptype='i')
+    LEFT OUTER JOIN pg_constraint con ON (con.tableoid = dep.refclassid AND con.oid = dep.refobjid)
+WHERE indrelid = {{tid}}::OID
+    AND conname is NULL
+    ORDER BY cls.relname
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/properties.sql
new file mode 100644
index 0000000..2641d4c
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/properties.sql
@@ -0,0 +1,22 @@
+SELECT DISTINCT ON(cls.relname) cls.oid, cls.relname as name, indrelid, indkey, indisclustered,
+    indisvalid, indisunique, indisprimary, n.nspname,indnatts,cls.reltablespace AS spcoid,
+    COALESCE(spcname, 'pg_default') as spcname, tab.relname as tabname, indclass, con.oid AS conoid,
+    CASE WHEN contype IN ('p', 'u', 'x') THEN desp.description
+         ELSE des.description END AS description,
+    pg_get_expr(indpred, indrelid, true) as indconstraint, contype, condeferrable, condeferred, amname,
+    substring(array_to_string(cls.reloptions, ',') from 'fillfactor=([0-9]*)') AS fillfactor
+    {% if datlastsysoid %}, (CASE WHEN cls.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_idx {% endif %}
+FROM pg_index idx
+    JOIN pg_class cls ON cls.oid=indexrelid
+    JOIN pg_class tab ON tab.oid=indrelid
+    LEFT OUTER JOIN pg_tablespace ta on ta.oid=cls.reltablespace
+    JOIN pg_namespace n ON n.oid=tab.relnamespace
+    JOIN pg_am am ON am.oid=cls.relam
+    LEFT JOIN pg_depend dep ON (dep.classid = cls.tableoid AND dep.objid = cls.oid AND dep.refobjsubid = '0' AND dep.refclassid=(SELECT oid FROM pg_class WHERE relname='pg_constraint') AND dep.deptype='i')
+    LEFT OUTER JOIN pg_constraint con ON (con.tableoid = dep.refclassid AND con.oid = dep.refobjid)
+    LEFT OUTER JOIN pg_description des ON (des.objoid=cls.oid AND des.classoid='pg_class'::regclass)
+    LEFT OUTER JOIN pg_description desp ON (desp.objoid=con.oid AND desp.objsubid = 0 AND desp.classoid='pg_constraint'::regclass)
+WHERE indrelid = {{tid}}::OID
+    AND conname is NULL
+    {% if idx %}AND cls.oid = {{idx}}::OID {% endif %}
+    ORDER BY cls.relname
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/update.sql
new file mode 100644
index 0000000..f2acd6c
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index/sql/9.1_plus/update.sql
@@ -0,0 +1,24 @@
+{## Changes name ##}
+{% if data.name and o_data.name != data.name %}
+ALTER INDEX {{conn|qtIdent(data.schema, o_data.name)}}
+    RENAME TO {{conn|qtIdent(data.name)}};
+{% endif %}
+{## Changes fillfactor ##}
+{% if data.fillfactor and o_data.fillfactor != data.fillfactor %}
+ALTER INDEX {{conn|qtIdent(data.schema, data.name)}}
+    SET (FILLFACTOR={{data.fillfactor}});
+{% endif %}
+{## Changes tablespace ##}
+{% if data.spcname and o_data.spcname != data.spcname %}
+ALTER INDEX {{conn|qtIdent(data.schema, data.name)}}
+    SET TABLESPACE {{conn|qtIdent(data.spcname)}};
+{% endif %}
+{## Alter index to use cluster type ##}
+{% if data.indisclustered is defined and o_data.indisclustered != data.indisclustered %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
+    CLUSTER ON {{conn|qtIdent(data.name)}};
+{% endif %}
+{## Changes description ##}
+{% if data.description is defined and o_data.description != data.description %}
+COMMENT ON INDEX {{conn|qtIdent(data.schema, data.name)}}
+    IS {{data.description|qtLiteral}};{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/alter.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/alter.sql
new file mode 100644
index 0000000..0fb0ea5
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/alter.sql
@@ -0,0 +1,4 @@
+{% if data.comment %}
+COMMENT ON CONSTRAINT {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(data.schema, data.table) }}
+    IS {{ data.comment|qtLiteral }};
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/begin.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/begin.sql
new file mode 100644
index 0000000..58bfee1
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/begin.sql
@@ -0,0 +1 @@
+BEGIN;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/create.sql
new file mode 100644
index 0000000..61a717e
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/create.sql
@@ -0,0 +1,12 @@
+ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }}
+    ADD{% if data.name %} CONSTRAINT {{ conn|qtIdent(data.name) }}{% endif%} {{constraint_name}} {% if data.index %}USING INDEX {{ conn|qtIdent(data.index) }}{% else %}
+({% for columnobj in data.columns %}{% if loop.index != 1 %}
+, {% endif %}{{ conn|qtIdent(columnobj.column)}}{% endfor %}){% if data.fillfactor %}
+
+    WITH (FILLFACTOR={{data.fillfactor}}){% endif %}{% if data.spcname and data.spcname != "pg_default" %}
+
+    USING INDEX TABLESPACE {{ conn|qtIdent(data.spcname) }}{% endif %}{% endif %}{% if data.condeferrable %}
+
+    DEFERRABLE{% if data.condeferred %}
+ INITIALLY DEFERRED{% endif%}
+{% endif%};
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/delete.sql
new file mode 100644
index 0000000..2096795
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/delete.sql
@@ -0,0 +1,3 @@
+{% if data %}
+ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }} DROP CONSTRAINT {{ conn|qtIdent(data.name) }}{% if cascade%} CASCADE{% endif %};
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/end.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/end.sql
new file mode 100644
index 0000000..92d09d5
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/end.sql
@@ -0,0 +1 @@
+END;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/get_constraint_cols.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/get_constraint_cols.sql
new file mode 100644
index 0000000..4b2fee2
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/get_constraint_cols.sql
@@ -0,0 +1,7 @@
+{% for n in range(colcnt|int) %}
+{% if loop.index != 1 %}
+UNION SELECT  pg_get_indexdef({{ cid|string }}, {{ loop.index|string }}, true) AS column
+{% else %}
+SELECT  pg_get_indexdef({{ cid|string }} , {{ loop.index|string }} , true) AS column
+{% endif %}
+{% endfor %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/get_indices.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/get_indices.sql
new file mode 100644
index 0000000..b9cab21
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/get_indices.sql
@@ -0,0 +1,3 @@
+SELECT relname FROM pg_class, pg_index
+WHERE pg_class.oid=indexrelid
+AND indrelid={{ tid }}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/get_name.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/get_name.sql
new file mode 100644
index 0000000..a1beafb
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/get_name.sql
@@ -0,0 +1,15 @@
+SELECT cls.relname as name
+FROM pg_index idx
+JOIN pg_class cls ON cls.oid=indexrelid
+LEFT JOIN pg_depend dep ON (dep.classid = cls.tableoid AND
+                            dep.objid = cls.oid AND
+                            dep.refobjsubid = '0'
+                            AND dep.refclassid=(SELECT oid
+                                                FROM pg_class
+                                                WHERE relname='pg_constraint') AND
+                            dep.deptype='i')
+LEFT OUTER JOIN pg_constraint con ON (con.tableoid = dep.refclassid AND
+                                      con.oid = dep.refobjid)
+WHERE indrelid = {{tid}}::oid
+AND contype='{{constraint_type}}'
+AND cls.oid = {{cid}}::oid;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/get_oid.sql
new file mode 100644
index 0000000..861ff50
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/get_oid.sql
@@ -0,0 +1,4 @@
+SELECT ct.conindid as oid
+FROM pg_constraint ct
+WHERE contype='{{constraint_type}}' AND
+ct.conname = {{ name|qtLiteral }};
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/get_oid_with_transaction.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/get_oid_with_transaction.sql
new file mode 100644
index 0000000..9ad8020
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/get_oid_with_transaction.sql
@@ -0,0 +1,5 @@
+SELECT ct.conindid as oid,
+    ct.conname as name
+FROM pg_constraint ct
+WHERE contype='{{constraint_type}}' AND
+    conrelid = {{tid}}::oid LIMIT 1;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/get_parent.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/get_parent.sql
new file mode 100644
index 0000000..a652857
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/get_parent.sql
@@ -0,0 +1,7 @@
+SELECT nsp.nspname AS schema,
+    rel.relname AS table
+FROM
+    pg_class rel
+JOIN pg_namespace nsp
+ON rel.relnamespace = nsp.oid::int
+WHERE rel.oid = {{tid}}::int
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/nodes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/nodes.sql
new file mode 100644
index 0000000..ed96b44
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/nodes.sql
@@ -0,0 +1,14 @@
+SELECT cls.oid, cls.relname as name
+FROM pg_index idx
+JOIN pg_class cls ON cls.oid=indexrelid
+LEFT JOIN pg_depend dep ON (dep.classid = cls.tableoid AND
+                            dep.objid = cls.oid AND
+                            dep.refobjsubid = '0' AND
+                            dep.refclassid=(SELECT oid
+                                            FROM pg_class
+                                            WHERE relname='pg_constraint') AND
+                            dep.deptype='i')
+LEFT OUTER JOIN pg_constraint con ON (con.tableoid = dep.refclassid AND
+                                      con.oid = dep.refobjid)
+WHERE indrelid = {{tid}}::oid
+AND contype='{{constraint_type}}'
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/properties.sql
new file mode 100644
index 0000000..0eabdd7
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/properties.sql
@@ -0,0 +1,29 @@
+SELECT cls.oid,
+    cls.relname as name,
+    indnatts,
+    COALESCE(spcname, 'pg_default') as spcname,
+    CASE contype
+        WHEN 'p' THEN desp.description
+        WHEN 'u' THEN desp.description
+        WHEN 'x' THEN desp.description
+        ELSE des.description
+    END AS comment,
+    condeferrable,
+    condeferred,
+    substring(array_to_string(cls.reloptions, ',') from 'fillfactor=([0-9]*)') AS fillfactor
+FROM pg_index idx
+JOIN pg_class cls ON cls.oid=indexrelid
+JOIN pg_class tab ON tab.oid=indrelid
+LEFT OUTER JOIN pg_tablespace ta on ta.oid=cls.reltablespace
+JOIN pg_namespace n ON n.oid=tab.relnamespace
+JOIN pg_am am ON am.oid=cls.relam
+LEFT JOIN pg_depend dep ON (dep.classid = cls.tableoid AND dep.objid = cls.oid AND dep.refobjsubid = '0' AND dep.refclassid=(SELECT oid FROM pg_class WHERE relname='pg_constraint') AND dep.deptype='i')
+LEFT OUTER JOIN pg_constraint con ON (con.tableoid = dep.refclassid AND con.oid = dep.refobjid)
+LEFT OUTER JOIN pg_description des ON (des.objoid=cls.oid AND des.classoid='pg_class'::regclass)
+LEFT OUTER JOIN pg_description desp ON (desp.objoid=con.oid AND desp.objsubid = 0 AND desp.classoid='pg_constraint'::regclass)
+WHERE indrelid = {{tid}}::oid
+{% if cid %}
+AND cls.oid = {{cid}}::oid
+{% endif %}
+AND contype='{{constraint_type}}'
+ORDER BY cls.relname
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/update.sql
new file mode 100644
index 0000000..6618532
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/index_constraint/sql/update.sql
@@ -0,0 +1,22 @@
+{### SQL to update constraint object ###}
+{% if data %}
+{# ==== To update constraint name ==== #}
+{% if data.name != o_data.name %}
+ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }}
+    RENAME CONSTRAINT {{ conn|qtIdent(o_data.name) }} TO {{ conn|qtIdent(data.name) }};
+{% endif %}
+{# ==== To update constraint tablespace ==== #}
+{% if data.spcname and data.spcname != o_data.spcname %}
+ALTER INDEX {{ conn|qtIdent(data.schema, data.name) }}
+    SET TABLESPACE {{ conn|qtIdent(data.spcname) }};
+{% endif %}
+{% if data.fillfactor and data.fillfactor != o_data.fillfactor %}
+ALTER INDEX {{ conn|qtIdent(data.schema, data.name) }}
+    SET (FILLFACTOR={{ data.fillfactor }});
+{% endif %}
+{# ==== To update constraint comments ==== #}
+{% if data.comment is defined and data.comment != o_data.comment %}
+COMMENT ON CONSTRAINT {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(data.schema, data.table) }}
+    IS {{ data.comment|qtLiteral }};
+{% endif %}
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/rules/sql/backend_support.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/rules/sql/backend_support.sql
new file mode 100644
index 0000000..bb5e8d8
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/rules/sql/backend_support.sql
@@ -0,0 +1,9 @@
+{#=============Checks if it is materialized view========#}
+{% if vid %}
+SELECT
+    CASE WHEN c.relkind = 'm' THEN False ELSE True END As m_view
+FROM
+    pg_class c
+WHERE
+    c.oid = {{ vid }}::oid
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/rules/sql/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/rules/sql/create.sql
new file mode 100644
index 0000000..fad2c7a
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/rules/sql/create.sql
@@ -0,0 +1,27 @@
+{# ============Create Rule============= #}
+{% if display_comments %}
+-- Rule: {{ data.name }} ON {{ conn|qtIdent(data.schema, data.name) }}
+
+-- DROP Rule {{ data.name }} ON {{ conn|qtIdent(data.schema, data.name) }};
+
+{% endif %}
+{% if data.name and data.schema and data.view %}
+CREATE OR REPLACE RULE {{ conn|qtIdent(data.name) }} AS
+    ON {{ data.event|upper if data.event else 'SELECT' }} TO {{ conn|qtIdent(data.schema, data.view) }}
+{% if data.condition %}
+    WHERE {{ data.condition }}
+{% endif %}
+    DO{% if data.do_instead in ['true', True] %}
+{{ ' INSTEAD' }}
+{% else %}
+{{ '' }}
+{% endif %}
+{% if data.statements %}
+{{ data.statements.rstrip(';') }};
+{% else %}
+  NOTHING;
+{% endif %}
+{% if data.comment %}
+
+COMMENT ON RULE {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(data.schema, data.view) }} IS {{ data.comment|qtLiteral }};{% endif %}
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/rules/sql/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/rules/sql/delete.sql
new file mode 100644
index 0000000..cf18913
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/rules/sql/delete.sql
@@ -0,0 +1,16 @@
+{# ======== Drop/Cascade Rule ========= #}
+{% if rid %}
+SELECT
+    rw.rulename,
+    cl.relname,
+    nsp.nspname
+FROM
+    pg_rewrite rw
+JOIN pg_class cl ON cl.oid=rw.ev_class
+JOIN pg_namespace nsp ON nsp.oid=cl.relnamespace
+WHERE
+    rw.oid={{ rid }};
+{% endif %}
+{% if rulename and relname and nspname %}
+DROP RULE {{ conn|qtIdent(rulename) }} ON {{ conn|qtIdent(nspname, relname) }} {% if cascade %} CASCADE {% endif %};
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/rules/sql/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/rules/sql/properties.sql
new file mode 100644
index 0000000..afdd139
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/rules/sql/properties.sql
@@ -0,0 +1,27 @@
+{# =================== Fetch Rules ==================== #}
+{% if tid or rid %}
+SELECT
+    rw.oid AS oid,
+    rw.rulename AS name,
+    relname AS view,
+    CASE WHEN relkind = 'r' THEN TRUE ELSE FALSE END AS parentistable,
+    nspname AS schema,
+    description AS comment,
+    {# ===== Check whether it is system rule or not ===== #}
+    CASE WHEN rw.rulename = '_RETURN' THEN True ELSE False END AS system_rule,
+    CASE WHEN rw.ev_enabled != 'D' THEN True ELSE False END AS enabled,
+    pg_get_ruledef(rw.oid, true) AS definition
+FROM
+    pg_rewrite rw
+JOIN pg_class cl ON cl.oid=rw.ev_class
+JOIN pg_namespace nsp ON nsp.oid=cl.relnamespace
+LEFT OUTER JOIN pg_description des ON (des.objoid=rw.oid AND des.classoid='pg_rewrite'::regclass)
+WHERE
+  {% if tid %}
+      ev_class = {{ tid }}
+  {% elif rid %}
+      rw.oid = {{ rid }}
+  {% endif %}
+ORDER BY
+    rw.rulename
+ {% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/rules/sql/rule_id.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/rules/sql/rule_id.sql
new file mode 100644
index 0000000..3dc6dba
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/rules/sql/rule_id.sql
@@ -0,0 +1,9 @@
+{#========Below will provide rule id for last created rule========#}
+{% if rule_name %}
+SELECT
+    rw.oid
+FROM
+    pg_rewrite rw
+WHERE
+    rw.rulename={{ rule_name|qtLiteral }}
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/rules/sql/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/rules/sql/update.sql
new file mode 100644
index 0000000..099d6e4
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/rules/sql/update.sql
@@ -0,0 +1,33 @@
+{# ===== Update Rule ===== #}
+{% if data.name is defined %}
+{% set rule_name = data.name %}
+{% else %}
+{% set rule_name = o_data.name %}
+{% endif %}
+{% if data.name and data.name != o_data.name %}
+ALTER RULE {{ conn|qtIdent(o_data.name) }} ON {{ conn|qtIdent(o_data.schema, o_data.view) }} RENAME TO {{ conn|qtIdent(data.name) }};{{ '\r\r' }}
+{% endif %}
+{% if data.event or data.do_instead or data.condition or data.statements %}
+CREATE OR REPLACE RULE {{ conn|qtIdent(rule_name) }} AS
+    ON {% if data.event and data.event != o_data.event %}{{ data.event|upper }}{% else %}{{ o_data.event|upper }}{% endif %}
+ TO {{ conn|qtIdent(o_data.schema, o_data.view) }}
+{% if data.condition and o_data.condition != data.condition %}
+    WHERE {{ data.condition }}
+{% elif data.condition is not defined and o_data.condition %}
+    WHERE {{ o_data.condition }}
+{% endif %}
+    DO {% if (('do_instead' not in data and o_data.do_instead in ['true', True]) or (data.do_instead in ['true', True])) %}{{ 'INSTEAD' }}{% endif %}
+{% if data.statements and data.statements != o_data.statements %}
+
+{{ data.statements.rstrip(';') }};
+{% elif data.statements is not defined and o_data.statements %}
+
+{{ o_data.statements.rstrip(';') }};
+{% else %}
+ NOTHING;
+{% endif %}
+
+{% endif %}
+{% set old_comment = o_data.comment|default('', true) %}
+{% if (data.comment is defined and (data.comment != old_comment)) %}
+COMMENT ON RULE {{ conn|qtIdent(rule_name) }} ON {{ conn|qtIdent(o_data.schema, o_data.view) }} IS {{ data.comment|qtLiteral }};{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/js/table.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/js/table.js
new file mode 100644
index 0000000..ae2b40f
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/js/table.js
@@ -0,0 +1,954 @@
+define(
+    [
+    'jquery', 'underscore', 'underscore.string', 'pgadmin',
+    'pgadmin.browser', 'alertify', 'pgadmin.browser.collection',
+    'pgadmin.node.column', 'pgadmin.node.constraints'
+    ],
+function($, _, S, pgAdmin, pgBrowser, alertify) {
+
+  if (!pgBrowser.Nodes['coll-table']) {
+    var databases = pgAdmin.Browser.Nodes['coll-table'] =
+      pgAdmin.Browser.Collection.extend({
+        node: 'table',
+        label: '{{ _('Tables') }}',
+        type: 'coll-table',
+        columns: ['name', 'relowner', 'description']
+      });
+  };
+
+  if (!pgBrowser.Nodes['table']) {
+    pgAdmin.Browser.Nodes['table'] = pgBrowser.Node.extend({
+      type: 'table',
+      label: '{{ _('Table') }}',
+      collection_type: 'coll-table',
+      hasSQL: true,
+      hasDepends: true,
+      sqlAlterHelp: 'sql-altertable.html',
+      sqlCreateHelp: 'sql-createtable.html',
+      parent_type: ['schema', 'catalog'],
+      hasScriptTypes: ['create', 'select', 'insert', 'update', 'delete'],
+      Init: function() {
+        /* Avoid mulitple registration of menus */
+        if (this.initialized)
+            return;
+
+        this.initialized = true;
+
+        pgBrowser.add_menus([{
+          name: 'create_table_on_coll', node: 'coll-table', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 1, label: '{{ _('Table...') }}',
+          icon: 'wcTabIcon icon-table', data: {action: 'create', check: true},
+          enable: 'canCreate'
+        },{
+          name: 'create_table', node: 'table', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 1, label: '{{ _('Table...') }}',
+          icon: 'wcTabIcon icon-table', data: {action: 'create', check: true},
+          enable: 'canCreate'
+        },{
+          name: 'create_table__on_schema', node: 'schema', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('Table...') }}',
+          icon: 'wcTabIcon icon-table', data: {action: 'create', check: false},
+          enable: 'canCreate'
+        },{
+          name: 'truncate_table', node: 'table', module: this,
+          applies: ['object', 'context'], callback: 'truncate_table',
+          category: 'Truncate', priority: 3, label: '{{ _('Truncate') }}',
+          icon: 'fa fa-eraser', enable : 'canCreate'
+        },{
+          name: 'truncate_table_cascade', node: 'table', module: this,
+          applies: ['object', 'context'], callback: 'truncate_table_cascade',
+          category: 'Truncate', priority: 3, label: '{{ _('Truncate Cascade') }}',
+          icon: 'fa fa-eraser', enable : 'canCreate'
+        },{
+          // To enable/disable all triggers for the table
+          name: 'enable_all_triggers', node: 'table', module: this,
+          applies: ['object', 'context'], callback: 'enable_triggers_on_table',
+          category: 'Trigger(s)', priority: 4, label: '{{ _('Enable All') }}',
+          icon: 'fa fa-check', enable : 'canCreate_with_trigger_enable'
+        },{
+          name: 'disable_all_triggers', node: 'table', module: this,
+          applies: ['object', 'context'], callback: 'disable_triggers_on_table',
+          category: 'Trigger(s)', priority: 4, label: '{{ _('Disable All') }}',
+          icon: 'fa fa-times', enable : 'canCreate_with_trigger_disable'
+        },{
+          name: 'reset_table_stats', node: 'table', module: this,
+          applies: ['object', 'context'], callback: 'reset_table_stats',
+          category: 'Reset', priority: 4, label: '{{ _('Reset statistics') }}',
+          icon: 'fa fa-bar-chart', enable : 'canCreate'
+        }
+        ]);
+      },
+      canDrop: pgBrowser.Nodes['schema'].canChildDrop,
+      canDropCascade: pgBrowser.Nodes['schema'].canChildDrop,
+      callbacks: {
+        /* Enable trigger(s) on table */
+        enable_triggers_on_table: function(args) {
+            var params = {'enable': true };
+            this.callbacks.set_triggers.apply(this, [args, params]);
+        },
+        /* Disable trigger(s) on table */
+        disable_triggers_on_table: function(args) {
+            var params = {'enable': false };
+            this.callbacks.set_triggers.apply(this, [args, params]);
+        },
+        set_triggers: function(args, params) {
+          // This function will send request to enable or
+          // disable triggers on table level
+          var input = args || {};
+          obj = this,
+          t = pgBrowser.tree,
+          i = input.item || t.selected(),
+          d = i && i.length == 1 ? t.itemData(i) : undefined;
+          if (!d)
+            return false;
+
+          $.ajax({
+            url: obj.generate_url(i, 'set_trigger' , d, true),
+            type:'PUT',
+            data: params,
+            dataType: "json",
+            success: function(res) {
+              if (res.success == 1) {
+                alertify.success("{{ _('" + res.info + "') }}");
+                t.unload(i);
+                t.setInode(i);
+                t.deselect(i);
+                setTimeout(function() {
+                  t.select(i);
+                }, 10);
+              }
+            },
+            error: function(xhr, status, error) {
+              try {
+                var err = $.parseJSON(xhr.responseText);
+                if (err.success == 0) {
+                  msg = S('{{ _(' + err.errormsg + ')}}').value();
+                  alertify.error("{{ _('" + err.errormsg + "') }}");
+                }
+              } catch (e) {}
+              t.unload(i);
+            }
+          });
+        },
+        /* Truncate table */
+        truncate_table: function(args) {
+            var params = {'cascade': false };
+            this.callbacks.truncate.apply(this, [args, params]);
+        },
+        /* Truncate table with cascade */
+        truncate_table_cascade: function(args) {
+            var params = {'cascade': true };
+            this.callbacks.truncate.apply(this, [args, params]);
+        },
+        truncate: function(args, params) {
+          var input = args || {};
+          obj = this,
+          t = pgBrowser.tree,
+          i = input.item || t.selected(),
+          d = i && i.length == 1 ? t.itemData(i) : undefined;
+
+          if (!d)
+            return false;
+
+          alertify.confirm(
+            S('{{ _('Are you sure you want to truncate table - %%s ?') }}').sprintf(d.label).value(),
+            function (e) {
+            if (e) {
+              var data = d;
+              $.ajax({
+                url: obj.generate_url(i, 'truncate' , d, true),
+                type:'PUT',
+                data: params,
+                dataType: "json",
+                success: function(res) {
+                  if (res.success == 1) {
+                    alertify.success("{{ _('" + res.info + "') }}");
+                    t.removeIcon(i);
+                    data.icon = 'icon-table';
+                    t.addIcon(i, {icon: data.icon});
+                    t.unload(i);
+                    t.setInode(i);
+                    t.deselect(i);
+                    // Fetch updated data from server
+                    setTimeout(function() {
+                      t.select(i);
+                    }, 10);
+                  }
+                },
+                error: function(xhr, status, error) {
+                  try {
+                    var err = $.parseJSON(xhr.responseText);
+                    if (err.success == 0) {
+                      msg = S('{{ _(' + err.errormsg + ')}}').value();
+                      alertify.error("{{ _('" + err.errormsg + "') }}");
+                    }
+                  } catch (e) {}
+                  t.unload(i);
+                }
+              });
+            }
+         });
+       },
+       reset_table_stats: function(args) {
+          var input = args || {};
+          obj = this,
+          t = pgBrowser.tree,
+          i = input.item || t.selected(),
+          d = i && i.length == 1 ? t.itemData(i) : undefined;
+
+          if (!d)
+            return false;
+
+          alertify.confirm(
+            S('{{ _('Are you sure you want to reset table statistics - %%s ?') }}').sprintf(d.label).value(),
+            function (e) {
+            if (e) {
+              var data = d;
+              $.ajax({
+                url: obj.generate_url(i, 'reset' , d, true),
+                type:'DELETE',
+                success: function(res) {
+                  if (res.success == 1) {
+                    alertify.success("{{ _('" + res.info + "') }}");
+                    t.removeIcon(i);
+                    data.icon = 'icon-table';
+                    t.addIcon(i, {icon: data.icon});
+                    t.unload(i);
+                    t.setInode(i);
+                    t.deselect(i);
+                    // Fetch updated data from server
+                    setTimeout(function() {
+                      t.select(i);
+                    }, 10);
+                  }
+                },
+                error: function(xhr, status, error) {
+                  try {
+                    var err = $.parseJSON(xhr.responseText);
+                    if (err.success == 0) {
+                      msg = S('{{ _(' + err.errormsg + ')}}').value();
+                      alertify.error("{{ _('" + err.errormsg + "') }}");
+                    }
+                  } catch (e) {}
+                  t.unload(i);
+                }
+              });
+            }
+         });
+       }
+      },
+      model: pgAdmin.Browser.Node.Model.extend({
+        defaults: {
+          name: undefined,
+          oid: undefined,
+          spcoid: undefined,
+          spcname: 'pg_default',
+          relowner: undefined,
+          relacl: undefined,
+          relhasoids: undefined,
+          relhassubclass: undefined,
+          reltuples: undefined,
+          description: undefined,
+          conname: undefined,
+          conkey: undefined,
+          isrepl: undefined,
+          triggercount: undefined,
+          relpersistence: undefined,
+          fillfactor: undefined,
+          reloftype: undefined,
+          typname: undefined,
+          labels: undefined,
+          providers: undefined,
+          is_sys_table: undefined,
+          coll_inherits: [],
+          hastoasttable: true,
+          toast_autovacuum_enabled: false,
+          autovacuum_enabled: false,
+          primary_key: []
+       },
+        // Default values!
+        initialize: function(attrs, args) {
+          var self = this,
+              isNew = (_.size(attrs) === 0);
+
+          if (isNew) {
+            var userInfo = pgBrowser.serverInfo[args.node_info.server._id].user;
+            var schemaInfo = args.node_info.schema;
+
+            this.set({'relowner': userInfo.name}, {silent: true});
+            this.set({'schema': schemaInfo.label}, {silent: true});
+          }
+          pgAdmin.Browser.Node.Model.prototype.initialize.apply(this, arguments);
+
+        },
+        schema: [{
+          id: 'name', label: '{{ _('Name') }}', cell: 'string',
+          type: 'text', mode: ['properties', 'create', 'edit'],
+          disabled: 'inSchema'
+        },{
+          id: 'oid', label:'{{ _('OID') }}', cell: 'string',
+          type: 'text' , mode: ['properties']
+        },{
+          id: 'relowner', label:'{{ _('Owner') }}', cell: 'string',
+          type: 'text', mode: ['properties', 'create', 'edit'],
+          disabled: 'inSchema', control: 'node-list-by-name',
+          node: 'role', select2: { allowClear: false }
+        },{
+          id: 'schema', label:'{{ _('Schema') }}', cell: 'string',
+          control: 'node-list-by-name',
+          type: 'text', mode: ['create', 'edit'], node: 'schema',
+          disabled: 'inSchema', filter: function(d) {
+            // If schema name start with pg_* then we need to exclude them
+            if(d && d.label.match(/^pg_/))
+            {
+              return false;
+            }
+            return true;
+          }
+        },{
+          id: 'spcname', label:'{{ _('Tablespace') }}', cell: 'string', control: 'node-list-by-name',
+          type: 'text', mode: ['properties', 'create', 'edit'], node: 'tablespace',
+          disabled: 'inSchema', select2:{allowClear:false},
+          filter: function(d) {
+            // If tablespace name is not "pg_global" then we need to exclude them
+            if(d && d.label.match(/pg_global/))
+            {
+              return false;
+            }
+            return true;
+          }
+        },{
+          id: 'description', label:'{{ _('Comment') }}', cell: 'string',
+          type: 'multiline', mode: ['properties', 'create', 'edit'],
+          disabled: 'inSchema'
+        },{
+          id: 'typname', label:'{{ _('Of type') }}', cell: 'string', control: 'node-ajax-options',
+          type: 'text', mode: ['properties', 'create', 'edit'],
+          disabled: 'checkOfType', url: 'get_oftype', group: '{{ _('Advanced') }}', deps: ['coll_inherits'],
+          transform: function(data, cell) {
+            var control = cell || this,
+              m = control.model;
+              m.of_types_tables = data;
+              return data;
+          },
+          control: Backform.NodeAjaxOptionsControl.extend({
+              // When of_types changes we need to clear columns collection
+              onChange: function() {
+                Backform.NodeAjaxOptionsControl.prototype.onChange.apply(this, arguments);
+                var self = this,
+                  tbl_oid = undefined,
+                  tbl_name = self.model.get('typname'),
+                  data = undefined,
+                  arg = undefined,
+                  column_collection = self.model.get('columns');
+
+                if (!_.isUndefined(tbl_name) &&
+                    tbl_name !== '' && column_collection.length !== 0) {
+                  var msg = '{{ _('Changing of type table will clear columns collection') }}';
+                  alertify.confirm(msg, function (e) {
+                    if (e) {
+                      // User clicks Ok, lets clear columns collection
+                      column_collection.reset();
+                    } else {
+                      return this;
+                    }
+                  });
+                } else if (!_.isUndefined(tbl_name) && tbl_name === '') {
+                  column_collection.reset();
+                }
+
+                // Run Ajax now to fetch columns
+                if (!_.isUndefined(tbl_name) && tbl_name !== '') {
+                  arg = { 'tname': tbl_name }
+                  data = self.model.fetch_columns_ajax.apply(self, [arg]);
+                  // Add into column collection
+                  column_collection.set(data, { merge:false,remove:false });
+                }
+              }
+            })
+        },{
+          id: 'fillfactor', label:'{{ _('Fill factor') }}', cell: 'integer',
+          type: 'int', mode: ['create', 'edit'], min: 10, max: 100,
+          disabled: 'inSchema',group: '{{ _('Advanced') }}'
+        },{
+          id: 'relhasoids', label:'{{ _('Has OIDs?') }}', cell: 'switch',
+          type: 'switch', mode: ['properties', 'create', 'edit'],
+          disabled: 'inSchema', group: '{{ _('Advanced') }}'
+        },{
+          id: 'relpersistence', label:'{{ _('Unlogged?') }}', cell: 'switch',
+          type: 'switch', mode: ['properties', 'create', 'edit'],
+          disabled: 'inSchemaWithModelCheck',
+          group: '{{ _('Advanced') }}'
+        },{
+          id: 'conname', label:'{{ _('Primary Key') }}', cell: 'string',
+          type: 'text', mode: ['properties'],
+          disabled: 'inSchema'
+        },{
+          id: 'reltuples', label:'{{ _('Rows (estimated)') }}', cell: 'string',
+          type: 'text', mode: ['properties'],
+          disabled: 'inSchema'
+        },{
+          id: 'rows_cnt', label:'{{ _('Rows (counted)') }}', cell: 'string',
+          type: 'text', mode: ['properties'],
+          disabled: 'inSchema'
+        },{
+          id: 'relhassubclass', label:'{{ _('Inherits tables?') }}', cell: 'switch',
+          type: 'switch', mode: ['properties'],
+          disabled: 'inSchema'
+        },{
+          id: 'is_sys_table', label:'{{ _('System tabel?') }}', cell: 'switch',
+          type: 'switch', mode: ['properties'],
+          disabled: 'inSchema'
+        },{
+          id: 'coll_inherits', label: '{{ _('Inherited from table(s)') }}',
+          url: 'get_inherits', type: 'array',
+          disabled: 'checkInheritance', deps: ['typname'],
+          select2: { multiple: true, allowClear: true,
+          placeholder: '{{ _('Select to inherit from...') }}'},
+          transform: function(data, cell) {
+            var control = cell || this,
+              m = control.model;
+              m.inherited_tables_list = data;
+              return data;
+          },
+          control: Backform.MultiSelectAjaxControl.extend({
+              // When changes we need to add/clear columns collection
+              onChange: function() {
+                Backform.MultiSelectAjaxControl.prototype.onChange.apply(this, arguments);
+                var self = this,
+                // current table list and previous table list
+                cTbl_list = self.model.get('coll_inherits') || [],
+                pTbl_list = self.model.previous('coll_inherits') || [];
+
+                if (!_.isUndefined(cTbl_list)) {
+                  var tbl_name = undefined,
+                    tid = undefined;
+
+                  // Add columns logic
+                  // If new table is added in list
+                  if(cTbl_list.length > 1 && cTbl_list.length > pTbl_list.length) {
+                    // Find newly added table from current list
+                    tbl_name = _.difference(cTbl_list, pTbl_list);
+                    tid = this.get_table_oid(tbl_name[0]);
+                    this.add_columns(tid);
+                  } else if (cTbl_list.length == 1) {
+                    // First table added
+                    tid = this.get_table_oid(cTbl_list[0]);
+                    this.add_columns(tid);
+                  }
+
+                  // Remove columns logic
+                  if(cTbl_list.length > 0 && cTbl_list.length < pTbl_list.length) {
+                    // Find deleted table from previous list
+                    tbl_name = _.difference(pTbl_list, cTbl_list);
+                    this.remove_columns(tbl_name[0]);
+                  } else if (pTbl_list.length === 1 && cTbl_list.length < 1) {
+                    // We got last table from list
+                    tbl_name = pTbl_list[0];
+                    this.remove_columns(tbl_name);
+                  }
+
+                }
+              },
+              add_columns: function(tid) {
+                // Create copy of old model if anything goes wrong at-least we have backup
+                // Then send AJAX request to fetch table specific columns
+                var self = this,
+                  url = 'get_columns',
+                  m = self.model.top || self.model,
+                  data = undefined,
+                  old_columns = _.clone(m.get('columns')),
+                  column_collection = m.get('columns');
+
+                var arg = {'tid': tid}
+                data = self.model.fetch_columns_ajax.apply(self, [arg]);
+
+                // Update existing column collection
+                column_collection.set(data, { merge:false,remove:false });
+              },
+              remove_columns: function(tblname) {
+                // Remove all the column models for deleted table
+                var tid = this.get_table_oid(tblname),
+                  column_collection = this.model.get('columns');
+                column_collection.remove(column_collection.where({'inheritedid': tid }));
+              },
+              get_table_oid: function(tblname) {
+                // Here we will fetch the table oid from table name
+                var tbl_oid = undefined;
+                // iterate over list to find table oid
+                _.each(this.model.inherited_tables_list, function(obj) {
+                    if(obj.label === tblname) {
+                      tbl_oid = obj.tid;
+                    }
+                });
+                return tbl_oid;
+              }
+            })
+        },{
+          id: 'inherited_tables_cnt', label:'{{ _('Inherited tables count') }}', cell: 'string',
+          type: 'text', mode: ['properties'],
+          disabled: 'inSchema'
+        },{
+          type: 'nested', control: 'fieldset', mode: ['edit', 'create'],
+          schema:[{
+            // Here we will create tab control for columns
+              id: 'columns', label:'{{ _('Columns') }}', type: 'collection',
+              group: '{{ _('Columns') }}',
+              model: pgBrowser.Nodes['column'].model,
+              subnode: pgBrowser.Nodes['column'].model,
+              mode: ['create', 'edit'],
+              disabled: 'inSchema',
+              canAdd: 'check_grid_add_condition',
+              canEdit: true, canDelete: true,
+              // For each row edit/delete button enable/disable
+              canEditRow: 'check_grid_row_edit_delete',
+              canDeleteRow: 'check_grid_row_edit_delete',
+              uniqueCol : ['name'],
+              columns : ['name' , 'cltype', 'is_primary_key', 'inheritedfrom'],
+              control: Backform.UniqueColCollectionControl.extend({
+                initialize: function() {
+                  Backform.UniqueColCollectionControl.prototype.initialize.apply(this, arguments);
+                  var self = this,
+                      collection = self.model.get(self.field.get('name'));
+
+                  collection.on("change:is_primary_key", function(m) {
+                    var primary_key_coll = self.model.get('primary_key'),
+                        column_name = m.get('name'),
+                        primary_key;
+
+                    if(m.get('is_primary_key')) {
+                    // Add column to primary key.
+                      if (primary_key_coll.length < 1) {
+                        primary_key = new (primary_key_coll.model)({}, {
+                          top: self.model,
+                          collection: primary_key_coll,
+                          handler: primary_key_coll
+                        });
+                        primary_key_coll.add(primary_key);
+                      } else {
+                        primary_key = primary_key_coll.first();
+                      }
+                      // Do not alter existing primary key columns.
+                      if (_.isUndefined(primary_key.get('oid'))) {
+                        var primary_key_column_coll = primary_key.get('columns'),
+                          primary_key_column_exist = primary_key_column_coll.where({column:column_name});
+
+                        if (primary_key_column_exist.length == 0) {
+                          var primary_key_column = new (primary_key_column_coll.model)(
+                              {column: column_name}, { silent: true,
+                              top: self.model,
+                              collection: primary_key_coll,
+                              handler: primary_key_coll
+                            });
+
+                          primary_key_column_coll.add(primary_key_column);
+                        }
+
+                        primary_key_column_coll.trigger('pgadmin:multicolumn:updated', primary_key_column_coll);
+                      }
+
+                    } else {
+                    // remove column from primary key.
+                      if (primary_key_coll.length > 0) {
+                        var primary_key = primary_key_coll.first();
+                        // Do not alter existing primary key columns.
+                        if (!_.isUndefined(primary_key.get('oid'))) {
+                          return;
+                        }
+
+                        var  primary_key_column_coll = primary_key.get('columns'),
+                            removedCols = primary_key_column_coll.where({column:column_name});
+                        if (removedCols.length > 0) {
+                          primary_key_column_coll.remove(removedCols);
+                          _.each(removedCols, function(m) {
+                            m.destroy();
+                          })
+                          if (primary_key_column_coll.length == 0) {
+                            setTimeout(function () {
+                              // There will be only on primary key so remove the first one.
+                              primary_key_coll.remove(primary_key_coll.first());
+                              /* Ideally above line of code should be "primary_key_coll.reset()".
+                               * But our custom DataCollection (extended from Backbone collection in datamodel.js)
+                               * does not respond to reset event, it only supports add, remove, change events.
+                               * And hence no custom event listeners/validators get called for reset event.
+                               */
+                            }, 10);
+                          }
+                        }
+                        primary_key_column_coll.trigger('pgadmin:multicolumn:updated', primary_key_column_coll);
+                      }
+                    }
+                  })
+                },
+                remove: function() {
+                  var collection = this.model.get(this.field.get('name'));
+                  if (collection) {
+                    collection.off("change:is_primary_key");
+                  }
+
+                  Backform.UniqueColCollectionControl.prototype.remove.apply(this, arguments);
+                }
+              }),
+              allowMultipleEmptyRow: false
+          }]
+        },{
+          type: 'nested', control: 'fieldset',
+          schema:[{
+              // Here we will create tab control for constraints
+              type: 'nested', control: 'tab', group: '{{ _('Constraints') }}',
+              mode: ['edit', 'create'],
+              schema: [{
+                  id: 'primary_key', label: '{{ _('Primary Key') }}',
+                  model: pgBrowser.Nodes['primary_key'].model,
+                  subnode: pgBrowser.Nodes['primary_key'].model,
+                  editable: false, type: 'collection',
+                  group: '{{ _('Primary Key') }}', mode: ['edit', 'create'],
+                  canEdit: true, canDelete: true,
+                  control: 'unique-col-collection',
+                  columns : ['name', 'columns'],
+                  canAdd: true,
+                  canAddRow: function(m) {
+                   // User can only add one primary key
+                   var columns = m.get('columns');
+
+                   return (m.get('primary_key') &&
+                            m.get('primary_key').length < 1 &&
+                            _.some(columns.pluck('name')));
+                  }
+                },{
+                  id: 'foreign_key', label: '{{ _('Foreign Key') }}',
+                  model: pgBrowser.Nodes['foreign_key'].model,
+                  subnode: pgBrowser.Nodes['foreign_key'].model,
+                  editable: false, type: 'collection',
+                  group: '{{ _('Foreign Key') }}', mode: ['edit', 'create'],
+                  canEdit: true, canDelete: true,
+                  control: 'unique-col-collection',
+                  canAdd: true,
+                  columns : ['name', 'columns'],
+                  canAddRow: function(m) {
+                   // User can only add if there is at least one column with name.
+                   var columns = m.get('columns');
+                   return _.some(columns.pluck('name'));
+                  }
+                },{
+                  id: 'check_constraint', label: '{{ _('Check Constraint') }}',
+                  model: pgBrowser.Nodes['check_constraints'].model,
+                  subnode: pgBrowser.Nodes['check_constraints'].model,
+                  editable: false, type: 'collection',
+                  group: '{{ _('Check') }}', mode: ['edit', 'create'],
+                  canEdit: true, canDelete: true,
+                  control: 'unique-col-collection',
+                  canAdd: true,
+                  columns : ['name', 'consrc']
+                },{
+                  id: 'unique_constraint', label: '{{ _('Unique Constraint') }}',
+                  model: pgBrowser.Nodes['unique_constraint'].model,
+                  subnode: pgBrowser.Nodes['unique_constraint'].model,
+                  editable: false, type: 'collection',
+                  group: '{{ _('Unique') }}', mode: ['edit', 'create'],
+                  canEdit: true, canDelete: true,
+                  control: 'unique-col-collection',
+                  columns : ['name', 'columns'],
+                  canAdd: true,
+                  canAddRow: function(m) {
+                   // User can only add if there is at least one column with name.
+                   var columns = m.get('columns');
+                   return _.some(columns.pluck('name'));
+                  }
+                },{
+                  id: 'exclude_constraint', label: '{{ _('Exclude Constraint') }}',
+                  model: pgBrowser.Nodes['exclusion_constraint'].model,
+                  subnode: pgBrowser.Nodes['exclusion_constraint'].model,
+                  editable: false, type: 'collection',
+                  group: '{{ _('Exclude') }}', mode: ['edit', 'create'],
+                  canEdit: true, canDelete: true,
+                  control: 'unique-col-collection',
+                  columns : ['name', 'columns', 'constraint'],
+                  canAdd: true,
+                  canAddRow: function(m) {
+                   // User can only add if there is at least one column with name.
+                   var columns = m.get('columns');
+                   return _.some(columns.pluck('name'));
+                  }
+            }]
+          }]
+        },{
+          type: 'nested', control: 'fieldset', label: '{{ _('Like') }}',
+          group: '{{ _('Advanced') }}',
+          schema:[{
+            id: 'like_relation', label:'{{ _('Relation') }}', cell: 'string',
+            type: 'text', mode: ['create', 'edit'],
+            control: 'node-ajax-options', url: 'get_relations',
+            disabled: 'inSchemaWithModelCheck', group: '{{ _('Like') }}'
+          },{
+            id: 'like_default_value', label:'{{ _('With Default values?') }}', cell: 'switch',
+            type: 'switch', mode: ['create', 'edit'],
+            disabled: 'inSchemaWithModelCheck', group: '{{ _('Like') }}'
+          },{
+            id: 'like_constraints', label:'{{ _('With Constraints?') }}', cell: 'switch',
+            type: 'switch', mode: ['create', 'edit'],
+            disabled: 'inSchemaWithModelCheck', group: '{{ _('Like') }}'
+          },{
+            id: 'like_indexes', label:'{{ _('With Indexes?') }}', cell: 'switch',
+            type: 'switch', mode: ['create', 'edit'],
+            disabled: 'inSchemaWithModelCheck', group: '{{ _('Like') }}'
+          },{
+            id: 'like_storage', label:'{{ _('With Storage?') }}', cell: 'switch',
+            type: 'switch', mode: ['create', 'edit'],
+            disabled: 'inSchemaWithModelCheck', group: '{{ _('Like') }}'
+          },{
+            id: 'like_comments', label:'{{ _('With Comments?') }}', cell: 'switch',
+            type: 'switch', mode: ['create', 'edit'],
+            disabled: 'inSchemaWithModelCheck', group: '{{ _('Like') }}'
+          }]
+        },{
+          // Here we will create tab control for auto-vacuum
+          type: 'nested', control: 'tab', group: '{{ _('Auto vacuum') }}',
+          mode: ['edit', 'create'],
+          schema: Backform.VacuumSettingsSchema
+        },{
+          id: 'relacl_str', label:'{{ _('Privileges') }}', cell: 'string',
+          type: 'text', mode: ['properties'], group: '{{ _('Security') }}',
+          disabled: 'inSchema'
+        },{
+          id: 'relacl', label: 'Privileges', type: 'collection',
+          group: '{{ _('Security') }}', control: 'unique-col-collection',
+          model: pgAdmin.Browser.Node.PrivilegeRoleModel.extend({
+          privileges: ['a','r','w','d','D','x','t']}),
+          mode: ['edit', 'create'], canAdd: true, canDelete: true,
+          uniqueCol : ['grantee']
+        },{
+          id: 'seclabels', label: '{{ _('Security Labels') }}',
+          model: pgAdmin.Browser.SecurityModel, editable: false, type: 'collection',
+          group: '{{ _('Security') }}', mode: ['edit', 'create'],
+          min_version: 90100, canAdd: true,
+          canEdit: false, canDelete: true, control: 'unique-col-collection'
+        },{
+          id: 'vacuum_settings_str', label: '{{ _('Storage Settings') }}',
+          type: 'multiline', group: '{{ _('Advanced') }}', mode: ['properties']
+        }
+        ],
+        validate: function() {
+          var err = {},
+              changedAttrs = this.changed,
+              msg = undefined,
+              name = this.get('name'),
+              schema = this.get('schema'),
+              relowner = this.get('relowner');
+
+          this.errorModel.clear();
+
+          if (_.isUndefined(name) || _.isNull(name) ||
+            String(name).replace(/^\s+|\s+$/g, '') == '') {
+            msg = '{{ _('Table name can not be empty.') }}';
+            this.errorModel.set('name', msg);
+            return msg;
+          } else if (_.isUndefined(schema) || _.isNull(schema) ||
+            String(schema).replace(/^\s+|\s+$/g, '') == '') {
+            msg = '{{ _('Table schema can not be empty.') }}';
+            this.errorModel.set('schema', msg);
+            return msg;
+          } else if (_.isUndefined(relowner) || _.isNull(relowner) ||
+            String(relowner).replace(/^\s+|\s+$/g, '') == '') {
+            msg = '{{ _('Table owner can not be empty.') }}';
+            this.errorModel.set('relowner', msg);
+            return msg;
+          }
+          return null;
+        },
+        // We will disable everything if we are under catalog node
+        inSchema: function() {
+          if(this.node_info &&  'catalog' in this.node_info)
+          {
+            return true;
+          }
+          return false;
+        },
+       isInheritedTable: function(m) {
+         if(!m.inSchema.apply(this, [m])) {
+          if(
+               (!_.isUndefined(m.get('coll_inherits')) && m.get('coll_inherits').length != 0)
+             ||
+               (!_.isUndefined(m.get('typname')) && String(m.get('typname')).replace(/^\s+|\s+$/g, '') !== '')
+             ) {
+            // Either of_types or coll_inherits has value
+            return false;
+          } else {
+            return true;
+          }
+         } else {
+           return false;
+         }
+        },
+        // We will disable it if Oftype is defined
+        checkInheritance: function(m) {
+        //coll_inherits || typname
+          if(!m.inSchema.apply(this, [m]) &&
+              ( _.isUndefined(m.get('typname')) ||
+                _.isNull(m.get('typname')) ||
+                String(m.get('typname')).replace(/^\s+|\s+$/g, '') == '')) {
+            return false;
+          }
+          return true;
+        },
+        // Check for column grid when to Add
+        check_grid_add_condition: function(m) {
+          var enable_flag = true;
+          if(!m.inSchema.apply(this, [m])) {
+            // if of_type then disable add in grid
+            if (!_.isUndefined(m.get('typname')) && !_.isNull(m.get('typname'))) {
+                    enable_flag = false;
+                }
+          }
+          return enable_flag;
+        },
+        // Check for column grid when to edit/delete (for each row)
+        check_grid_row_edit_delete: function(m) {
+          var flag = true;
+          if(!_.isUndefined(m.get('inheritedfrom')) &&
+               !_.isNull(m.get('inheritedfrom')) &&
+               String(m.get('inheritedfrom')).replace(/^\s+|\s+$/g, '') !== '') {
+            flag = false;
+          }
+          return flag;
+        },
+        // We will disable it if Inheritance is defined
+        checkOfType: function(m) {
+        //coll_inherits || typname
+          if(!m.inSchemaWithModelCheck.apply(this, [m]) &&
+              (_.isUndefined(m.get('coll_inherits')) ||
+               _.isNull(m.get('coll_inherits')) ||
+               String(m.get('coll_inherits')).replace(/^\s+|\s+$/g, '') == '')) {
+            return false;
+          }
+          return true;
+        },
+        // We will check if we are under schema node & in 'create' mode
+        inSchemaWithModelCheck: function(m) {
+          if(this.node_info &&  'schema' in this.node_info)
+          {
+            // We will disbale control if it's in 'edit' mode
+            if (m.isNew()) {
+              return false;
+            } else {
+              return true;
+            }
+          }
+          return true;
+        },
+        isTableAutoVacuumEnable: function(m) {
+          // We need to check additional condition to toggle enable/disable
+          // for table auto-vacuum
+          if(!m.inSchema.apply(this, [m]) &&
+              m.get('autovacuum_enabled') === true) {
+            return false;
+          }
+          return true;
+        },
+        isToastTableAutoVacuumEnable: function(m) {
+          // We need to check additional condition to toggle enable/disable
+          // for toast table auto-vacuum
+          if(!m.inSchemaWithModelCheck.apply(this, [m]) &&
+              m.get('toast_autovacuum_enabled') == true) {
+            return false;
+          }
+          return true;
+        },
+        fetch_columns_ajax: function(arg) {
+        var self = this,
+          url = 'get_columns',
+          m = self.model.top || self.model,
+          old_columns = _.clone(m.get('columns'))
+          data = undefined;
+
+          if (url) {
+            var node = this.field.get('schema_node'),
+              node_info = this.field.get('node_info'),
+              full_url = node.generate_url.apply(
+                node, [
+                  null, url, this.field.get('node_data'),
+                  this.field.get('url_with_id') || false, node_info
+                ]),
+              cache_level = this.field.get('cache_level') || node.type,
+              cache_node = this.field.get('cache_node');
+
+            cache_node = (cache_node && pgAdmin.Browser.Nodes['cache_node']) || node;
+
+            m.trigger('pgadmin:view:fetching', m, self.field);
+            // Fetching Columns data for the selected table.
+            $.ajax({
+              async: false,
+              url: full_url,
+              data: arg,
+              success: function(res) {
+                data = cache_node.cache(url, node_info, cache_level, res.data);
+              },
+              error: function() {
+                m.trigger('pgadmin:view:fetch:error', m, self.field);
+              }
+            });
+            m.trigger('pgadmin:view:fetched', m, self.field);
+            data = (data && data.data) || [];
+            return data;
+          }
+        }
+      }),
+      canCreate: function(itemData, item, data) {
+          //If check is false then , we will allow create menu
+          if (data && data.check == false)
+            return true;
+
+          var t = pgBrowser.tree, i = item, d = itemData;
+          // To iterate over tree to check parent node
+          while (i) {
+            // If it is schema then allow user to create table
+            if (_.indexOf(['schema'], d._type) > -1)
+              return true;
+
+            if ('coll-table' == d._type) {
+              //Check if we are not child of catalog
+              prev_i = t.hasParent(i) ? t.parent(i) : null;
+              prev_d = prev_i ? t.itemData(prev_i) : null;
+              if( prev_d._type == 'catalog') {
+                return false;
+              } else {
+                return true;
+              }
+            }
+            i = t.hasParent(i) ? t.parent(i) : null;
+            d = i ? t.itemData(i) : null;
+          }
+          // by default we do not want to allow create menu
+          return true;
+      },
+      // Check to whether table has disable trigger(s)
+      canCreate_with_trigger_enable: function(itemData, item, data) {
+        if(this.canCreate.apply(this, [itemData, item, data])) {
+          // We are here means we can create menu, now let's check condition
+          if(itemData.tigger_count > 0) {
+            return true;
+          } else {
+            return false;
+          }
+        }
+      },
+      // Check to whether table has enable trigger(s)
+      canCreate_with_trigger_disable: function(itemData, item, data) {
+        if(this.canCreate.apply(this, [itemData, item, data])) {
+          // We are here means we can create menu, now let's check condition
+          if(itemData.tigger_count > 0 && itemData.has_enable_triggers > 0) {
+            return true;
+          } else {
+            return false;
+          }
+        }
+      }
+  });
+
+  }
+
+  return pgBrowser.Nodes['table'];
+});
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/acl.sql
new file mode 100644
index 0000000..56f1f76
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/acl.sql
@@ -0,0 +1,46 @@
+{### SQL to fetch privileges for tablespace ###}
+SELECT 'relacl' as deftype, COALESCE(gt.rolname, 'public') grantee, g.rolname grantor,
+    array_agg(privilege_type) as privileges, array_agg(is_grantable) as grantable
+FROM
+  (SELECT
+    d.grantee, d.grantor, d.is_grantable,
+    CASE d.privilege_type
+		WHEN 'CONNECT' THEN 'c'
+		WHEN 'CREATE' THEN 'C'
+		WHEN 'DELETE' THEN 'd'
+		WHEN 'EXECUTE' THEN 'X'
+		WHEN 'INSERT' THEN 'a'
+		WHEN 'REFERENCES' THEN 'x'
+		WHEN 'SELECT' THEN 'r'
+		WHEN 'TEMPORARY' THEN 'T'
+		WHEN 'TRIGGER' THEN 't'
+		WHEN 'TRUNCATE' THEN 'D'
+		WHEN 'UPDATE' THEN 'w'
+		WHEN 'USAGE' THEN 'U'
+		ELSE 'UNKNOWN'
+	END AS privilege_type
+  FROM
+    (SELECT rel.relacl
+        FROM pg_class rel
+          LEFT OUTER JOIN pg_tablespace spc on spc.oid=rel.reltablespace
+          LEFT OUTER JOIN pg_constraint con ON con.conrelid=rel.oid AND con.contype='p'
+          LEFT OUTER JOIN pg_class tst ON tst.oid = rel.reltoastrelid
+          LEFT JOIN pg_type typ ON rel.reloftype=typ.oid
+        WHERE rel.relkind IN ('r','s','t') AND rel.relnamespace = {{ scid }}::oid
+            AND rel.oid = {{ tid }}::oid
+    ) acl,
+    (SELECT (d).grantee AS grantee, (d).grantor AS grantor, (d).is_grantable
+        AS is_grantable, (d).privilege_type AS privilege_type FROM (SELECT
+        aclexplode(rel.relacl) as d
+        FROM pg_class rel
+          LEFT OUTER JOIN pg_tablespace spc on spc.oid=rel.reltablespace
+          LEFT OUTER JOIN pg_constraint con ON con.conrelid=rel.oid AND con.contype='p'
+          LEFT OUTER JOIN pg_class tst ON tst.oid = rel.reltoastrelid
+          LEFT JOIN pg_type typ ON rel.reloftype=typ.oid
+        WHERE rel.relkind IN ('r','s','t') AND rel.relnamespace = {{ scid }}::oid
+            AND rel.oid = {{ tid }}::oid
+        ) a) d
+    ) d
+  LEFT JOIN pg_catalog.pg_roles g ON (d.grantor = g.oid)
+  LEFT JOIN pg_catalog.pg_roles gt ON (d.grantee = gt.oid)
+GROUP BY g.rolname, gt.rolname
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/backend_support.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/backend_support.sql
new file mode 100644
index 0000000..f9b9564
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/backend_support.sql
@@ -0,0 +1,18 @@
+SELECT
+ CASE WHEN nsp.nspname IN ('sys', 'dbo', 'information_schema') THEN true ELSE false END AS dbSupport
+FROM pg_namespace nsp
+WHERE nsp.oid={{scid}}::int
+AND (
+	(nspname = 'pg_catalog' AND EXISTS
+	                               (SELECT 1 FROM pg_class WHERE relname = 'pg_class' AND relnamespace = nsp.oid LIMIT 1))
+	OR (nspname = 'pgagent' AND EXISTS
+	                               (SELECT 1 FROM pg_class WHERE relname = 'pga_job' AND relnamespace = nsp.oid LIMIT 1))
+	OR (nspname = 'information_schema' AND EXISTS
+	                               (SELECT 1 FROM pg_class WHERE relname = 'tables' AND relnamespace = nsp.oid LIMIT 1))
+	OR (nspname LIKE '_%' AND EXISTS
+	                               (SELECT 1 FROM pg_proc WHERE proname='slonyversion' AND pronamespace = nsp.oid LIMIT 1))
+)
+AND
+ nspname NOT LIKE E'pg\\temp\\%'
+AND
+ nspname NOT LIKE E'pg\\toast_temp\\%'
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/create.sql
new file mode 100644
index 0000000..c0fb5e4
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/create.sql
@@ -0,0 +1,157 @@
+{% import 'macros/schemas/security.macros' as SECLABLE %}
+{% import 'macros/schemas/privilege.macros' as PRIVILEGE %}
+{% import 'macros/variable.macros' as VARIABLE %}
+{% import 'column/macros/security.macros' as COLUMN_SECLABLE %}
+{% import 'column/macros/privilege.macros' as COLUMN_PRIVILEGE %}
+{% import 'table/sql/macros/constraints.macro' as CONSTRAINTS %}
+{#===========================================#}
+{#====== MAIN TABLE TEMPLATE STARTS HERE ======#}
+{#===========================================#}
+{#
+ If user has not provided any details but only name then
+ add empty bracket with table name
+#}
+{% set empty_bracket = ""%}
+{% if data.coll_inherits|length == 0 and  data.columns|length == 0 and not data.typname and not data.like_relation and data.primary_key|length == 0 and data.unique_constraint|length == 0 and data.foreign_key|length == 0 and data.check_constraint|length == 0 and data.exclude_constraint|length == 0 %}
+{% set empty_bracket = "\n(\n)"%}
+{% endif %}
+CREATE {% if data.relpersistence %}UNLOGGED {% endif %}TABLE {{conn|qtIdent(data.schema, data.name)}}{{empty_bracket}}
+{% if data.typname %}
+    OF {{ data.typname }}
+{% endif %}
+{% if data.like_relation or data.coll_inherits or data.columns|length > 0 or data.primary_key|length > 0 or data.unique_constraint|length > 0 or data.foreign_key|length > 0 or data.check_constraint|length > 0 or data.exclude_constraint|length > 0 %}
+(
+{% endif %}
+{% if data.like_relation %}
+    LIKE {{ data.like_relation }}{% if data.like_default_value %}
+
+        INCLUDING DEFAULTS{% endif %}{% if data.like_constraints %}
+
+        INCLUDING CONSTRAINTS{% endif %}{% if data.like_indexes %}
+
+        INCLUDING INDEXES{% endif %}{% if data.like_storage %}
+
+        INCLUDING STORAGE{% endif %}{% if data.like_comments %}
+
+        INCLUDING COMMENTS{% endif %}{% if data.columns|length > 0 %},
+{% endif %}
+
+{% endif %}
+{### Add columns ###}
+{% if data.columns and data.columns|length > 0 %}
+{% for c in data.columns %}
+{% if c.name and c.cltype %}
+{% if loop.index != 1 %},
+{% endif %}
+    {{conn|qtIdent(c.name)}} {{c.cltype}}{% if c.attlen %}
+({{c.attlen}}{% if c.attprecision%}, {{c.attprecision}}{% endif %}){% endif %}{% if c.hasSqrBracket %}
+[]{% endif %}{% if c.collspcname %} COLLATE {{c.collspcname}}{% endif %}{% if c.attnotnull %} NOT NULL{% endif %}{% if c.defval %} DEFAULT {{c.defval}}{% endif %}
+{% endif %}
+{% endfor %}
+{% endif %}
+{# Macro to render for constraints #}
+{% if data.primary_key|length > 0 %}{% if data.columns|length > 0 %},{% endif %}
+{{CONSTRAINTS.PRIMARY_KEY(conn, data.primary_key[0])}}{% endif %}{% if data.unique_constraint|length > 0 %}{% if data.columns|length > 0 or data.primary_key|length > 0 %},{% endif %}
+{{CONSTRAINTS.UNIQUE(conn, data.unique_constraint)}}{% endif %}{% if data.foreign_key|length > 0 %}{% if data.columns|length > 0 or data.primary_key|length > 0 or data.unique_constraint|length > 0 %},{% endif %}
+{{CONSTRAINTS.FOREIGN_KEY(conn, data.foreign_key)}}{% endif %}{% if data.check_constraint|length > 0 %}{% if data.columns|length > 0 or data.primary_key|length > 0 or data.unique_constraint|length > 0 or data.foreign_key|length > 0 %},{% endif %}
+{{CONSTRAINTS.CHECK(conn, data.check_constraint)}}{% endif %}{% if data.exclude_constraint|length > 0 %}{% if data.columns|length > 0 or data.primary_key|length > 0 or data.unique_constraint|length > 0 or data.foreign_key|length > 0 or data.check_constraint|length > 0 %},{% endif %}
+{{CONSTRAINTS.EXCLUDE(conn, data.exclude_constraint)}}{% endif %}
+{% if data.like_relation or data.coll_inherits or data.columns|length > 0 or data.primary_key|length > 0 or data.unique_constraint|length > 0 or data.foreign_key|length > 0 or data.check_constraint|length > 0 or data.exclude_constraint|length > 0 %}
+
+)
+{% endif %}
+{### If we are inheriting it from another table(s) ###}
+{% if data.coll_inherits %}
+    INHERITS ({% for val in data.coll_inherits %}{% if loop.index != 1 %}, {% endif %}{{val}}{% endfor %})
+{% endif %}
+WITH (
+    OIDS = {% if data.relhasoids %}TRUE{% else %}FALSE{% endif %}{% if data.fillfactor %},
+    FILLFACTOR = {{ data.fillfactor }}{% endif %}{% if data.autovacuum_custom %},
+    autovacuum_enabled = {% if data.autovacuum_enabled %}TRUE{% else %}FALSE{% endif %}{% endif %}{% if data.toast_autovacuum %},
+    toast.autovacuum_enabled = {% if data.toast_autovacuum_enabled %}TRUE{% else %}FALSE{% endif %}
+{% endif %}{% if data.autovacuum_enabled and data.vacuum_table|length > 0 %}
+{% for opt in data.vacuum_table %}{% if opt.name and opt.value %}
+,
+    {{opt.name}} = {{opt.value}}{% endif %}
+{% endfor %}{% endif %}{% if data.toast_autovacuum_enabled and data.vacuum_toast|length > 0 %}
+{% for opt in data.vacuum_toast %}{% if opt.name and opt.value %}
+,
+    toast.{{opt.name}} = {{opt.value}}{% endif %}
+{% endfor %}{% endif %}
+
+)
+{### SQL for Tablespace ###}
+{% if data.spcname %}
+TABLESPACE {{ conn|qtIdent(data.spcname) }};
+{% endif %}
+{### Alter SQL for Owner ###}
+{% if data.relowner %}
+
+ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
+    OWNER to {{conn|qtIdent(data.relowner)}};
+{% endif %}
+{### Security Labels on Table ###}
+{% if data.seclabels and data.seclabels|length > 0 %}
+
+{% for r in data.seclabels %}
+{{ SECLABLE.SET(conn, 'TABLE', data.name, r.provider, r.label, data.schema) }}
+{% endfor %}
+{% endif %}
+{###  ACL on Table ###}
+{% if data.relacl %}
+
+{% for priv in data.relacl %}
+{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }}
+{% endfor %}
+{% endif %}
+{### SQL for COMMENT ###}
+{% if data.description %}
+COMMENT ON TABLE {{conn|qtIdent(data.schema, data.name)}}
+    IS {{data.description|qtLiteral}};
+{% endif %}
+{#===========================================#}
+{#====== MAIN TABLE TEMPLATE ENDS HERE ======#}
+{#===========================================#}
+{#===========================================#}
+{#  COLUMN SPECIFIC TEMPLATES STARTS HERE    #}
+{#===========================================#}
+{% if data.columns and data.columns|length > 0 %}
+{% for c in data.columns %}
+{% if c.description %}
+
+COMMENT ON COLUMN {{conn|qtIdent(data.schema, data.name, c.name)}}
+    IS {{c.description|qtLiteral}};
+{% endif %}
+{###  Add variables to column ###}
+{% if c.attoptions and c.attoptions|length > 0 %}
+
+ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
+    {{ VARIABLE.SET(conn, 'COLUMN', c.name, c.attoptions) }}
+{% endif %}
+{###  ACL ###}
+{% if c.attacl and c.attacl|length > 0 %}
+
+{% for priv in c.attacl %}
+    {{ COLUMN_PRIVILEGE.APPLY(conn, data.schema, data.name, c.name, priv.grantee, priv.without_grant, priv.with_grant) }}
+{% endfor %}
+{% endif %}
+{###  Security Lables ###}
+{% if c.seclabels and c.seclabels|length > 0 %}
+
+{% for r in c.seclabels %}
+{{ COLUMN_SECLABLE.APPLY(conn, 'COLUMN',data.schema, data.name, c.name, r.provider, r.label) }}
+{% endfor %}
+{% endif %}
+{% endfor %}
+{% endif %}
+{#===========================================#}
+{#   COLUMN SPECIFIC TEMPLATES ENDS HERE     #}
+{#===========================================#}
+{#======================================#}
+{#   CONSTRAINTS SPECIFIC TEMPLATES     #}
+{#======================================#}
+{{CONSTRAINTS.CONSTRAINT_COMMENTS(conn, data.schema, data.name, data.primary_key)}}
+{{CONSTRAINTS.CONSTRAINT_COMMENTS(conn, data.schema, data.name, data.unique_constraint)}}
+{{CONSTRAINTS.CONSTRAINT_COMMENTS(conn, data.schema, data.name, data.foreign_key)}}
+{{CONSTRAINTS.CONSTRAINT_COMMENTS(conn, data.schema, data.name, data.check_constraint)}}
+{{CONSTRAINTS.CONSTRAINT_COMMENTS(conn, data.schema, data.name, data.exclude_constraint)}}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/delete.sql
new file mode 100644
index 0000000..01d0314
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/delete.sql
@@ -0,0 +1 @@
+DROP TABLE {{conn|qtIdent(data.schema, data.name)}}{% if cascade %} CASCADE{% endif %};
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/depend.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/depend.sql
new file mode 100644
index 0000000..f5f39e7
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/depend.sql
@@ -0,0 +1,9 @@
+SELECT
+    ref.relname AS refname, d2.refclassid, dep.deptype AS deptype
+FROM pg_depend dep
+    LEFT JOIN pg_depend d2 ON dep.objid=d2.objid AND dep.refobjid != d2.refobjid
+    LEFT JOIN pg_class ref ON ref.oid=d2.refobjid
+    LEFT JOIN pg_attribute att ON d2.refclassid=att.attrelid AND d2.refobjsubid=att.attnum
+    {{ where }} AND
+    dep.classid=(SELECT oid FROM pg_class WHERE relname='pg_attrdef') AND
+    dep.refobjid NOT IN (SELECT d3.refobjid FROM pg_depend d3 WHERE d3.objid=d2.refobjid)
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/enable_disable_trigger.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/enable_disable_trigger.sql
new file mode 100644
index 0000000..a4ab154
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/enable_disable_trigger.sql
@@ -0,0 +1,2 @@
+ALTER TABLE {{ conn|qtIdent(data.schema, data.name) }}
+    {% if is_enable_trigger == True %}ENABLE{% else %}DISABLE{% endif %} TRIGGER ALL;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/get_columns_for_table.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/get_columns_for_table.sql
new file mode 100644
index 0000000..3d6bbb7
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/get_columns_for_table.sql
@@ -0,0 +1,16 @@
+SELECT
+    a.attname AS name, format_type(a.atttypid, NULL) AS cltype,
+    quote_ident(n.nspname)||'.'||quote_ident(c.relname) as inheritedfrom,
+    c.oid as inheritedid
+FROM
+    pg_class c
+JOIN
+    pg_namespace n ON c.relnamespace=n.oid
+JOIN
+    pg_attribute a ON a.attrelid = c.oid AND NOT a.attisdropped AND a.attnum > 0
+WHERE
+{% if tid %}
+    c.oid = {{tid}}::OID
+{% else %}
+    c.relname = {{tname|qtLiteral}}
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/get_inherits.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/get_inherits.sql
new file mode 100644
index 0000000..50f9a1d
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/get_inherits.sql
@@ -0,0 +1,13 @@
+SELECT c.oid, c.relname , nspname,
+CASE WHEN (nspname NOT LIKE E'pg\_%' AND nspname <> 'public') THEN
+ quote_ident(nspname)||'.'||quote_ident(c.relname)
+ELSE quote_ident(c.relname)
+END AS inherits
+FROM pg_class c
+JOIN pg_namespace n
+ON n.oid=c.relnamespace
+WHERE relkind='r'
+{% if not show_system_objects %}
+AND (n.nspname NOT LIKE E'pg\_%' AND n.nspname NOT in ('information_schema'))
+{% endif %}
+ORDER BY relnamespace, c.relname
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/get_oftype.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/get_oftype.sql
new file mode 100644
index 0000000..aed42f2
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/get_oftype.sql
@@ -0,0 +1,6 @@
+SELECT t.oid,
+  quote_ident(n.nspname)||'.'||quote_ident(t.typname) AS typname
+  FROM pg_type t, pg_namespace n
+WHERE t.typtype='c' AND t.typnamespace=n.oid
+  AND NOT (n.nspname like 'pg_%' OR n.nspname='information_schema')
+ORDER BY typname;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/get_oid.sql
new file mode 100644
index 0000000..e9dc772
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/get_oid.sql
@@ -0,0 +1,5 @@
+SELECT rel.oid as tid
+FROM pg_class rel
+WHERE rel.relkind IN ('r','s','t')
+AND rel.relnamespace = {{ scid }}::oid
+AND rel.relname = {{data.name|qtLiteral}}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/get_relations.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/get_relations.sql
new file mode 100644
index 0000000..431ee88
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/get_relations.sql
@@ -0,0 +1,6 @@
+SELECT c.oid, quote_ident(n.nspname)||'.'||quote_ident(c.relname) AS like_relation
+FROM pg_class c, pg_namespace n
+WHERE c.relnamespace=n.oid
+AND
+c.relkind IN ('r', 'v', 'f')
+ORDER BY 1;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/get_tables_for_constraints.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/get_tables_for_constraints.sql
new file mode 100644
index 0000000..1362463
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/get_tables_for_constraints.sql
@@ -0,0 +1,8 @@
+SELECT cl.oid as value, quote_ident(nspname)||'.'||quote_ident(relname) AS label
+FROM pg_namespace nsp, pg_class cl
+WHERE relnamespace=nsp.oid AND relkind='r'
+   AND nsp.nspname NOT LIKE E'pg\_temp\_%'
+   {% if not show_sysobj %}
+   AND (nsp.nspname NOT LIKE E'pg\_%' AND nsp.nspname NOT in ('information_schema'))
+   {% endif %}
+ORDER BY nspname, relname
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/get_types_where_condition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/get_types_where_condition.sql
new file mode 100644
index 0000000..fadfc99
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/get_types_where_condition.sql
@@ -0,0 +1,10 @@
+{### Additional where condition for get_types route for column node ###}
+typisdefined AND typtype IN ('b', 'c', 'd', 'e', 'r')
+AND NOT EXISTS (SELECT 1 FROM pg_class WHERE relnamespace=typnamespace
+AND relname = typname AND relkind != 'c') AND
+(typname NOT LIKE '_%' OR NOT EXISTS (SELECT 1 FROM pg_class WHERE
+relnamespace=typnamespace AND relname = substring(typname FROM 2)::name
+AND relkind != 'c'))
+{% if not show_system_objects %}
+AND nsp.nspname != 'information_schema'
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/nodes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/nodes.sql
new file mode 100644
index 0000000..43f14cb
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/nodes.sql
@@ -0,0 +1,6 @@
+SELECT rel.oid, rel.relname AS name,
+    (SELECT count(*) FROM pg_trigger WHERE tgrelid=rel.oid AND tgisinternal = FALSE) AS triggercount,
+    (SELECT count(*) FROM pg_trigger WHERE tgrelid=rel.oid AND tgisinternal = FALSE AND tgenabled = 'O') AS has_enable_triggers
+FROM pg_class rel
+    WHERE rel.relkind IN ('r','s','t') AND rel.relnamespace = {{ scid }}::oid
+    ORDER BY rel.relname;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/properties.sql
new file mode 100644
index 0000000..99727c9
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/properties.sql
@@ -0,0 +1,65 @@
+SELECT rel.oid, rel.relname AS name, rel.reltablespace AS spcoid,rel.relacl AS relacl_str,
+  (CASE WHEN length(spc.spcname) > 0 THEN spc.spcname ELSE 'pg_default' END) as spcname,
+  (select nspname FROM pg_namespace WHERE oid = {{scid}}::oid ) as schema,
+  pg_get_userbyid(rel.relowner) AS relowner, rel.relhasoids,
+  rel.relhassubclass, rel.reltuples, des.description, con.conname, con.conkey,
+	EXISTS(select 1 FROM pg_trigger
+			JOIN pg_proc pt ON pt.oid=tgfoid AND pt.proname='logtrigger'
+			JOIN pg_proc pc ON pc.pronamespace=pt.pronamespace AND pc.proname='slonyversion'
+			WHERE tgrelid=rel.oid) AS isrepl,
+	(SELECT count(*) FROM pg_trigger WHERE tgrelid=rel.oid AND tgisinternal = FALSE) AS triggercount,
+	(SELECT ARRAY(SELECT CASE WHEN (nspname NOT LIKE E'pg\_%' AND nspname <> 'public') THEN
+            quote_ident(nspname)||'.'||quote_ident(c.relname)
+            ELSE quote_ident(c.relname) END AS inherited_tables
+    FROM pg_inherits i
+    JOIN pg_class c ON c.oid = i.inhparent
+    JOIN pg_namespace n ON n.oid=c.relnamespace
+    WHERE i.inhrelid = rel.oid ORDER BY inhseqno)) AS coll_inherits,
+  (SELECT count(*)
+		FROM pg_inherits i
+      JOIN pg_class c ON c.oid = i.inhparent
+      JOIN pg_namespace n ON n.oid=c.relnamespace
+		WHERE i.inhrelid = rel.oid) AS inherited_tables_cnt,
+	(CASE WHEN rel.relpersistence = 'u' THEN true ELSE false END) AS relpersistence,
+	substring(array_to_string(rel.reloptions, ',') FROM 'fillfactor=([0-9]*)') AS fillfactor,
+	(CASE WHEN (substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)') = 'true')
+	  THEN true ELSE false END) AS autovacuum_enabled,
+	substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS autovacuum_vacuum_threshold,
+	substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.][0-9]*)') AS autovacuum_vacuum_scale_factor,
+	substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_analyze_threshold=([0-9]*)') AS autovacuum_analyze_threshold,
+	substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_analyze_scale_factor=([0-9]*[.][0-9]*)') AS autovacuum_analyze_scale_factor,
+	substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS autovacuum_vacuum_cost_delay,
+	substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS autovacuum_vacuum_cost_limit,
+	substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_freeze_min_age=([0-9]*)') AS autovacuum_freeze_min_age,
+	substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_freeze_max_age=([0-9]*)') AS autovacuum_freeze_max_age,
+	substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS autovacuum_freeze_table_age,
+	(CASE WHEN (substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)') =  'true')
+	  THEN true ELSE false END) AS toast_autovacuum_enabled,
+	substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS toast_autovacuum_vacuum_threshold,
+	substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.][0-9]*)') AS toast_autovacuum_vacuum_scale_factor,
+	substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_analyze_threshold=([0-9]*)') AS toast_autovacuum_analyze_threshold,
+	substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_analyze_scale_factor=([0-9]*[.][0-9]*)') AS toast_autovacuum_analyze_scale_factor,
+	substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS toast_autovacuum_vacuum_cost_delay,
+	substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS toast_autovacuum_vacuum_cost_limit,
+	substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_min_age=([0-9]*)') AS toast_autovacuum_freeze_min_age,
+	substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_max_age=([0-9]*)') AS toast_autovacuum_freeze_max_age,
+	substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS toast_autovacuum_freeze_table_age,
+	array_to_string(rel.reloptions, ',') AS table_vacuum_settings_str,
+	array_to_string(tst.reloptions, ',') AS toast_table_vacuum_settings_str,
+	rel.reloptions AS reloptions, tst.reloptions AS toast_reloptions, rel.reloftype, typ.typname,
+	(CASE WHEN rel.reltoastrelid = 0 THEN false ELSE true END) AS hastoasttable,
+    -- Added for pgAdmin4
+	(CASE WHEN (substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)'))::boolean  THEN true ELSE false END) AS autovacuum_custom,
+	(CASE WHEN (substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)'))::boolean  AND rel.reltoastrelid != 0 THEN true ELSE false END) AS toast_autovacuum,
+
+	(SELECT array_agg(provider || '=' || label) FROM pg_seclabels sl1 WHERE sl1.objoid=rel.oid AND sl1.objsubid=0) AS seclabels,
+	(CASE WHEN rel.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_table
+FROM pg_class rel
+  LEFT OUTER JOIN pg_tablespace spc on spc.oid=rel.reltablespace
+  LEFT OUTER JOIN pg_description des ON (des.objoid=rel.oid AND des.objsubid=0 AND des.classoid='pg_class'::regclass)
+  LEFT OUTER JOIN pg_constraint con ON con.conrelid=rel.oid AND con.contype='p'
+  LEFT OUTER JOIN pg_class tst ON tst.oid = rel.reltoastrelid
+  LEFT JOIN pg_type typ ON rel.reloftype=typ.oid
+WHERE rel.relkind IN ('r','s','t') AND rel.relnamespace = {{ scid }}::oid
+{% if tid %}  AND rel.oid = {{ tid }}::oid {% endif %}
+ORDER BY rel.relname;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/reset_stats.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/reset_stats.sql
new file mode 100644
index 0000000..36eca0d
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/reset_stats.sql
@@ -0,0 +1 @@
+SELECT pg_stat_reset_single_table_counters({{tid}})
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/sql.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/sql.sql
new file mode 100644
index 0000000..17b35ae
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/sql.sql
@@ -0,0 +1 @@
+TAKE ASHESH'S HELP ON THIS TASK :-)
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/truncate.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/truncate.sql
new file mode 100644
index 0000000..6a276f3
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/truncate.sql
@@ -0,0 +1 @@
+TRUNCATE TABLE {{conn|qtIdent(data.schema, data.name)}}{% if cascade %} CASCADE{% endif %};
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/update.sql
new file mode 100644
index 0000000..a97ac30
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.1_plus/update.sql
@@ -0,0 +1,201 @@
+{% import 'macros/schemas/security.macros' as SECLABLE %}
+{% import 'macros/schemas/privilege.macros' as PRIVILEGE %}
+{% import 'macros/variable.macros' as VARIABLE %}
+{#####################################################}
+{## Rename table ##}
+{#####################################################}
+{% if data.name and data.name != o_data.name %}
+ALTER TABLE {{conn|qtIdent(o_data.schema, o_data.name)}}
+    RENAME TO {{conn|qtIdent(data.name)}};
+
+{% endif %}
+{#####################################################}
+{## Change table schema ##}
+{#####################################################}
+{% if data.schema and data.schema != o_data.schema %}
+ALTER TABLE {{conn|qtIdent(o_data.schema, data.name)}}
+  SET SCHEMA {{conn|qtIdent(data.schema)}};
+
+{% endif %}
+{#####################################################}
+{## Change table owner ##}
+{#####################################################}
+{% if data.relowner and data.relowner != o_data.relowner %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
+    OWNER TO {{conn|qtIdent(data.relowner)}};
+
+{% endif %}
+{#####################################################}
+{## Update Inherits table definition ##}
+{#####################################################}
+{% if data.coll_inherits_added|length > 0 %}
+{% for val in data.coll_inherits_added %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
+    INHERIT {{val}};
+
+{% endfor %}
+{% endif %}
+{% if data.coll_inherits_removed|length > 0 %}
+{% for val in data.coll_inherits_removed %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
+    NO INHERIT {{val}};
+
+{% endfor %}
+{% endif %}
+{#####################################################}
+{## Change hasOID attribute of table ##}
+{#####################################################}
+{% if data.relhasoids is defined and data.relhasoids != o_data.relhasoids %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
+    SET {% if data.relhasoids %}WITH{% else %}WITHOUT{% endif %} OIDS;
+
+{% endif %}
+{#####################################################}
+{## Change tablespace ##}
+{#####################################################}
+{% if data.spcname and data.spcname != o_data.spcname %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
+    SET TABLESPACE {{conn|qtIdent(data.spcname)}};
+
+{% endif %}
+{#####################################################}
+{## change fillfactore settings ##}
+{#####################################################}
+{% if data.fillfactor and data.fillfactor != o_data.fillfactor %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
+    SET (FILLFACTOR={{data.fillfactor}});
+
+{% endif %}
+{###############################}
+{## Table AutoVacuum settings ##}
+{###############################}
+{% if o_data.autovacuum_custom and data.autovacuum_custom == false %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.name)}} RESET (
+    autovacuum_enabled,
+    autovacuum_analyze_scale_factor,
+    autovacuum_analyze_threshold,
+    autovacuum_freeze_max_age,
+    autovacuum_vacuum_cost_delay,
+    autovacuum_vacuum_cost_limit,
+    autovacuum_vacuum_scale_factor,
+    autovacuum_vacuum_threshold,
+    autovacuum_freeze_min_age,
+    autovacuum_freeze_table_age
+);
+{% elif data.autovacuum_enabled != o_data.autovacuum_enabled %}
+{% if data.autovacuum_enabled and o_data.autovacuum_enabled == false %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.name)}} SET (
+    autovacuum_enabled = true{% elif data.autovacuum_enabled == false and o_data.autovacuum_enabled %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.name)}} SET (
+       autovacuum_enabled = false{% endif %}
+{% if (data.autovacuum_enabled or o_data.autovacuum_enabled )and data.vacuum_table and data.vacuum_table.changed|length > 0 %}
+{% for opt in data.vacuum_table.changed %}{% if opt.name and opt.value %}
+{% if flag or (data.autovacuum_enabled and o_data.autovacuum_enabled == false) or (data.autovacuum_enabled == false and o_data.autovacuum_enabled) %}
+,
+{% else %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.name)}} SET (
+{% set flag = true %}
+{% endif %}
+    {{opt.name}} = {{opt.value}}{% endif %}
+{% if loop.index == data.vacuum_table.changed|length and (flag or (data.autovacuum_enabled and o_data.autovacuum_enabled == false) or (data.autovacuum_enabled == false and o_data.autovacuum_enabled))%}
+
+);
+{% endif %}
+{% endfor %}
+{% elif (data.autovacuum_enabled and o_data.autovacuum_enabled == false) or (data.autovacuum_enabled == false and o_data.autovacuum_enabled) %}
+
+);
+{% endif %}
+{% endif %}
+{#####################################}
+{## Toast table AutoVacuum settings ##}
+{#####################################}
+{% if o_data.toast_autovacuum and data.toast_autovacuum == false %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.name)}} RESET (
+    toast.autovacuum_enabled,
+    toast.autovacuum_freeze_max_age,
+    toast.autovacuum_vacuum_cost_delay,
+    toast.autovacuum_vacuum_cost_limit,
+    toast.autovacuum_vacuum_scale_factor,
+    toast.autovacuum_vacuum_threshold,
+    toast.autovacuum_freeze_min_age,
+    toast.autovacuum_freeze_table_age,
+    toast.autovacuum_analyze_threshold,
+    toast.autovacuum_analyze_scale_factor
+);
+{% elif data.toast_autovacuum_enabled != o_data.toast_autovacuum_enabled %}
+{% if data.toast_autovacuum_enabled and o_data.toast_autovacuum_enabled == false %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.name)}} SET (
+    toast.autovacuum_enabled = true{% elif data.toast_autovacuum_enabled == false and o_data.toast_autovacuum_enabled %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.name)}} SET (
+       toast.autovacuum_enabled = false{% endif %}
+{% if (data.toast_autovacuum_enabled or o_data.toast_autovacuum_enabled )and data.vacuum_toast and data.vacuum_toast.changed|length > 0 %}
+{% for opt in data.vacuum_toast.changed %}{% if opt.name and opt.value %}
+{% if flag or (data.toast_autovacuum_enabled and o_data.toast_autovacuum_enabled == false) or (data.toast_autovacuum_enabled == false and o_data.toast_autovacuum_enabled) %}
+,
+{% else %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.name)}} SET (
+{% set flag = true %}
+{% endif %}
+    toast.{{opt.name}} = {{opt.value}}{% endif %}
+{% if loop.index == data.vacuum_toast.changed|length and (flag or (data.toast_autovacuum_enabled and o_data.toast_autovacuum_enabled == false) or (data.toast_autovacuum_enabled == false and o_data.toast_autovacuum_enabled))%}
+
+);
+{% endif %}
+{% endfor %}
+{% elif (data.toast_autovacuum_enabled and o_data.toast_autovacuum_enabled == false) or (data.toast_autovacuum_enabled == false and o_data.toast_autovacuum_enabled) %}
+
+);
+{% endif %}
+{% endif %}
+{#####################################################}
+{## Change table comments ##}
+{#####################################################}
+{% if data.description and data.description != o_data.description %}
+COMMENT ON TABLE {{conn|qtIdent(data.schema, data.name)}}
+  IS {{data.description|qtLiteral}};
+
+{% endif %}
+{#####################################################}
+{## Update table Privileges ##}
+{#####################################################}
+{% if data.relacl %}
+{% if 'deleted' in data.relacl %}
+{% for priv in data.relacl.deleted %}
+{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }}
+{% endfor %}
+{% endif %}
+{% if 'changed' in data.relacl %}
+{% for priv in data.relacl.changed %}
+{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }}
+{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }}
+{% endfor %}
+{% endif %}
+{% if 'added' in data.relacl %}
+{% for priv in data.relacl.added %}
+{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }}
+{% endfor %}
+{% endif %}
+{% endif %}
+{#####################################################}
+{## Update table SecurityLabel ##}
+{#####################################################}
+{% if data.seclabels and data.seclabels|length > 0 %}
+{% set seclabels = data.seclabels %}
+{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %}
+{% for r in seclabels.deleted %}
+{{ SECLABEL.UNSET(conn, 'TABLE', data.name, r.provider, data.schema) }}
+{% endfor %}
+{% endif %}
+{% if 'added' in seclabels and seclabels.added|length > 0 %}
+{% for r in seclabels.added %}
+{{ SECLABLE.SET(conn, 'TABLE', data.name, r.provider, r.label, data.schema) }}
+{% endfor %}
+{% endif %}
+{% if 'changed' in seclabels and seclabels.changed|length > 0 %}
+{% for r in seclabels.changed %}
+{{ SECLABLE.SET(conn, 'TABLE', data.name, r.provider, r.label, data.schema) }}
+{% endfor %}
+{% endif %}
+
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/acl.sql
new file mode 100644
index 0000000..56f1f76
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/acl.sql
@@ -0,0 +1,46 @@
+{### SQL to fetch privileges for tablespace ###}
+SELECT 'relacl' as deftype, COALESCE(gt.rolname, 'public') grantee, g.rolname grantor,
+    array_agg(privilege_type) as privileges, array_agg(is_grantable) as grantable
+FROM
+  (SELECT
+    d.grantee, d.grantor, d.is_grantable,
+    CASE d.privilege_type
+		WHEN 'CONNECT' THEN 'c'
+		WHEN 'CREATE' THEN 'C'
+		WHEN 'DELETE' THEN 'd'
+		WHEN 'EXECUTE' THEN 'X'
+		WHEN 'INSERT' THEN 'a'
+		WHEN 'REFERENCES' THEN 'x'
+		WHEN 'SELECT' THEN 'r'
+		WHEN 'TEMPORARY' THEN 'T'
+		WHEN 'TRIGGER' THEN 't'
+		WHEN 'TRUNCATE' THEN 'D'
+		WHEN 'UPDATE' THEN 'w'
+		WHEN 'USAGE' THEN 'U'
+		ELSE 'UNKNOWN'
+	END AS privilege_type
+  FROM
+    (SELECT rel.relacl
+        FROM pg_class rel
+          LEFT OUTER JOIN pg_tablespace spc on spc.oid=rel.reltablespace
+          LEFT OUTER JOIN pg_constraint con ON con.conrelid=rel.oid AND con.contype='p'
+          LEFT OUTER JOIN pg_class tst ON tst.oid = rel.reltoastrelid
+          LEFT JOIN pg_type typ ON rel.reloftype=typ.oid
+        WHERE rel.relkind IN ('r','s','t') AND rel.relnamespace = {{ scid }}::oid
+            AND rel.oid = {{ tid }}::oid
+    ) acl,
+    (SELECT (d).grantee AS grantee, (d).grantor AS grantor, (d).is_grantable
+        AS is_grantable, (d).privilege_type AS privilege_type FROM (SELECT
+        aclexplode(rel.relacl) as d
+        FROM pg_class rel
+          LEFT OUTER JOIN pg_tablespace spc on spc.oid=rel.reltablespace
+          LEFT OUTER JOIN pg_constraint con ON con.conrelid=rel.oid AND con.contype='p'
+          LEFT OUTER JOIN pg_class tst ON tst.oid = rel.reltoastrelid
+          LEFT JOIN pg_type typ ON rel.reloftype=typ.oid
+        WHERE rel.relkind IN ('r','s','t') AND rel.relnamespace = {{ scid }}::oid
+            AND rel.oid = {{ tid }}::oid
+        ) a) d
+    ) d
+  LEFT JOIN pg_catalog.pg_roles g ON (d.grantor = g.oid)
+  LEFT JOIN pg_catalog.pg_roles gt ON (d.grantee = gt.oid)
+GROUP BY g.rolname, gt.rolname
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/backend_support.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/backend_support.sql
new file mode 100644
index 0000000..f9b9564
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/backend_support.sql
@@ -0,0 +1,18 @@
+SELECT
+ CASE WHEN nsp.nspname IN ('sys', 'dbo', 'information_schema') THEN true ELSE false END AS dbSupport
+FROM pg_namespace nsp
+WHERE nsp.oid={{scid}}::int
+AND (
+	(nspname = 'pg_catalog' AND EXISTS
+	                               (SELECT 1 FROM pg_class WHERE relname = 'pg_class' AND relnamespace = nsp.oid LIMIT 1))
+	OR (nspname = 'pgagent' AND EXISTS
+	                               (SELECT 1 FROM pg_class WHERE relname = 'pga_job' AND relnamespace = nsp.oid LIMIT 1))
+	OR (nspname = 'information_schema' AND EXISTS
+	                               (SELECT 1 FROM pg_class WHERE relname = 'tables' AND relnamespace = nsp.oid LIMIT 1))
+	OR (nspname LIKE '_%' AND EXISTS
+	                               (SELECT 1 FROM pg_proc WHERE proname='slonyversion' AND pronamespace = nsp.oid LIMIT 1))
+)
+AND
+ nspname NOT LIKE E'pg\\temp\\%'
+AND
+ nspname NOT LIKE E'pg\\toast_temp\\%'
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/create.sql
new file mode 100644
index 0000000..c0fb5e4
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/create.sql
@@ -0,0 +1,157 @@
+{% import 'macros/schemas/security.macros' as SECLABLE %}
+{% import 'macros/schemas/privilege.macros' as PRIVILEGE %}
+{% import 'macros/variable.macros' as VARIABLE %}
+{% import 'column/macros/security.macros' as COLUMN_SECLABLE %}
+{% import 'column/macros/privilege.macros' as COLUMN_PRIVILEGE %}
+{% import 'table/sql/macros/constraints.macro' as CONSTRAINTS %}
+{#===========================================#}
+{#====== MAIN TABLE TEMPLATE STARTS HERE ======#}
+{#===========================================#}
+{#
+ If user has not provided any details but only name then
+ add empty bracket with table name
+#}
+{% set empty_bracket = ""%}
+{% if data.coll_inherits|length == 0 and  data.columns|length == 0 and not data.typname and not data.like_relation and data.primary_key|length == 0 and data.unique_constraint|length == 0 and data.foreign_key|length == 0 and data.check_constraint|length == 0 and data.exclude_constraint|length == 0 %}
+{% set empty_bracket = "\n(\n)"%}
+{% endif %}
+CREATE {% if data.relpersistence %}UNLOGGED {% endif %}TABLE {{conn|qtIdent(data.schema, data.name)}}{{empty_bracket}}
+{% if data.typname %}
+    OF {{ data.typname }}
+{% endif %}
+{% if data.like_relation or data.coll_inherits or data.columns|length > 0 or data.primary_key|length > 0 or data.unique_constraint|length > 0 or data.foreign_key|length > 0 or data.check_constraint|length > 0 or data.exclude_constraint|length > 0 %}
+(
+{% endif %}
+{% if data.like_relation %}
+    LIKE {{ data.like_relation }}{% if data.like_default_value %}
+
+        INCLUDING DEFAULTS{% endif %}{% if data.like_constraints %}
+
+        INCLUDING CONSTRAINTS{% endif %}{% if data.like_indexes %}
+
+        INCLUDING INDEXES{% endif %}{% if data.like_storage %}
+
+        INCLUDING STORAGE{% endif %}{% if data.like_comments %}
+
+        INCLUDING COMMENTS{% endif %}{% if data.columns|length > 0 %},
+{% endif %}
+
+{% endif %}
+{### Add columns ###}
+{% if data.columns and data.columns|length > 0 %}
+{% for c in data.columns %}
+{% if c.name and c.cltype %}
+{% if loop.index != 1 %},
+{% endif %}
+    {{conn|qtIdent(c.name)}} {{c.cltype}}{% if c.attlen %}
+({{c.attlen}}{% if c.attprecision%}, {{c.attprecision}}{% endif %}){% endif %}{% if c.hasSqrBracket %}
+[]{% endif %}{% if c.collspcname %} COLLATE {{c.collspcname}}{% endif %}{% if c.attnotnull %} NOT NULL{% endif %}{% if c.defval %} DEFAULT {{c.defval}}{% endif %}
+{% endif %}
+{% endfor %}
+{% endif %}
+{# Macro to render for constraints #}
+{% if data.primary_key|length > 0 %}{% if data.columns|length > 0 %},{% endif %}
+{{CONSTRAINTS.PRIMARY_KEY(conn, data.primary_key[0])}}{% endif %}{% if data.unique_constraint|length > 0 %}{% if data.columns|length > 0 or data.primary_key|length > 0 %},{% endif %}
+{{CONSTRAINTS.UNIQUE(conn, data.unique_constraint)}}{% endif %}{% if data.foreign_key|length > 0 %}{% if data.columns|length > 0 or data.primary_key|length > 0 or data.unique_constraint|length > 0 %},{% endif %}
+{{CONSTRAINTS.FOREIGN_KEY(conn, data.foreign_key)}}{% endif %}{% if data.check_constraint|length > 0 %}{% if data.columns|length > 0 or data.primary_key|length > 0 or data.unique_constraint|length > 0 or data.foreign_key|length > 0 %},{% endif %}
+{{CONSTRAINTS.CHECK(conn, data.check_constraint)}}{% endif %}{% if data.exclude_constraint|length > 0 %}{% if data.columns|length > 0 or data.primary_key|length > 0 or data.unique_constraint|length > 0 or data.foreign_key|length > 0 or data.check_constraint|length > 0 %},{% endif %}
+{{CONSTRAINTS.EXCLUDE(conn, data.exclude_constraint)}}{% endif %}
+{% if data.like_relation or data.coll_inherits or data.columns|length > 0 or data.primary_key|length > 0 or data.unique_constraint|length > 0 or data.foreign_key|length > 0 or data.check_constraint|length > 0 or data.exclude_constraint|length > 0 %}
+
+)
+{% endif %}
+{### If we are inheriting it from another table(s) ###}
+{% if data.coll_inherits %}
+    INHERITS ({% for val in data.coll_inherits %}{% if loop.index != 1 %}, {% endif %}{{val}}{% endfor %})
+{% endif %}
+WITH (
+    OIDS = {% if data.relhasoids %}TRUE{% else %}FALSE{% endif %}{% if data.fillfactor %},
+    FILLFACTOR = {{ data.fillfactor }}{% endif %}{% if data.autovacuum_custom %},
+    autovacuum_enabled = {% if data.autovacuum_enabled %}TRUE{% else %}FALSE{% endif %}{% endif %}{% if data.toast_autovacuum %},
+    toast.autovacuum_enabled = {% if data.toast_autovacuum_enabled %}TRUE{% else %}FALSE{% endif %}
+{% endif %}{% if data.autovacuum_enabled and data.vacuum_table|length > 0 %}
+{% for opt in data.vacuum_table %}{% if opt.name and opt.value %}
+,
+    {{opt.name}} = {{opt.value}}{% endif %}
+{% endfor %}{% endif %}{% if data.toast_autovacuum_enabled and data.vacuum_toast|length > 0 %}
+{% for opt in data.vacuum_toast %}{% if opt.name and opt.value %}
+,
+    toast.{{opt.name}} = {{opt.value}}{% endif %}
+{% endfor %}{% endif %}
+
+)
+{### SQL for Tablespace ###}
+{% if data.spcname %}
+TABLESPACE {{ conn|qtIdent(data.spcname) }};
+{% endif %}
+{### Alter SQL for Owner ###}
+{% if data.relowner %}
+
+ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
+    OWNER to {{conn|qtIdent(data.relowner)}};
+{% endif %}
+{### Security Labels on Table ###}
+{% if data.seclabels and data.seclabels|length > 0 %}
+
+{% for r in data.seclabels %}
+{{ SECLABLE.SET(conn, 'TABLE', data.name, r.provider, r.label, data.schema) }}
+{% endfor %}
+{% endif %}
+{###  ACL on Table ###}
+{% if data.relacl %}
+
+{% for priv in data.relacl %}
+{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }}
+{% endfor %}
+{% endif %}
+{### SQL for COMMENT ###}
+{% if data.description %}
+COMMENT ON TABLE {{conn|qtIdent(data.schema, data.name)}}
+    IS {{data.description|qtLiteral}};
+{% endif %}
+{#===========================================#}
+{#====== MAIN TABLE TEMPLATE ENDS HERE ======#}
+{#===========================================#}
+{#===========================================#}
+{#  COLUMN SPECIFIC TEMPLATES STARTS HERE    #}
+{#===========================================#}
+{% if data.columns and data.columns|length > 0 %}
+{% for c in data.columns %}
+{% if c.description %}
+
+COMMENT ON COLUMN {{conn|qtIdent(data.schema, data.name, c.name)}}
+    IS {{c.description|qtLiteral}};
+{% endif %}
+{###  Add variables to column ###}
+{% if c.attoptions and c.attoptions|length > 0 %}
+
+ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
+    {{ VARIABLE.SET(conn, 'COLUMN', c.name, c.attoptions) }}
+{% endif %}
+{###  ACL ###}
+{% if c.attacl and c.attacl|length > 0 %}
+
+{% for priv in c.attacl %}
+    {{ COLUMN_PRIVILEGE.APPLY(conn, data.schema, data.name, c.name, priv.grantee, priv.without_grant, priv.with_grant) }}
+{% endfor %}
+{% endif %}
+{###  Security Lables ###}
+{% if c.seclabels and c.seclabels|length > 0 %}
+
+{% for r in c.seclabels %}
+{{ COLUMN_SECLABLE.APPLY(conn, 'COLUMN',data.schema, data.name, c.name, r.provider, r.label) }}
+{% endfor %}
+{% endif %}
+{% endfor %}
+{% endif %}
+{#===========================================#}
+{#   COLUMN SPECIFIC TEMPLATES ENDS HERE     #}
+{#===========================================#}
+{#======================================#}
+{#   CONSTRAINTS SPECIFIC TEMPLATES     #}
+{#======================================#}
+{{CONSTRAINTS.CONSTRAINT_COMMENTS(conn, data.schema, data.name, data.primary_key)}}
+{{CONSTRAINTS.CONSTRAINT_COMMENTS(conn, data.schema, data.name, data.unique_constraint)}}
+{{CONSTRAINTS.CONSTRAINT_COMMENTS(conn, data.schema, data.name, data.foreign_key)}}
+{{CONSTRAINTS.CONSTRAINT_COMMENTS(conn, data.schema, data.name, data.check_constraint)}}
+{{CONSTRAINTS.CONSTRAINT_COMMENTS(conn, data.schema, data.name, data.exclude_constraint)}}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/delete.sql
new file mode 100644
index 0000000..01d0314
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/delete.sql
@@ -0,0 +1 @@
+DROP TABLE {{conn|qtIdent(data.schema, data.name)}}{% if cascade %} CASCADE{% endif %};
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/depend.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/depend.sql
new file mode 100644
index 0000000..f5f39e7
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/depend.sql
@@ -0,0 +1,9 @@
+SELECT
+    ref.relname AS refname, d2.refclassid, dep.deptype AS deptype
+FROM pg_depend dep
+    LEFT JOIN pg_depend d2 ON dep.objid=d2.objid AND dep.refobjid != d2.refobjid
+    LEFT JOIN pg_class ref ON ref.oid=d2.refobjid
+    LEFT JOIN pg_attribute att ON d2.refclassid=att.attrelid AND d2.refobjsubid=att.attnum
+    {{ where }} AND
+    dep.classid=(SELECT oid FROM pg_class WHERE relname='pg_attrdef') AND
+    dep.refobjid NOT IN (SELECT d3.refobjid FROM pg_depend d3 WHERE d3.objid=d2.refobjid)
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/enable_disable_trigger.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/enable_disable_trigger.sql
new file mode 100644
index 0000000..a4ab154
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/enable_disable_trigger.sql
@@ -0,0 +1,2 @@
+ALTER TABLE {{ conn|qtIdent(data.schema, data.name) }}
+    {% if is_enable_trigger == True %}ENABLE{% else %}DISABLE{% endif %} TRIGGER ALL;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/get_columns_for_table.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/get_columns_for_table.sql
new file mode 100644
index 0000000..3d6bbb7
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/get_columns_for_table.sql
@@ -0,0 +1,16 @@
+SELECT
+    a.attname AS name, format_type(a.atttypid, NULL) AS cltype,
+    quote_ident(n.nspname)||'.'||quote_ident(c.relname) as inheritedfrom,
+    c.oid as inheritedid
+FROM
+    pg_class c
+JOIN
+    pg_namespace n ON c.relnamespace=n.oid
+JOIN
+    pg_attribute a ON a.attrelid = c.oid AND NOT a.attisdropped AND a.attnum > 0
+WHERE
+{% if tid %}
+    c.oid = {{tid}}::OID
+{% else %}
+    c.relname = {{tname|qtLiteral}}
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/get_inherits.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/get_inherits.sql
new file mode 100644
index 0000000..50f9a1d
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/get_inherits.sql
@@ -0,0 +1,13 @@
+SELECT c.oid, c.relname , nspname,
+CASE WHEN (nspname NOT LIKE E'pg\_%' AND nspname <> 'public') THEN
+ quote_ident(nspname)||'.'||quote_ident(c.relname)
+ELSE quote_ident(c.relname)
+END AS inherits
+FROM pg_class c
+JOIN pg_namespace n
+ON n.oid=c.relnamespace
+WHERE relkind='r'
+{% if not show_system_objects %}
+AND (n.nspname NOT LIKE E'pg\_%' AND n.nspname NOT in ('information_schema'))
+{% endif %}
+ORDER BY relnamespace, c.relname
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/get_oftype.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/get_oftype.sql
new file mode 100644
index 0000000..aed42f2
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/get_oftype.sql
@@ -0,0 +1,6 @@
+SELECT t.oid,
+  quote_ident(n.nspname)||'.'||quote_ident(t.typname) AS typname
+  FROM pg_type t, pg_namespace n
+WHERE t.typtype='c' AND t.typnamespace=n.oid
+  AND NOT (n.nspname like 'pg_%' OR n.nspname='information_schema')
+ORDER BY typname;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/get_oid.sql
new file mode 100644
index 0000000..e9dc772
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/get_oid.sql
@@ -0,0 +1,5 @@
+SELECT rel.oid as tid
+FROM pg_class rel
+WHERE rel.relkind IN ('r','s','t')
+AND rel.relnamespace = {{ scid }}::oid
+AND rel.relname = {{data.name|qtLiteral}}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/get_relations.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/get_relations.sql
new file mode 100644
index 0000000..431ee88
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/get_relations.sql
@@ -0,0 +1,6 @@
+SELECT c.oid, quote_ident(n.nspname)||'.'||quote_ident(c.relname) AS like_relation
+FROM pg_class c, pg_namespace n
+WHERE c.relnamespace=n.oid
+AND
+c.relkind IN ('r', 'v', 'f')
+ORDER BY 1;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/get_tables_for_constraints.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/get_tables_for_constraints.sql
new file mode 100644
index 0000000..1362463
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/get_tables_for_constraints.sql
@@ -0,0 +1,8 @@
+SELECT cl.oid as value, quote_ident(nspname)||'.'||quote_ident(relname) AS label
+FROM pg_namespace nsp, pg_class cl
+WHERE relnamespace=nsp.oid AND relkind='r'
+   AND nsp.nspname NOT LIKE E'pg\_temp\_%'
+   {% if not show_sysobj %}
+   AND (nsp.nspname NOT LIKE E'pg\_%' AND nsp.nspname NOT in ('information_schema'))
+   {% endif %}
+ORDER BY nspname, relname
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/get_types_where_condition.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/get_types_where_condition.sql
new file mode 100644
index 0000000..fadfc99
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/get_types_where_condition.sql
@@ -0,0 +1,10 @@
+{### Additional where condition for get_types route for column node ###}
+typisdefined AND typtype IN ('b', 'c', 'd', 'e', 'r')
+AND NOT EXISTS (SELECT 1 FROM pg_class WHERE relnamespace=typnamespace
+AND relname = typname AND relkind != 'c') AND
+(typname NOT LIKE '_%' OR NOT EXISTS (SELECT 1 FROM pg_class WHERE
+relnamespace=typnamespace AND relname = substring(typname FROM 2)::name
+AND relkind != 'c'))
+{% if not show_system_objects %}
+AND nsp.nspname != 'information_schema'
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/nodes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/nodes.sql
new file mode 100644
index 0000000..43f14cb
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/nodes.sql
@@ -0,0 +1,6 @@
+SELECT rel.oid, rel.relname AS name,
+    (SELECT count(*) FROM pg_trigger WHERE tgrelid=rel.oid AND tgisinternal = FALSE) AS triggercount,
+    (SELECT count(*) FROM pg_trigger WHERE tgrelid=rel.oid AND tgisinternal = FALSE AND tgenabled = 'O') AS has_enable_triggers
+FROM pg_class rel
+    WHERE rel.relkind IN ('r','s','t') AND rel.relnamespace = {{ scid }}::oid
+    ORDER BY rel.relname;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/properties.sql
new file mode 100644
index 0000000..99727c9
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/properties.sql
@@ -0,0 +1,65 @@
+SELECT rel.oid, rel.relname AS name, rel.reltablespace AS spcoid,rel.relacl AS relacl_str,
+  (CASE WHEN length(spc.spcname) > 0 THEN spc.spcname ELSE 'pg_default' END) as spcname,
+  (select nspname FROM pg_namespace WHERE oid = {{scid}}::oid ) as schema,
+  pg_get_userbyid(rel.relowner) AS relowner, rel.relhasoids,
+  rel.relhassubclass, rel.reltuples, des.description, con.conname, con.conkey,
+	EXISTS(select 1 FROM pg_trigger
+			JOIN pg_proc pt ON pt.oid=tgfoid AND pt.proname='logtrigger'
+			JOIN pg_proc pc ON pc.pronamespace=pt.pronamespace AND pc.proname='slonyversion'
+			WHERE tgrelid=rel.oid) AS isrepl,
+	(SELECT count(*) FROM pg_trigger WHERE tgrelid=rel.oid AND tgisinternal = FALSE) AS triggercount,
+	(SELECT ARRAY(SELECT CASE WHEN (nspname NOT LIKE E'pg\_%' AND nspname <> 'public') THEN
+            quote_ident(nspname)||'.'||quote_ident(c.relname)
+            ELSE quote_ident(c.relname) END AS inherited_tables
+    FROM pg_inherits i
+    JOIN pg_class c ON c.oid = i.inhparent
+    JOIN pg_namespace n ON n.oid=c.relnamespace
+    WHERE i.inhrelid = rel.oid ORDER BY inhseqno)) AS coll_inherits,
+  (SELECT count(*)
+		FROM pg_inherits i
+      JOIN pg_class c ON c.oid = i.inhparent
+      JOIN pg_namespace n ON n.oid=c.relnamespace
+		WHERE i.inhrelid = rel.oid) AS inherited_tables_cnt,
+	(CASE WHEN rel.relpersistence = 'u' THEN true ELSE false END) AS relpersistence,
+	substring(array_to_string(rel.reloptions, ',') FROM 'fillfactor=([0-9]*)') AS fillfactor,
+	(CASE WHEN (substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)') = 'true')
+	  THEN true ELSE false END) AS autovacuum_enabled,
+	substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS autovacuum_vacuum_threshold,
+	substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.][0-9]*)') AS autovacuum_vacuum_scale_factor,
+	substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_analyze_threshold=([0-9]*)') AS autovacuum_analyze_threshold,
+	substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_analyze_scale_factor=([0-9]*[.][0-9]*)') AS autovacuum_analyze_scale_factor,
+	substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS autovacuum_vacuum_cost_delay,
+	substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS autovacuum_vacuum_cost_limit,
+	substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_freeze_min_age=([0-9]*)') AS autovacuum_freeze_min_age,
+	substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_freeze_max_age=([0-9]*)') AS autovacuum_freeze_max_age,
+	substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS autovacuum_freeze_table_age,
+	(CASE WHEN (substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)') =  'true')
+	  THEN true ELSE false END) AS toast_autovacuum_enabled,
+	substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS toast_autovacuum_vacuum_threshold,
+	substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.][0-9]*)') AS toast_autovacuum_vacuum_scale_factor,
+	substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_analyze_threshold=([0-9]*)') AS toast_autovacuum_analyze_threshold,
+	substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_analyze_scale_factor=([0-9]*[.][0-9]*)') AS toast_autovacuum_analyze_scale_factor,
+	substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS toast_autovacuum_vacuum_cost_delay,
+	substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS toast_autovacuum_vacuum_cost_limit,
+	substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_min_age=([0-9]*)') AS toast_autovacuum_freeze_min_age,
+	substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_max_age=([0-9]*)') AS toast_autovacuum_freeze_max_age,
+	substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS toast_autovacuum_freeze_table_age,
+	array_to_string(rel.reloptions, ',') AS table_vacuum_settings_str,
+	array_to_string(tst.reloptions, ',') AS toast_table_vacuum_settings_str,
+	rel.reloptions AS reloptions, tst.reloptions AS toast_reloptions, rel.reloftype, typ.typname,
+	(CASE WHEN rel.reltoastrelid = 0 THEN false ELSE true END) AS hastoasttable,
+    -- Added for pgAdmin4
+	(CASE WHEN (substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)'))::boolean  THEN true ELSE false END) AS autovacuum_custom,
+	(CASE WHEN (substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)'))::boolean  AND rel.reltoastrelid != 0 THEN true ELSE false END) AS toast_autovacuum,
+
+	(SELECT array_agg(provider || '=' || label) FROM pg_seclabels sl1 WHERE sl1.objoid=rel.oid AND sl1.objsubid=0) AS seclabels,
+	(CASE WHEN rel.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_table
+FROM pg_class rel
+  LEFT OUTER JOIN pg_tablespace spc on spc.oid=rel.reltablespace
+  LEFT OUTER JOIN pg_description des ON (des.objoid=rel.oid AND des.objsubid=0 AND des.classoid='pg_class'::regclass)
+  LEFT OUTER JOIN pg_constraint con ON con.conrelid=rel.oid AND con.contype='p'
+  LEFT OUTER JOIN pg_class tst ON tst.oid = rel.reltoastrelid
+  LEFT JOIN pg_type typ ON rel.reloftype=typ.oid
+WHERE rel.relkind IN ('r','s','t') AND rel.relnamespace = {{ scid }}::oid
+{% if tid %}  AND rel.oid = {{ tid }}::oid {% endif %}
+ORDER BY rel.relname;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/reset_stats.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/reset_stats.sql
new file mode 100644
index 0000000..36eca0d
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/reset_stats.sql
@@ -0,0 +1 @@
+SELECT pg_stat_reset_single_table_counters({{tid}})
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/sql.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/sql.sql
new file mode 100644
index 0000000..17b35ae
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/sql.sql
@@ -0,0 +1 @@
+TAKE ASHESH'S HELP ON THIS TASK :-)
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/truncate.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/truncate.sql
new file mode 100644
index 0000000..6a276f3
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/truncate.sql
@@ -0,0 +1 @@
+TRUNCATE TABLE {{conn|qtIdent(data.schema, data.name)}}{% if cascade %} CASCADE{% endif %};
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/update.sql
new file mode 100644
index 0000000..a97ac30
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/9.5_plus/update.sql
@@ -0,0 +1,201 @@
+{% import 'macros/schemas/security.macros' as SECLABLE %}
+{% import 'macros/schemas/privilege.macros' as PRIVILEGE %}
+{% import 'macros/variable.macros' as VARIABLE %}
+{#####################################################}
+{## Rename table ##}
+{#####################################################}
+{% if data.name and data.name != o_data.name %}
+ALTER TABLE {{conn|qtIdent(o_data.schema, o_data.name)}}
+    RENAME TO {{conn|qtIdent(data.name)}};
+
+{% endif %}
+{#####################################################}
+{## Change table schema ##}
+{#####################################################}
+{% if data.schema and data.schema != o_data.schema %}
+ALTER TABLE {{conn|qtIdent(o_data.schema, data.name)}}
+  SET SCHEMA {{conn|qtIdent(data.schema)}};
+
+{% endif %}
+{#####################################################}
+{## Change table owner ##}
+{#####################################################}
+{% if data.relowner and data.relowner != o_data.relowner %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
+    OWNER TO {{conn|qtIdent(data.relowner)}};
+
+{% endif %}
+{#####################################################}
+{## Update Inherits table definition ##}
+{#####################################################}
+{% if data.coll_inherits_added|length > 0 %}
+{% for val in data.coll_inherits_added %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
+    INHERIT {{val}};
+
+{% endfor %}
+{% endif %}
+{% if data.coll_inherits_removed|length > 0 %}
+{% for val in data.coll_inherits_removed %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
+    NO INHERIT {{val}};
+
+{% endfor %}
+{% endif %}
+{#####################################################}
+{## Change hasOID attribute of table ##}
+{#####################################################}
+{% if data.relhasoids is defined and data.relhasoids != o_data.relhasoids %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
+    SET {% if data.relhasoids %}WITH{% else %}WITHOUT{% endif %} OIDS;
+
+{% endif %}
+{#####################################################}
+{## Change tablespace ##}
+{#####################################################}
+{% if data.spcname and data.spcname != o_data.spcname %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
+    SET TABLESPACE {{conn|qtIdent(data.spcname)}};
+
+{% endif %}
+{#####################################################}
+{## change fillfactore settings ##}
+{#####################################################}
+{% if data.fillfactor and data.fillfactor != o_data.fillfactor %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
+    SET (FILLFACTOR={{data.fillfactor}});
+
+{% endif %}
+{###############################}
+{## Table AutoVacuum settings ##}
+{###############################}
+{% if o_data.autovacuum_custom and data.autovacuum_custom == false %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.name)}} RESET (
+    autovacuum_enabled,
+    autovacuum_analyze_scale_factor,
+    autovacuum_analyze_threshold,
+    autovacuum_freeze_max_age,
+    autovacuum_vacuum_cost_delay,
+    autovacuum_vacuum_cost_limit,
+    autovacuum_vacuum_scale_factor,
+    autovacuum_vacuum_threshold,
+    autovacuum_freeze_min_age,
+    autovacuum_freeze_table_age
+);
+{% elif data.autovacuum_enabled != o_data.autovacuum_enabled %}
+{% if data.autovacuum_enabled and o_data.autovacuum_enabled == false %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.name)}} SET (
+    autovacuum_enabled = true{% elif data.autovacuum_enabled == false and o_data.autovacuum_enabled %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.name)}} SET (
+       autovacuum_enabled = false{% endif %}
+{% if (data.autovacuum_enabled or o_data.autovacuum_enabled )and data.vacuum_table and data.vacuum_table.changed|length > 0 %}
+{% for opt in data.vacuum_table.changed %}{% if opt.name and opt.value %}
+{% if flag or (data.autovacuum_enabled and o_data.autovacuum_enabled == false) or (data.autovacuum_enabled == false and o_data.autovacuum_enabled) %}
+,
+{% else %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.name)}} SET (
+{% set flag = true %}
+{% endif %}
+    {{opt.name}} = {{opt.value}}{% endif %}
+{% if loop.index == data.vacuum_table.changed|length and (flag or (data.autovacuum_enabled and o_data.autovacuum_enabled == false) or (data.autovacuum_enabled == false and o_data.autovacuum_enabled))%}
+
+);
+{% endif %}
+{% endfor %}
+{% elif (data.autovacuum_enabled and o_data.autovacuum_enabled == false) or (data.autovacuum_enabled == false and o_data.autovacuum_enabled) %}
+
+);
+{% endif %}
+{% endif %}
+{#####################################}
+{## Toast table AutoVacuum settings ##}
+{#####################################}
+{% if o_data.toast_autovacuum and data.toast_autovacuum == false %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.name)}} RESET (
+    toast.autovacuum_enabled,
+    toast.autovacuum_freeze_max_age,
+    toast.autovacuum_vacuum_cost_delay,
+    toast.autovacuum_vacuum_cost_limit,
+    toast.autovacuum_vacuum_scale_factor,
+    toast.autovacuum_vacuum_threshold,
+    toast.autovacuum_freeze_min_age,
+    toast.autovacuum_freeze_table_age,
+    toast.autovacuum_analyze_threshold,
+    toast.autovacuum_analyze_scale_factor
+);
+{% elif data.toast_autovacuum_enabled != o_data.toast_autovacuum_enabled %}
+{% if data.toast_autovacuum_enabled and o_data.toast_autovacuum_enabled == false %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.name)}} SET (
+    toast.autovacuum_enabled = true{% elif data.toast_autovacuum_enabled == false and o_data.toast_autovacuum_enabled %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.name)}} SET (
+       toast.autovacuum_enabled = false{% endif %}
+{% if (data.toast_autovacuum_enabled or o_data.toast_autovacuum_enabled )and data.vacuum_toast and data.vacuum_toast.changed|length > 0 %}
+{% for opt in data.vacuum_toast.changed %}{% if opt.name and opt.value %}
+{% if flag or (data.toast_autovacuum_enabled and o_data.toast_autovacuum_enabled == false) or (data.toast_autovacuum_enabled == false and o_data.toast_autovacuum_enabled) %}
+,
+{% else %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.name)}} SET (
+{% set flag = true %}
+{% endif %}
+    toast.{{opt.name}} = {{opt.value}}{% endif %}
+{% if loop.index == data.vacuum_toast.changed|length and (flag or (data.toast_autovacuum_enabled and o_data.toast_autovacuum_enabled == false) or (data.toast_autovacuum_enabled == false and o_data.toast_autovacuum_enabled))%}
+
+);
+{% endif %}
+{% endfor %}
+{% elif (data.toast_autovacuum_enabled and o_data.toast_autovacuum_enabled == false) or (data.toast_autovacuum_enabled == false and o_data.toast_autovacuum_enabled) %}
+
+);
+{% endif %}
+{% endif %}
+{#####################################################}
+{## Change table comments ##}
+{#####################################################}
+{% if data.description and data.description != o_data.description %}
+COMMENT ON TABLE {{conn|qtIdent(data.schema, data.name)}}
+  IS {{data.description|qtLiteral}};
+
+{% endif %}
+{#####################################################}
+{## Update table Privileges ##}
+{#####################################################}
+{% if data.relacl %}
+{% if 'deleted' in data.relacl %}
+{% for priv in data.relacl.deleted %}
+{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }}
+{% endfor %}
+{% endif %}
+{% if 'changed' in data.relacl %}
+{% for priv in data.relacl.changed %}
+{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }}
+{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }}
+{% endfor %}
+{% endif %}
+{% if 'added' in data.relacl %}
+{% for priv in data.relacl.added %}
+{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }}
+{% endfor %}
+{% endif %}
+{% endif %}
+{#####################################################}
+{## Update table SecurityLabel ##}
+{#####################################################}
+{% if data.seclabels and data.seclabels|length > 0 %}
+{% set seclabels = data.seclabels %}
+{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %}
+{% for r in seclabels.deleted %}
+{{ SECLABEL.UNSET(conn, 'TABLE', data.name, r.provider, data.schema) }}
+{% endfor %}
+{% endif %}
+{% if 'added' in seclabels and seclabels.added|length > 0 %}
+{% for r in seclabels.added %}
+{{ SECLABLE.SET(conn, 'TABLE', data.name, r.provider, r.label, data.schema) }}
+{% endfor %}
+{% endif %}
+{% if 'changed' in seclabels and seclabels.changed|length > 0 %}
+{% for r in seclabels.changed %}
+{{ SECLABLE.SET(conn, 'TABLE', data.name, r.provider, r.label, data.schema) }}
+{% endfor %}
+{% endif %}
+
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/macros/constraints.macro b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/macros/constraints.macro
new file mode 100644
index 0000000..fe7389a
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/macros/constraints.macro
@@ -0,0 +1,103 @@
+{##########################}
+{# Macros for Constraints #}
+{##########################}
+{#    CREATE MODE ONLY    #}
+{##########################}
+{% macro PRIMARY_KEY(conn, data) -%}
+{% if data.columns|length > 0 %}
+
+    {% if data.name %}CONSTRAINT {{conn|qtIdent(data.name)}} {% endif %}PRIMARY KEY ({% for c in data.columns%}
+{% if loop.index != 1 %}, {% endif %}{{conn|qtIdent(c.column)}}{% endfor %}){% if data.fillfactor %}
+
+        WITH (FILLFACTOR={{data.fillfactor}}){% endif %}
+{% if data.spcname and data.spcname != "pg_default" %}
+
+        USING INDEX TABLESPACE {{ conn|qtIdent(data.spcname) }}{% endif %}
+{% if data.condeferrable %}
+
+        DEFERRABLE{% if data.condeferred %} INITIALLY DEFERRED{% endif%}{% endif%}
+{% endif %}
+{%- endmacro %}
+{% macro UNIQUE(conn, unique_data) -%}
+{% for data in unique_data %}
+{% if data.columns|length > 0 %}{% if loop.index !=1 %},{% endif %}
+
+    {% if data.name %}CONSTRAINT {{conn|qtIdent(data.name)}} {% endif %}UNIQUE ({% for c in data.columns%}
+{% if loop.index != 1 %}, {% endif %}{{conn|qtIdent(c.column)}}{% endfor %}){% if data.fillfactor %}
+
+        WITH (FILLFACTOR={{data.fillfactor}}){% endif %}
+{% if data.spcname and data.spcname != "pg_default" %}
+
+        USING INDEX TABLESPACE {{ conn|qtIdent(data.spcname) }}{% endif %}
+{% if data.condeferrable %}
+
+        DEFERRABLE{% if data.condeferred %} INITIALLY DEFERRED{% endif%}{% endif%}
+{% endif %}
+{% endfor %}
+{%- endmacro %}
+{% macro CHECK(conn, check_data) -%}
+{% for data in check_data %}{% if loop.index !=1 %},{% endif %}
+
+    {% if data.name %}CONSTRAINT {{ conn|qtIdent(data.name) }} {% endif%}CHECK ({{ data.consrc }}){% if data.convalidated %}
+ NOT VALID{% endif %}{% if data.connoinherit %} NO INHERIT{% endif %}
+{% endfor %}
+{%- endmacro %}
+{% macro FOREIGN_KEY(conn, foreign_key_data) -%}
+{% for data in foreign_key_data %}{% if loop.index != 1 %},{% endif %}
+
+    {% if data.name %}CONSTRAINT {{conn|qtIdent(data.name)}} {% endif %}FOREIGN KEY ({% for columnobj in data.columns %}{% if loop.index != 1 %}
+, {% endif %}{{ conn|qtIdent(columnobj.local_column)}}{% endfor %})
+        REFERENCES {{ conn|qtIdent(data.remote_schema, data.remote_table) }} ({% for columnobj in data.columns %}{% if loop.index != 1 %}
+, {% endif %}{{ conn|qtIdent(columnobj.referenced)}}{% endfor %}) {% if data.confmatchtype %}MATCH FULL{% else %}MATCH SIMPLE{% endif%}
+
+        ON UPDATE{% if data.confupdtype  == 'a' %}
+ NO ACTION{% elif data.confupdtype  == 'r' %}
+ RESTRICT{% elif data.confupdtype  == 'c' %}
+ CASCADE{% elif data.confupdtype  == 'n' %}
+ SET NULL{% elif data.confupdtype  == 'd' %}
+ SET DEFAULT{% endif %}
+
+        ON DELETE{% if data.confdeltype  == 'a' %}
+ NO ACTION{% elif data.confdeltype  == 'r' %}
+ RESTRICT{% elif data.confdeltype  == 'c' %}
+ CASCADE{% elif data.confdeltype  == 'n' %}
+ SET NULL{% elif data.confdeltype  == 'd' %}
+ SET DEFAULT{% endif %}
+{% if data.condeferrable %}
+
+        DEFERRABLE{% if data.condeferred %}
+ INITIALLY DEFERRED{% endif%}
+{% endif%}
+{% if data.convalidated %}
+
+        NOT VALID{% endif%}
+{% endfor %}
+{%- endmacro %}
+{% macro EXCLUDE(conn, exclude_data) -%}
+{% for data in exclude_data %}{% if loop.index != 1 %},{% endif %}
+
+    {% if data.name %}CONSTRAINT {{ conn|qtIdent(data.name) }} {% endif%}EXCLUDE {% if data.amname and data.amname != '' %}USING {{data.amname}}{% endif %} ({% for col in data.columns %}{% if loop.index != 1 %},
+        {% endif %}{{ conn|qtIdent(col.column)}} {% if col.oper_class and col.oper_class != '' %}{{col.oper_class}} {% endif%}{% if col.order %}ASC{% else %}DESC{% endif %} NULLS {% if col.nulls_order %}FIRST{% else %}LAST{% endif %} WITH {{col.operator}}{% endfor %}){% if data.fillfactor %}
+
+        WITH (FILLFACTOR={{data.fillfactor}}){% endif %}
+        {% if data.spcname and data.spcname != "pg_default" %}
+
+        USING INDEX TABLESPACE {{ conn|qtIdent(data.spcname) }}{% endif %}
+{% if data.condeferrable %}
+
+        DEFERRABLE{% if data.condeferred %}
+ INITIALLY DEFERRED{% endif%}
+{% endif%}{% if data.constraint %} WHERE ({{data.constraint}}){% endif%}
+{% endfor %}
+{%- endmacro %}
+{##########################}
+{#     COMMENTS ONLY      #}
+{##########################}
+{% macro CONSTRAINT_COMMENTS(conn, schema, table, data) -%}
+{% for d in data %}
+{% if d.name and d.comment %}
+COMMENT ON CONSTRAINT {{ conn|qtIdent(d.name) }} ON {{ conn|qtIdent(schema, table) }}
+    IS {{ d.comment|qtLiteral }};
+{% endif %}
+{% endfor %}
+{%- endmacro %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/alter.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/alter.sql
new file mode 100644
index 0000000..93f323e
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/alter.sql
@@ -0,0 +1,9 @@
+{## Alter index to use cluster type ##}
+{% if data.indisclustered %}
+ALTER TABLE {{conn|qtIdent(data.schema, data.table)}}
+    CLUSTER ON {{conn|qtIdent(data.name)}};
+{% endif %}
+{## Changes description ##}
+{% if data.description %}
+COMMENT ON INDEX {{conn|qtIdent(data.name)}}
+    IS {{data.description|qtLiteral}};{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/backend_support.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/backend_support.sql
new file mode 100644
index 0000000..bb5e8d8
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/backend_support.sql
@@ -0,0 +1,9 @@
+{#=============Checks if it is materialized view========#}
+{% if vid %}
+SELECT
+    CASE WHEN c.relkind = 'm' THEN False ELSE True END As m_view
+FROM
+    pg_class c
+WHERE
+    c.oid = {{ vid }}::oid
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/create.sql
new file mode 100644
index 0000000..b619f71
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/create.sql
@@ -0,0 +1,27 @@
+{### Set a flag which allows us to put OR between events ###}
+{% set or_flag = False %}
+CREATE{% if data.is_constraint_trigger %} CONSTRAINT{% endif %} TRIGGER {{ conn|qtIdent(data.name) }}
+    {{data.fires}} {% if data.evnt_insert %}INSERT{% set or_flag = True %}
+{% endif %}{% if data.evnt_delete %}
+{% if or_flag %} OR {% endif %}DELETE{% set or_flag = True %}
+{% endif %}{% if data.evnt_turncate %}
+{% if or_flag %} OR {% endif %}TRUNCATE{% set or_flag = True %}
+{% endif %}{% if data.evnt_update %}
+{% if or_flag %} OR {% endif %}UPDATE {% if data.columns|length > 0 %}OF {% for c in data.columns %}{% if loop.index != 1 %}, {% endif %}{{ conn|qtIdent(c.column) }}{% endfor %}{% endif %}
+{% endif %}
+
+    ON {{ conn|qtIdent(data.schema, data.table) }}
+{% if data.tgdeferrable %}
+    DEFERRABLE{% if data.tginitdeferred %} INITIALLY DEFERRED{% endif %}
+{% endif %}
+    FOR EACH{% if data.is_row_trigger %} ROW{% else %} STATEMENT{% endif %}
+{% if data.whenclause %}
+
+    WHEN {{ data.whenclause }}{% endif %}
+
+    {% if data.code %}{{ data.code }}{% else %}EXECUTE PROCEDURE {{ data.tfunction }}{% if data.tgargs %}({{ data.tgargs }}){% else %}(){% endif%}{% endif%};
+
+{% if data.description %}
+COMMENT ON TRIGGER {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(data.schema, data.table) }}
+    IS {{data.description|qtLiteral}};
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/delete.sql
new file mode 100644
index 0000000..4c6e82b
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/delete.sql
@@ -0,0 +1 @@
+DROP TRIGGER {{conn|qtIdent(data.name)}} ON {{conn|qtIdent(data.nspname, data.relname )}}{% if cascade %} CASCADE{% endif %};
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/enable_disable_trigger.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/enable_disable_trigger.sql
new file mode 100644
index 0000000..b700927
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/enable_disable_trigger.sql
@@ -0,0 +1,2 @@
+ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }}
+    {% if data.is_enable_trigger == True %}ENABLE{% else %}DISABLE{% endif %} TRIGGER {{ conn|qtIdent(data.name) }};
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/get_columns.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/get_columns.sql
new file mode 100644
index 0000000..c74c68b
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/get_columns.sql
@@ -0,0 +1,6 @@
+SELECT att.attname as name
+FROM pg_attribute att
+    WHERE att.attrelid = {{tid}}::oid
+    AND att.attnum IN ({{ clist }})
+    AND att.attisdropped IS FALSE
+    ORDER BY att.attnum
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/get_oid.sql
new file mode 100644
index 0000000..cf30257
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/get_oid.sql
@@ -0,0 +1,5 @@
+SELECT t.oid
+FROM pg_trigger t
+    WHERE NOT tgisinternal
+    AND tgrelid = {{tid}}::OID
+    AND tgname = {{data.name|qtLiteral}};
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/get_parent.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/get_parent.sql
new file mode 100644
index 0000000..5dd5d3c
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/get_parent.sql
@@ -0,0 +1,5 @@
+SELECT nsp.nspname AS schema ,rel.relname AS table
+FROM pg_class rel
+    JOIN pg_namespace nsp
+    ON rel.relnamespace = nsp.oid::int
+    WHERE rel.oid = {{tid}}::int
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/get_triggerfunctions.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/get_triggerfunctions.sql
new file mode 100644
index 0000000..6134e0e
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/get_triggerfunctions.sql
@@ -0,0 +1,11 @@
+SELECT quote_ident(nspname) || '.' || quote_ident(proname) AS tfunctions
+FROM pg_proc p, pg_namespace n, pg_language l
+    WHERE p.pronamespace = n.oid
+    AND p.prolang = l.oid
+    -- PGOID_TYPE_TRIGGER = 2279
+    AND l.lanname != 'edbspl' AND prorettype = 2279
+    -- If Show SystemObjects is not true
+    {% if not show_system_objects %}
+    AND (nspname NOT LIKE E'pg\_%' AND nspname NOT in ('information_schema'))
+    {% endif %}
+    ORDER BY nspname ASC, proname ASC
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/nodes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/nodes.sql
new file mode 100644
index 0000000..095ada3
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/nodes.sql
@@ -0,0 +1,5 @@
+SELECT t.oid, t.tgname as name, (CASE WHEN tgenabled = 'O' THEN true ElSE false END) AS is_enable_trigger
+FROM pg_trigger t
+    WHERE NOT tgisinternal
+    AND tgrelid = {{tid}}::OID
+    ORDER BY tgname;
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/properties.sql
new file mode 100644
index 0000000..535627b
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/properties.sql
@@ -0,0 +1,23 @@
+SELECT t.oid,t.tgname AS name, t.xmin, t.*, relname, CASE WHEN relkind = 'r' THEN TRUE ELSE FALSE END AS parentistable,
+    nspname, des.description, l.lanname, p.prosrc, p.proname AS tfunction,
+    COALESCE(substring(pg_get_triggerdef(t.oid), 'WHEN (.*) EXECUTE PROCEDURE'),
+    substring(pg_get_triggerdef(t.oid), 'WHEN (.*)  \\$trigger')) AS whenclause,
+    -- We need to convert tgargs column bytea datatype to array datatype
+    (string_to_array(encode(tgargs, 'escape'), '\000')::text[])[1:tgnargs] AS tgargs,
+{% if datlastsysoid %}
+    (CASE WHEN t.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_trigger,
+{% endif %}
+    (CASE WHEN tgconstraint != 0::OID THEN true ElSE false END) AS is_constarint,
+    (CASE WHEN tgenabled = 'O' THEN true ElSE false END) AS is_enable_trigger
+FROM pg_trigger t
+    JOIN pg_class cl ON cl.oid=tgrelid
+    JOIN pg_namespace na ON na.oid=relnamespace
+    LEFT OUTER JOIN pg_description des ON (des.objoid=t.oid AND des.classoid='pg_trigger'::regclass)
+    LEFT OUTER JOIN pg_proc p ON p.oid=t.tgfoid
+    LEFT OUTER JOIN pg_language l ON l.oid=p.prolang
+WHERE NOT tgisinternal
+    AND tgrelid = {{tid}}::OID
+{% if trid %}
+    AND t.oid = {{trid}}::OID
+{% endif %}
+ORDER BY tgname;
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/update.sql
new file mode 100644
index 0000000..fa64809
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/trigger/sql/9.1_plus/update.sql
@@ -0,0 +1,8 @@
+{% if data.name and o_data.name != data.name %}
+ALTER TRIGGER {{ conn|qtIdent(o_data.name) }} ON {{ conn|qtIdent(o_data.nspname, o_data.relname) }}
+    RENAME TO {{ conn|qtIdent(data.name) }};
+{% endif %}
+{% if data.description is defined  and o_data.description != data.description %}
+COMMENT ON TRIGGER {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(o_data.nspname, o_data.relname) }}
+    IS {{data.description|qtLiteral}};
+{% endif %}
\ No newline at end of file
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
new file mode 100644
index 0000000..634483a
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/__init__.py
@@ -0,0 +1,944 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+""" Implements Trigger Node """
+
+from flask import render_template, make_response, request, jsonify
+from flask.ext.babel import gettext
+from pgadmin.utils.ajax import make_json_response, \
+    make_response as ajax_response, internal_server_error
+from pgadmin.browser.utils import PGChildNodeView
+from pgadmin.browser.collection import CollectionNodeModule
+import pgadmin.browser.server_groups.servers.databases as database
+from pgadmin.browser.server_groups.servers.databases.schemas.utils import \
+    trigger_definition as _trigger_definition
+from pgadmin.utils.ajax import precondition_required
+from pgadmin.utils.driver import get_driver
+from config import PG_DEFAULT_DRIVER
+from functools import wraps
+import json
+
+
+class TriggerModule(CollectionNodeModule):
+    """
+     class TriggerModule(CollectionNodeModule)
+
+        A module class for Trigger node derived from CollectionNodeModule.
+
+    Methods:
+    -------
+    * __init__(*args, **kwargs)
+      - Method is used to initialize the Trigger and it's base module.
+
+    * get_nodes(gid, sid, did, scid, tid)
+      - Method is used to generate the browser collection node.
+
+    * node_inode()
+      - Method is overridden from its base class to make the node as leaf node.
+
+    * script_load()
+      - Load the module script for trigger, when any of the server node is
+        initialized.
+    """
+
+    NODE_TYPE = 'trigger'
+    COLLECTION_LABEL = gettext("Triggers")
+
+    def __init__(self, *args, **kwargs):
+        """
+        Method is used to initialize the TriggerModule and it's base module.
+
+        Args:
+            *args:
+            **kwargs:
+        """
+        self.min_ver = None
+        self.max_ver = None
+        super(TriggerModule, self).__init__(*args, **kwargs)
+
+    def BackendSupported(self, manager, **kwargs):
+        """
+        Load this module if vid is view, we will not load it under
+        material view
+        """
+        if super(TriggerModule, self).BackendSupported(manager, **kwargs):
+            conn = manager.connection(did=kwargs['did'])
+            # If DB is not connected then return error to browser
+            if not conn.connected():
+                return precondition_required(
+                    gettext(
+                            "Connection to the server has been lost!"
+                    )
+                )
+
+            if 'vid' not in kwargs:
+                return True
+
+            template_path = 'trigger/sql/9.1_plus'
+            SQL = render_template("/".join(
+                  [template_path, 'backend_support.sql']), vid=kwargs['vid'])
+            status, res = conn.execute_scalar(SQL)
+            # check if any errors
+            if not status:
+                return internal_server_error(errormsg=res)
+            # Check vid is view not material view
+            # then true, othewise false
+            return res
+
+    def get_nodes(self, gid, sid, did, scid, **kwargs):
+        """
+        Generate the collection node
+        """
+        assert('tid' in kwargs or 'vid' in kwargs)
+        yield self.generate_browser_collection_node(
+            kwargs['tid'] if 'tid' in kwargs else kwargs['vid']
+        )
+
+    @property
+    def script_load(self):
+        """
+        Load the module script for server, when any of the server-group node is
+        initialized.
+        """
+        return database.DatabaseModule.NODE_TYPE
+
+    @property
+    def node_inode(self):
+        """
+        Load the module node as a leaf node
+        """
+        return True
+
+    @property
+    def csssnippets(self):
+        """
+        Returns a snippet of css to include in the page
+        """
+        snippets = [
+                render_template(
+                    "trigger/css/trigger.css",
+                    node_type=self.node_type
+                    )
+                ]
+
+        for submodule in self.submodules:
+            snippets.extend(submodule.csssnippets)
+
+        return snippets
+
+blueprint = TriggerModule(__name__)
+
+
+class TriggerView(PGChildNodeView):
+    """
+    This class is responsible for generating routes for Trigger node
+
+    Methods:
+    -------
+    * __init__(**kwargs)
+      - Method is used to initialize the TriggerView and it's base view.
+
+    * module_js()
+      - This property defines (if javascript) exists for this node.
+        Override this property for your own logic
+
+    * check_precondition()
+      - This function will behave as a decorator which will checks
+        database connection before running view, it will also attaches
+        manager,conn & template_path properties to self
+
+    * list()
+      - This function is used to list all the Trigger nodes within that
+      collection.
+
+    * nodes()
+      - This function will used to create all the child node within that
+        collection, Here it will create all the Trigger node.
+
+    * properties(gid, sid, did, scid, tid, trid)
+      - This function will show the properties of the selected Trigger node
+
+    * create(gid, sid, did, scid, tid)
+      - This function will create the new Trigger object
+
+    * update(gid, sid, did, scid, tid, trid)
+      - This function will update the data for the selected Trigger node
+
+    * delete(self, gid, sid, scid, tid, trid):
+      - This function will drop the Trigger object
+
+    * enable(self, gid, sid, scid, tid, trid):
+      - This function will enable/disable Trigger object
+
+    * msql(gid, sid, did, scid, tid, trid)
+      - This function is used to return modified SQL for the selected
+        Trigger node
+
+    * get_sql(data, scid, tid, trid)
+      - This function will generate sql from model data
+
+    * sql(gid, sid, did, scid, tid, trid):
+      - This function will generate sql to show it in sql pane for the
+        selected Trigger node.
+
+    * dependency(gid, sid, did, scid, tid, trid):
+      - This function will generate dependency list show it in dependency
+        pane for the selected Trigger node.
+
+    * dependent(gid, sid, did, scid, tid, trid):
+      - This function will generate dependent list to show it in dependent
+        pane for the selected Trigger node.
+
+    * get_trigger_functions(gid, sid, did, scid, tid, trid):
+      - This function will return list of trigger functions available
+        via AJAX response
+
+    * _column_details(tid, clist)::
+      - This function will fetch the columns for trigger
+
+    * _trigger_definition(data):
+      - This function will set additional trigger definitions in
+        AJAX response
+    """
+
+    node_type = blueprint.node_type
+
+    parent_ids = [
+            {'type': 'int', 'id': 'gid'},
+            {'type': 'int', 'id': 'sid'},
+            {'type': 'int', 'id': 'did'},
+            {'type': 'int', 'id': 'scid'},
+            {'type': 'int', 'id': 'tid'}
+            ]
+    ids = [
+            {'type': 'int', 'id': 'trid'}
+            ]
+
+    operations = dict({
+        'obj': [
+            {'get': 'properties', 'delete': 'delete', 'put': 'update'},
+            {'get': 'list', 'post': 'create'}
+        ],
+        'delete': [{'delete': 'delete'}],
+        'children': [{'get': 'children'}],
+        'nodes': [{'get': 'node'}, {'get': 'nodes'}],
+        'sql': [{'get': 'sql'}],
+        'msql': [{'get': 'msql'}, {'get': 'msql'}],
+        'stats': [{'get': 'statistics'}],
+        'dependency': [{'get': 'dependencies'}],
+        'dependent': [{'get': 'dependents'}],
+        'module.js': [{}, {}, {'get': 'module_js'}],
+        'get_triggerfunctions': [{'get': 'get_trigger_functions'},
+                               {'get': 'get_trigger_functions'}],
+        'enable': [{'put': 'enable_disable_trigger'}]
+    })
+
+    def check_precondition(f):
+        """
+        This function will behave as a decorator which will checks
+        database connection before running view, it will also attaches
+        manager,conn & template_path properties to self
+        """
+        @wraps(f)
+        def wrap(*args, **kwargs):
+            # Here args[0] will hold self & kwargs will hold gid,sid,did
+            self = args[0]
+            self.manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(
+                kwargs['sid']
+            )
+            self.conn = self.manager.connection(did=kwargs['did'])
+            # If DB not connected then return error to browser
+            if not self.conn.connected():
+                return precondition_required(
+                    gettext(
+                            "Connection to the server has been lost!"
+                    )
+                )
+
+            # We need datlastsysoid to check if current trigger is system trigger
+            self.datlastsysoid = self.manager.db_info[kwargs['did']]['datlastsysoid']
+
+            # we will set template path for sql scripts
+            self.template_path = 'trigger/sql/9.1_plus'
+            # Store server type
+            self.server_type = self.manager.server_type
+            # We need parent's name eg table name and schema name
+            # when we create new trigger in update we can fetch it using
+            # property sql
+            SQL = render_template("/".join([self.template_path,
+                                            'get_parent.sql']),
+                                  tid=kwargs['tid'])
+            status, rset = self.conn.execute_2darray(SQL)
+            if not status:
+                return internal_server_error(errormsg=rset)
+
+            for row in rset['rows']:
+                self.schema = row['schema']
+                self.table = row['table']
+
+            # Here we are storing trigger definition
+            # We will use it to check trigger type definition
+            self.trigger_definition = {
+                'TRIGGER_TYPE_ROW':         (1 << 0),
+                'TRIGGER_TYPE_BEFORE':      (1 << 1),
+                'TRIGGER_TYPE_INSERT':      (1 << 2),
+                'TRIGGER_TYPE_DELETE':      (1 << 3),
+                'TRIGGER_TYPE_UPDATE':      (1 << 4),
+                'TRIGGER_TYPE_TRUNCATE':    (1 << 5),
+                'TRIGGER_TYPE_INSTEAD':     (1 << 6)
+            }
+
+            return f(*args, **kwargs)
+
+        return wrap
+
+    @check_precondition
+    def get_trigger_functions(self, gid, sid, did, scid, tid, trid=None):
+        """
+        This function will return list of trigger functions available
+        via AJAX response
+        """
+        res = [{'label': '', 'value': ''}]
+
+        # TODO: REMOVE True Condition , it's just for testing
+        # If server type is EDB-PPAS then we also need to add
+        # inline edb-spl along with options fetched by below sql
+
+        if self.server_type == 'ppas':
+            res.append({
+                'label': 'Inline EDB-SPL',
+                'value': 'Inline EDB-SPL'
+                })
+        try:
+            SQL = render_template("/".join([self.template_path,
+                                            'get_triggerfunctions.sql']),
+                                  show_system_objects=self.blueprint.show_system_objects
+                                  )
+            status, rset = self.conn.execute_2darray(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            for row in rset['rows']:
+                res.append(
+                            {'label': row['tfunctions'],
+                             'value': row['tfunctions']}
+                        )
+            return make_json_response(
+                    data=res,
+                    status=200
+                    )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def list(self, gid, sid, did, scid, tid):
+        """
+        This function is used to list all the trigger nodes within that collection.
+
+        Args:
+            gid: Server group ID
+            sid: Server ID
+            did: Database ID
+            scid: Schema ID
+            tid: Table ID
+
+        Returns:
+            JSON of available trigger nodes
+        """
+
+        SQL = render_template("/".join([self.template_path,
+                                        'properties.sql']), tid=tid)
+        status, res = self.conn.execute_dict(SQL)
+
+        if not status:
+            return internal_server_error(errormsg=res)
+        return ajax_response(
+                response=res['rows'],
+                status=200
+                )
+
+    @check_precondition
+    def nodes(self, gid, sid, did, scid, tid):
+        """
+        This function will used to create all the child node within that collection.
+        Here it will create all the trigger node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            scid: Schema ID
+            tid: Table ID
+
+        Returns:
+            JSON of available trigger child nodes
+        """
+        res = []
+        SQL = render_template("/".join([self.template_path,
+                                        'nodes.sql']), tid=tid)
+        status, rset = self.conn.execute_2darray(SQL)
+        if not status:
+            return internal_server_error(errormsg=rset)
+
+        for row in rset['rows']:
+            res.append(
+                    self.blueprint.generate_browser_node(
+                        row['oid'],
+                        tid,
+                        row['name'],
+                        icon="icon-trigger" if row['is_enable_trigger']
+                        else "icon-trigger-bad"
+                    ))
+
+        return make_json_response(
+                data=res,
+                status=200
+                )
+
+    def _column_details(self, tid, clist):
+        """
+        This functional will fetch list of column for trigger
+
+        Args:
+            tid: Table OID
+            clist: List of columns
+
+        Returns:
+            Updated properties data with column
+        """
+
+        SQL = render_template("/".join([self.template_path,
+                                        'get_columns.sql']),
+                              tid=tid, clist=clist)
+        status, rset = self.conn.execute_2darray(SQL)
+        if not status:
+            return internal_server_error(errormsg=rset)
+        # 'tgattr' contains list of columns from table used in trigger
+        columns = []
+
+        for row in rset['rows']:
+            columns.append({'column': row['name']})
+
+        return columns
+
+    def _trigger_definition(self, data):
+        """
+        This functional will set the trigger definition
+
+        Args:
+            data: Properties data
+
+        Returns:
+            Updated properties data with trigger definition
+        """
+
+        # Fires event definition
+        if data['tgtype'] & self.trigger_definition['TRIGGER_TYPE_BEFORE']:
+             data['fires'] = 'BEFORE'
+        elif data['tgtype'] & self.trigger_definition['TRIGGER_TYPE_INSTEAD']:
+            data['fires'] = 'INSTEAD OF'
+        else:
+            data['fires'] = 'AFTER'
+
+        # Trigger of type definition
+        if data['tgtype'] & self.trigger_definition['TRIGGER_TYPE_ROW']:
+            data['is_row_trigger'] = True
+        else:
+            data['is_row_trigger'] = False
+
+        # Event definition
+        if data['tgtype'] & self.trigger_definition['TRIGGER_TYPE_INSERT']:
+            data['evnt_insert'] = True
+        else:
+            data['evnt_insert'] = False
+
+        if data['tgtype'] & self.trigger_definition['TRIGGER_TYPE_DELETE']:
+            data['evnt_delete'] = True
+        else:
+            data['evnt_delete'] = False
+
+        if data['tgtype'] & self.trigger_definition['TRIGGER_TYPE_UPDATE']:
+            data['evnt_update'] = True
+        else:
+            data['evnt_update'] = False
+
+        if data['tgtype'] & self.trigger_definition['TRIGGER_TYPE_TRUNCATE']:
+            data['evnt_turncate'] = True
+        else:
+            data['evnt_turncate'] = False
+
+        return data
+
+    @check_precondition
+    def properties(self, gid, sid, did, scid, tid, trid):
+        """
+        This function will show the properties of the selected trigger node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did:  Database ID
+            scid: Schema ID
+            scid: Schema ID
+            tid: Table ID
+            trid: Trigger ID
+
+        Returns:
+            JSON of selected trigger node
+        """
+
+        SQL = render_template("/".join([self.template_path,
+                                        'properties.sql']),
+                              tid=tid, trid=trid,
+                              datlastsysoid=self.datlastsysoid)
+
+        status, res = self.conn.execute_dict(SQL)
+
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        # Making copy of output for future use
+        data = dict(res['rows'][0])
+        if data['tgnargs'] > 1:
+            # We know that trigger has more than 1 arguments, let's join them
+            # and convert it as string
+            data['tgargs'] = ', '.join(data['tgargs'])
+
+        if len(data['tgattr']) > 1:
+            columns = ', '.join(data['tgattr'].split(' '))
+            data['columns'] = self._column_details(tid, columns)
+
+        data = self._trigger_definition(data)
+
+        return ajax_response(
+                response=data,
+                status=200
+                )
+
+    @check_precondition
+    def create(self, gid, sid, did, scid, tid):
+        """
+        This function will creates new the trigger object
+
+         Args:
+           gid: Server Group ID
+           sid: Server ID
+           did: Database ID
+           scid: Schema ID
+           tid: Table ID
+        """
+        data = request.form if request.form else json.loads(
+            request.data.decode()
+        )
+
+        for k, v in data.items():
+            try:
+                data[k] = json.loads(v)
+            except (ValueError, TypeError):
+                data[k] = v
+
+        required_args = {
+            'name': 'Name',
+            'tfunction': 'Trigger function'
+        }
+
+        for arg in required_args:
+            if arg not in data:
+                return make_json_response(
+                        status=410,
+                        success=0,
+                        errormsg=gettext("Couldn't find the required parameter (%s)." % \
+                                required_args[arg])
+                        )
+
+        # Adding parent into data dict, will be using it while creating sql
+        data['schema'] = self.schema
+        data['table'] = self.table
+
+        try:
+            SQL = render_template("/".join([self.template_path,
+                                            'create.sql']),
+                                  data=data, conn=self.conn)
+            status, res = self.conn.execute_scalar(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            # we need oid to to add object in tree at browser
+            SQL = render_template("/".join([self.template_path,
+                                            'get_oid.sql']),
+                                  tid=tid, data=data)
+            status, trid = self.conn.execute_scalar(SQL)
+            if not status:
+                return internal_server_error(errormsg=tid)
+
+            return jsonify(
+                node=self.blueprint.generate_browser_node(
+                    trid,
+                    scid,
+                    data['name'],
+                    icon="icon-trigger"
+                )
+            )
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def delete(self, gid, sid, did, scid, tid, trid):
+        """
+        This function will updates existing the trigger object
+
+         Args:
+           gid: Server Group ID
+           sid: Server ID
+           did: Database ID
+           scid: Schema ID
+           tid: Table ID
+           trid: Trigger ID
+        """
+        # Below will decide if it's simple drop or drop with cascade call
+        if self.cmd == 'delete':
+            # This is a cascade operation
+            cascade = True
+        else:
+            cascade = False
+
+        try:
+            # We will first fetch the trigger name for current request
+            # so that we create template for dropping trigger
+            SQL = render_template("/".join([self.template_path,
+                                            'properties.sql']),
+                                  tid=tid, trid=trid,
+                                  datlastsysoid=self.datlastsysoid)
+
+            status, res = self.conn.execute_dict(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            data = dict(res['rows'][0])
+
+            SQL = render_template("/".join([self.template_path,
+                                            'delete.sql']),
+                                  data=data, conn=self.conn, cascade=cascade)
+            status, res = self.conn.execute_scalar(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            return make_json_response(
+                success=1,
+                info=gettext("Trigger is dropped"),
+                data={
+                    'id': trid,
+                    'tid': tid
+                }
+            )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def update(self, gid, sid, did, scid, tid, trid):
+        """
+        This function will updates existing the trigger object
+
+         Args:
+           gid: Server Group ID
+           sid: Server ID
+           did: Database ID
+           scid: Schema ID
+           tid: Table ID
+           trid: Trigger ID
+        """
+        data = request.form if request.form else json.loads(request.data.decode())
+
+        try:
+            SQL = self.get_sql(scid, tid, trid, data)
+            if SQL and SQL.strip('\n') and SQL.strip(' '):
+                status, res = self.conn.execute_scalar(SQL)
+                if not status:
+                    return internal_server_error(errormsg=res)
+
+                return make_json_response(
+                    success=1,
+                    info="Trigger updated",
+                    data={
+                        'id': trid,
+                        'tid': tid,
+                        'scid': scid
+                    }
+                )
+            else:
+                return make_json_response(
+                    success=1,
+                    info="Nothing to update",
+                    data={
+                        'id': trid,
+                        'tid': tid,
+                        'scid': scid
+                    }
+                )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def msql(self, gid, sid, did, scid, tid, trid=None):
+        """
+        This function will generates modified sql for trigger object
+
+         Args:
+           gid: Server Group ID
+           sid: Server ID
+           did: Database ID
+           scid: Schema ID
+           tid: Table ID
+           trid: Trigger ID (When working with existing trigger)
+        """
+        data = dict()
+        for k, v in request.args.items():
+            try:
+                data[k] = json.loads(v)
+            except ValueError:
+                data[k] = v
+
+        # Adding parent into data dict, will be using it while creating sql
+        data['schema'] = self.schema
+        data['table'] = self.table
+
+        try:
+            SQL = self.get_sql(scid, tid, trid, data)
+
+            if SQL and SQL.strip('\n') and SQL.strip(' '):
+                return make_json_response(
+                        data=SQL,
+                        status=200
+                        )
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    def get_sql(self, scid, tid, trid, data):
+        """
+        This function will genrate sql from model data
+        """
+        if trid is not None:
+            SQL = render_template("/".join([self.template_path,
+                                            'properties.sql']),
+                                  tid=tid, trid=trid,
+                                  datlastsysoid=self.datlastsysoid)
+
+            status, res = self.conn.execute_dict(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            old_data = dict(res['rows'][0])
+
+            # If name is not present in data then
+            # we will fetch it from old data, we also need schema & table name
+            if 'name' not in data:
+                data['name'] = old_data['name']
+
+            if old_data['tgnargs'] > 1:
+                # We know that trigger has more than 1 arguments, let's join them
+                old_data['tgargs'] = ', '.join(old_data['tgargs'])
+
+            if len(old_data['tgattr']) > 1:
+                columns = ', '.join(old_data['tgattr'].split(' '))
+                old_data['columns'] = self._column_details(tid, columns)
+
+            old_data = self._trigger_definition(old_data)
+
+            SQL = render_template(
+                "/".join([self.template_path, 'update.sql']),
+                data=data, o_data=old_data, conn=self.conn
+                )
+        else:
+            required_args = {
+                'name': 'Name',
+                'tfunction': 'Trigger function'
+            }
+
+            for arg in required_args:
+                if arg not in data:
+                    return gettext('-- incomplete definition')
+
+            # If the request for new object which do not have did
+            SQL = render_template("/".join([self.template_path, 'create.sql']),
+                                  data=data, conn=self.conn)
+        return SQL
+
+    @check_precondition
+    def sql(self, gid, sid, did, scid, tid, trid):
+        """
+        This function will generates reverse engineered sql for trigger object
+
+         Args:
+           gid: Server Group ID
+           sid: Server ID
+           did: Database ID
+           scid: Schema ID
+           tid: Table ID
+           trid: Trigger ID
+        """
+        try:
+            SQL = render_template("/".join([self.template_path,
+                                            'properties.sql']),
+                                  tid=tid, trid=trid,
+                                  datlastsysoid=self.datlastsysoid)
+
+            status, res = self.conn.execute_dict(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            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 data['tgnargs'] > 1:
+                # We know that trigger has more than 1 arguments, let's join them
+                data['tgargs'] = ', '.join(data['tgargs'])
+
+            if len(data['tgattr']) > 1:
+                columns = ', '.join(data['tgattr'].split(' '))
+                data['columns'] = self._column_details(tid, columns)
+
+            data = self._trigger_definition(data)
+
+            SQL = self.get_sql(scid, tid, None, data)
+
+            sql_header = "-- 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 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 ajax_response(response=SQL)
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def enable_disable_trigger(self, gid, sid, did, scid, tid, trid):
+        """
+        This function will enable OR disable the current trigger object
+
+         Args:
+           gid: Server Group ID
+           sid: Server ID
+           did: Database ID
+           scid: Schema ID
+           tid: Table ID
+           trid: Trigger ID
+        """
+
+        data = request.form if request.form else json.loads(request.data.decode())
+
+        # Convert str 'true' to boolean type
+        is_enable_flag = json.loads(data['enable'])
+
+        try:
+
+            SQL = render_template("/".join([self.template_path,
+                                            'properties.sql']),
+                                  tid=tid, trid=trid,
+                                  datlastsysoid=self.datlastsysoid)
+
+            status, res = self.conn.execute_dict(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            o_data = dict(res['rows'][0])
+
+            # If enable is set to true means we need SQL to enable
+            # current trigger which is disabled already so we need to
+            # alter the 'is_enable_trigger' flag so that we can render
+            # correct SQL for operation
+            o_data['is_enable_trigger'] = is_enable_flag
+
+            # Adding parent into data dict, will be using it while creating sql
+            o_data['schema'] = self.schema
+            o_data['table'] = self.table
+
+            SQL = render_template("/".join([self.template_path,
+                                            'enable_disable_trigger.sql']),
+                                  data=o_data, conn=self.conn)
+            status, res = self.conn.execute_scalar(SQL)
+
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            return make_json_response(
+                success=1,
+                info="Trigger updated",
+                data={
+                    'id': trid,
+                    'tid': tid,
+                    'scid': scid
+                }
+            )
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+
+    @check_precondition
+    def dependents(self, gid, sid, did, scid, tid, trid):
+        """
+        This function get the dependents and return ajax response
+        for the trigger node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            scid: Schema ID
+            tid: Table ID
+            trid: Trigger ID
+        """
+        dependents_result = self.get_dependents(
+            self.conn, trid
+        )
+
+        return ajax_response(
+                response=dependents_result,
+                status=200
+                )
+
+    @check_precondition
+    def dependencies(self, gid, sid, did, scid, tid, trid):
+        """
+        This function get the dependencies and return ajax response
+        for the trigger node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            scid: Schema ID
+            tid: Table ID
+            trid: Trigger ID
+
+        """
+        dependencies_result = self.get_dependencies(
+            self.conn, trid
+        )
+
+        return ajax_response(
+                response=dependencies_result,
+                status=200
+                )
+
+TriggerView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/static/img/coll-trigger.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/static/img/coll-trigger.png
new file mode 100644
index 0000000000000000000000000000000000000000..3c339406fa325dad67f59141a6a08a5334debcda
GIT binary patch
literal 350
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFv5AX?b1=6kiPU=rwT=MDBga5xP
z_8ouw|L>&#A2Xj{cR#w-VBI{+?aRZi97(#*xCE$_u_VYZn8D%MjWi&Kv%n*=7)X17
zvD?XPJ0K&^)5S4_<9f0{kWc~xb80dxhx5@;Pr)+*-bQ9j-mAoSvNTT3G+F96CDTtU
zys(goD^vGXfVVgEs_XYmg7@y()6wYo{DM|*UmqVUo8r>Dvy9XIn6#3t7H`cGJ>lb~
z`u6T@g>5h9G)5dcu;fSs3qw<vM2e~mdkWBI)e_f;l9a@fRIB8oR3OD*WMF8ZYiOiv
zU>IU#U}a)#Wn!vrU}|MxFz=n-DijU5`6-!cl@JXEmS7D))h1R3W)KahriZQpYGCkm
L^>bP0l+XkKAR%?3

literal 0
HcmV?d00001

diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/static/img/trigger-bad.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/static/img/trigger-bad.png
new file mode 100644
index 0000000000000000000000000000000000000000..6cc2fe96c8f234a73672cc73fd272a15fc7de4f9
GIT binary patch
literal 610
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbMf&j6ngS0LTG@1*|3#U-B}o%;Xd
z@BjbbfBg9M>-UfEKmPptck0#i>q$vR85k~vM;<wH;@IDBlcy{^>h66vGt;?!=F#Zb
zZ{_7j+`X5s+_2Bq>0@|!L|y;4va)YQMPKvs_E<Z73=4bj@BhxjGp@SlRA9*0+}tl2
z8K0AqK7@w8_XCQ1SoF-Bv2V}k#Ke!$(H}xW-uwE!b9XmezhLo!y|+?RKLi6seBZgb
zt<o{>KeX=}P-AfLdmo>7uC8zF>|a}0_%=`3<>K}sDCoVn_gfd&*XHK03=LmuYd7cA
zd<YDD=jHX**=44)*Gnz!7pkhy6%^h&IUjNJn(5;GTwY=QPpA1n&oh<;`2{mLJiCzw
z<Zu>vL>2>S4={E+nQaGTEbw%343W5;d-f{dp#&b*2lcZ1ns=Wr`2LXZ@Y}!gZH&=I
zLRA-+#NU!T_D{s!WsY3O^U7b0%|TU)i%;fkeASY}^oDQwY2NeVd+dG)a<mDAsWxTk
z^s!7@X<|1)aN^mgfg01U^cJ}~Yz@md*(!e}tNg;-uZo$P&5CZ1PnImpJtH2m?%Iu<
z@>M5p$oE-1tl3!?oFZs`=O(lN+cwV$Ps+oeiATx_obU^~(ExO-YKdz^NlIc#s#S7P
zDv)9@GB7mMH89pSum~|UvNANcGO*M(Ftai+xcqEI5{ic0{FKbJO57S2?H0HP)WG2B
L>gTe~DWM4fI7SDA

literal 0
HcmV?d00001

diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/static/img/trigger.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/static/img/trigger.png
new file mode 100644
index 0000000000000000000000000000000000000000..3b413e4a648c999c0dcc005aaaf02a710be4414b
GIT binary patch
literal 324
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPHF3h)VW1=6kiPU=rwT=MDBssBIz
z{{Mgc|Bu?=uTvji_Bye{WYZ$U_4Az$Y>2*ja-Gx8WkA)8B|(0{3=Yq3qyagc1s;*b
zK-vS0-A-oP0U3dwE{-7_*OL<(nB7!eIhs%2;5b!K7}#Lo<lL;#vt^6P2CZeEK7CSR
z6j;p6;jn5(+POKFoI0Dbu4-*CTXuK1IcI}p`Z<TQJF7XfW=>*a4r5?=RWIaqXXEsv
zK*Lo_Tq8<S5=&C8l8aJ-6oZk0p`osUp{|i}h=H*c5E&Y48<<%c7@VBUTY#b=H$Npa
rtrDccK-a($s3*k8*viDj%D_z9z!a$A)b!9bKn)C@u6{1-oD!M<5hib6

literal 0
HcmV?d00001

diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/templates/trigger/css/trigger.css b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/templates/trigger/css/trigger.css
new file mode 100644
index 0000000..811c838
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/templates/trigger/css/trigger.css
@@ -0,0 +1,20 @@
+.icon-coll-trigger {
+  background-image: url('{{ url_for('NODE-trigger.static', filename='img/coll-trigger.png' )}}') !important;
+  background-repeat: no-repeat;
+  align-content: center;
+  vertical-align: middle;
+  height: 1.3em;
+}
+
+.icon-trigger {
+  background-image: url('{{ url_for('NODE-trigger.static', filename='img/trigger.png') }}') !important;
+  background-repeat: no-repeat;
+  align-content: center;
+  vertical-align: middle;
+  height: 1.3em;
+}
+
+.icon-trigger-bad {
+  background-image: url('{{ url_for('NODE-trigger.static', filename='img/trigger-bad.png') }}') !important;
+  border-radius: 10px
+}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/templates/trigger/js/trigger.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/templates/trigger/js/trigger.js
new file mode 100644
index 0000000..bd22795
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/templates/trigger/js/trigger.js
@@ -0,0 +1,547 @@
+define(
+        ['jquery', 'underscore', 'underscore.string', 'pgadmin', 'pgadmin.browser',
+        'backform', 'alertify', 'pgadmin.browser.collection'],
+function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
+
+  if (!pgBrowser.Nodes['coll-trigger']) {
+    var triggers = pgAdmin.Browser.Nodes['coll-trigger'] =
+      pgAdmin.Browser.Collection.extend({
+        node: 'trigger',
+        label: '{{ _('Triggers') }}',
+        type: 'coll-trigger',
+        columns: ['name', 'description']
+      });
+  };
+
+  if (!pgBrowser.Nodes['trigger']) {
+    pgAdmin.Browser.Nodes['trigger'] = pgAdmin.Browser.Node.extend({
+      parent_type: ['table', 'view'],
+      collection_type: ['coll-table', 'coll-view'],
+      type: 'trigger',
+      label: '{{ _('Trigger') }}',
+      hasSQL:  true,
+      hasDepends: true,
+      sqlAlterHelp: 'sql-altertrigger.html',
+      sqlCreateHelp: 'sql-createtrigger.html',
+      Init: function() {
+        /* Avoid mulitple registration of menus */
+        if (this.initialized)
+            return;
+
+        this.initialized = true;
+
+        pgBrowser.add_menus([{
+          name: 'create_trigger_on_coll', node: 'coll-trigger', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('Trigger...') }}',
+          icon: 'wcTabIcon icon-trigger', data: {action: 'create', check: true},
+          enable: 'canCreate'
+        },{
+          name: 'create_trigger', node: 'trigger', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('Trigger...') }}',
+          icon: 'wcTabIcon icon-trigger', data: {action: 'create', check: true},
+          enable: 'canCreate'
+        },{
+          name: 'create_trigger_onTable', node: 'table', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('Trigger...') }}',
+          icon: 'wcTabIcon icon-trigger', data: {action: 'create', check: true},
+          enable: 'canCreate'
+        },{
+          name: 'enable_trigger', node: 'trigger', module: this,
+          applies: ['object', 'context'], callback: 'enable_trigger',
+          category: 'connect', priority: 3, label: '{{ _('Enable trigger') }}',
+          icon: 'fa fa-check', enable : 'canCreate_with_trigger_enable'
+        },{
+          name: 'disable_trigger', node: 'trigger', module: this,
+          applies: ['object', 'context'], callback: 'disable_trigger',
+          category: 'drop', priority: 3, label: '{{ _('Disable trigger') }}',
+          icon: 'fa fa-times', enable : 'canCreate_with_trigger_disable'
+        },{
+          name: 'create_trigger_onView', node: 'view', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('Trigger...') }}',
+          icon: 'wcTabIcon icon-trigger', data: {action: 'create', check: true},
+          enable: 'canCreate'
+        }
+        ]);
+      },
+      callbacks: {
+        /* Enable trigger */
+        enable_trigger: function(args) {
+          var input = args || {};
+          obj = this,
+          t = pgBrowser.tree,
+          i = input.item || t.selected(),
+          d = i && i.length == 1 ? t.itemData(i) : undefined;
+
+          if (!d)
+            return false;
+
+          var data = d;
+          $.ajax({
+            url: obj.generate_url(i, 'enable' , d, true),
+            type:'PUT',
+            data: {'enable' : true},
+            dataType: "json",
+            success: function(res) {
+              if (res.success == 1) {
+                alertify.success("{{ _('" + res.info + "') }}");
+                t.removeIcon(i);
+                data.icon = 'icon-trigger';
+                t.addIcon(i, {icon: data.icon});
+                t.unload(i);
+                t.setInode(i);
+                t.deselect(i);
+                // Fetch updated data from server
+                setTimeout(function() {
+                  t.select(i);
+                }, 10);
+              }
+            },
+            error: function(xhr, status, error) {
+              try {
+                var err = $.parseJSON(xhr.responseText);
+                if (err.success == 0) {
+                  msg = S('{{ _(' + err.errormsg + ')}}').value();
+                  alertify.error("{{ _('" + err.errormsg + "') }}");
+                }
+              } catch (e) {}
+              t.unload(i);
+            }
+          })
+        },
+        /* Disable trigger */
+        disable_trigger: function(args) {
+          var input = args || {};
+          obj = this,
+          t = pgBrowser.tree,
+          i = input.item || t.selected(),
+          d = i && i.length == 1 ? t.itemData(i) : undefined;
+
+          if (!d)
+            return false;
+
+          var data = d;
+          $.ajax({
+            url: obj.generate_url(i, 'enable' , d, true),
+            type:'PUT',
+            data: {'enable' : false},
+            dataType: "json",
+            success: function(res) {
+              if (res.success == 1) {
+                alertify.success("{{ _('" + res.info + "') }}");
+                t.removeIcon(i);
+                data.icon = 'icon-trigger-bad';
+                t.addIcon(i, {icon: data.icon});
+                t.unload(i);
+                t.setInode(i);
+                t.deselect(i);
+                // Fetch updated data from server
+                setTimeout(function() {
+                  t.select(i);
+                }, 10);
+              }
+            },
+            error: function(xhr, status, error) {
+              try {
+                var err = $.parseJSON(xhr.responseText);
+                if (err.success == 0) {
+                  msg = S('{{ _(' + err.errormsg + ')}}').value();
+                  alertify.error("{{ _('" + err.errormsg + "') }}");
+                }
+              } catch (e) {}
+              t.unload(i);
+            }
+          })
+        }
+      },
+      canDrop: pgBrowser.Nodes['schema'].canChildDrop,
+      canDropCascade: pgBrowser.Nodes['schema'].canChildDrop,
+      model: pgAdmin.Browser.Node.Model.extend({
+        defaults: {
+          name: undefined,
+					is_row_trigger: true
+        },
+        schema: [{
+          id: 'name', label: '{{ _('Name') }}', cell: 'string',
+          type: 'text', disabled: 'inSchema'
+        },{
+          id: 'oid', label:'{{ _('OID') }}', cell: 'string',
+          type: 'int', disabled: true, mode: ['properties']
+        },{
+          id: 'is_enable_trigger', label:'{{ _('Enable trigger?') }}',
+          type: 'switch', disabled: 'inSchema', mode: ['properties']
+        },{
+          id: 'is_row_trigger', label:'{{ _('Row trigger') }}',
+          type: 'switch', group: '{{ _('Definition') }}',
+          mode: ['create','edit', 'properties'],
+          deps: ['is_constraint_trigger'],
+          disabled: function(m) {
+            // If contraint trigger is set to True then row trigger will
+            // automatically set to True and becomes disable
+            var is_constraint_trigger = m.get('is_constraint_trigger');
+            if(!m.inSchemaWithModelCheck.apply(this, [m])) {
+                if(!_.isUndefined(is_constraint_trigger) &&
+                is_constraint_trigger === true) {
+                // change it's model value
+                    setTimeout(function() { m.set('is_row_trigger', true) }, 10);
+                    return true;
+                } else {
+                    return false;
+                }
+            } else {
+                // Disbale it
+                return true;
+            }
+          }
+        },{
+          id: 'is_constraint_trigger', label:'{{ _('Constraint trigger') }}',
+          type: 'switch', disabled: 'inSchemaWithModelCheck',
+          mode: ['create','edit', 'properties'],
+          group: '{{ _('Definition') }}'
+        },{
+          id: 'tgdeferrable', label:'{{ _('Deferrable') }}',
+          type: 'switch', group: '{{ _('Definition') }}',
+          mode: ['create','edit', 'properties'],
+          deps: ['is_constraint_trigger'],
+          disabled: function(m) {
+            // If contraint trigger is set to True then only enable it
+            var is_constraint_trigger = m.get('is_constraint_trigger');
+            if(!m.inSchemaWithModelCheck.apply(this, [m])) {
+                if(!_.isUndefined(is_constraint_trigger) &&
+                is_constraint_trigger === true) {
+                    return false;
+                } else {
+                    setTimeout(function() { m.set('tgdeferrable', false) }, 10);
+                    return true;
+                }
+            } else {
+                // Disbale it
+                return true;
+            }
+          }
+        },{
+          id: 'tginitdeferred', label:'{{ _('Deferred') }}',
+          type: 'switch', group: '{{ _('Definition') }}',
+          mode: ['create','edit', 'properties'],
+          deps: ['tgdeferrable'],
+          disabled: function(m) {
+            // If contraint trigger is set to True then only enable it
+            var is_constraint_trigger = m.get('tgdeferrable');
+            if(!m.inSchemaWithModelCheck.apply(this, [m])) {
+                if(!_.isUndefined(is_constraint_trigger) &&
+                is_constraint_trigger === true) {
+                    return false;
+                } else {
+                    setTimeout(function() { m.set('tginitdeferred', false) }, 10);
+                    return true;
+                }
+            } else {
+                // Disbale it
+                return true;
+            }
+          }
+        },{
+          id: 'tfunction', label:'{{ _('Trigger Function') }}',
+          type: 'text', disabled: 'inSchemaWithModelCheck',
+          mode: ['create','edit', 'properties'], group: '{{ _('Definition') }}',
+          control: 'node-ajax-options', url: 'get_triggerfunctions'
+        },{
+          id: 'tgargs', label:'{{ _('Arguments') }}', cell: 'string',
+          group: '{{ _('Definition') }}',
+          type: 'text',mode: ['create','edit', 'properties'], deps: ['tfunction'],
+          disabled: function(m) {
+            // We will disable it when EDB PPAS and trigger function is
+            // set to Inline EDB-SPL
+            var tfunction = m.get('tfunction'),
+                server_type = m.node_info['server']['server_type'];
+            if(!m.inSchemaWithModelCheck.apply(this, [m])) {
+                if(server_type === 'ppas' &&
+                    !_.isUndefined(tfunction) &&
+                tfunction === 'Inline EDB-SPL') {
+                    // Disbale and clear its value
+                    m.set('tgargs', undefined)
+                    return true;
+                } else {
+                    return false;
+                }
+            } else {
+                // Disbale it
+                return true;
+            }
+          }
+        },{
+        id: 'fires', label:'{{ _('Fires') }}', deps: ['is_constraint_trigger'],
+        mode: ['create','edit', 'properties'], group: '{{ _('Definition') }}',
+        options: function(control) {
+            var table_options = [
+                {label: "BEFORE", value: "BEFORE"},
+                {label: "AFTER", value: "AFTER"}],
+                view_options = [
+                {label: "BEFORE", value: "BEFORE"},
+                {label: "AFTER", value: "AFTER"},
+                {label: "INSTEAD OF", value: "INSTEAD OF"}];
+            // If we are under table then show table specific options
+            if(_.indexOf(Object.keys(control.model.node_info), 'table') != -1) {
+                return table_options;
+            } else {
+                return view_options;
+            }
+        },
+        // If create mode then by default open composite type
+        control: Backform.Select2Control.extend({
+            render: function(){
+                // Initialize parent's render method
+                Backform.Select2Control.prototype.render.apply(this, arguments);
+                if(this.model.isNew() &&
+                        this.model.get('is_constraint_trigger') !== true ) {
+                    this.model.set({'fires': 'BEFORE'}, {silent: true});
+                }
+                return this;
+            }
+        }),
+        select2: { allowClear: false, width: "100%" },
+        disabled: function(m) {
+        // If contraint trigger is set to True then only enable it
+        var is_constraint_trigger = m.get('is_constraint_trigger');
+        if(!m.inSchemaWithModelCheck.apply(this, [m])) {
+            if(!_.isUndefined(is_constraint_trigger) &&
+            is_constraint_trigger === true) {
+                setTimeout(function() { m.set('fires', 'AFTER', {silent: true}) }, 10);
+                return true;
+            } else {
+                return false;
+            }
+        } else {
+            // Disbale it
+            return true;
+        }
+       }
+      },{
+        type: 'nested', control: 'fieldset', mode: ['create','edit', 'properties'],
+        label: '{{ _('Events') }}', group: '{{ _('Definition') }}',
+        schema:[{
+            id: 'evnt_insert', label:'{{ _('INSERT') }}',
+            type: 'switch', mode: ['create','edit', 'properties'],
+            group: '{{ _('Events') }}',
+            disabled: function(m) {
+                return m.inSchemaWithModelCheck.apply(this, [m]);
+            }
+        },{
+            id: 'evnt_update', label:'{{ _('UPDATE') }}',
+            type: 'switch', mode: ['create','edit', 'properties'],
+            group: '{{ _('Events') }}',
+            disabled: function(m) {
+                return m.inSchemaWithModelCheck.apply(this, [m]);
+            }
+        },{
+            id: 'evnt_delete', label:'{{ _('DELETE') }}',
+            type: 'switch', mode: ['create','edit', 'properties'],
+            group: '{{ _('Events') }}',
+            disabled: function(m) {
+                return m.inSchemaWithModelCheck.apply(this, [m]);
+            }
+        },{
+            id: 'evnt_turncate', label:'{{ _('TRUNCATE') }}',
+            type: 'switch', group: '{{ _('Events') }}',
+            disabled: function(m) {
+            var is_constraint_trigger = m.get('is_constraint_trigger'),
+                is_row_trigger = m.get('is_row_trigger'),
+                server_type = m.node_info['server']['server_type'];
+            if(!m.inSchemaWithModelCheck.apply(this, [m])) {
+                // We will enabale truncate only for EDB PPAS
+                // and both triggers row & constarint are set to false
+                if(server_type === 'ppas' &&
+                    !_.isUndefined(is_constraint_trigger) &&
+                    !_.isUndefined(is_row_trigger) &&
+                is_constraint_trigger === false &&
+                    is_row_trigger === false) {
+                    return false;
+                } else {
+                    return true;
+                }
+            } else {
+                // Disbale it
+                return true;
+            }
+        }
+        }]
+        },{
+            id: 'whenclause', label:'{{ _('When') }}',
+            type: 'text', disabled: 'inSchemaWithModelCheck',
+            mode: ['create', 'edit', 'properties'],
+            control: 'sql-field', visible: true, group: '{{ _('Definition') }}'
+        },{
+            id: 'columns', label: '{{ _('Columns') }}', url: 'nodes',
+            type: 'collection', control: 'multi-select-ajax',
+            deps: ['evnt_update'], node: 'column', group: '{{ _('Definition') }}',
+            model: pgBrowser.Node.Model.extend({
+                keys: ['column'], defaults: { column: undefined }
+            }),
+            disabled: function(m) {
+                if(this.node_info &&  'catalog' in this.node_info) {
+                    return true;
+                }
+                //Disbale in edit mode
+                if (!m.isNew()) {
+                    return true;
+                }
+                // Enable column only if update event is set true
+                var isUpdate = m.get('evnt_update');
+                if(!_.isUndefined(isUpdate) && isUpdate) {
+                    return false;
+                }
+             return true;
+            }
+        },{
+            id: 'code', label:'{{ _('Code') }}', group: '{{ _('Code') }}',
+            type: 'text', mode: ['create', 'edit'], deps: ['tfunction'],
+            control: 'sql-field', visible: true,
+            disabled: function(m) {
+                // We will enable it only when EDB PPAS and trigger function is
+                // set to Inline EDB-SPL
+                var tfunction = m.get('tfunction'),
+                    server_type = m.node_info['server']['server_type'];
+                if(!m.inSchemaWithModelCheck.apply(this, [m])) {
+                    if(server_type === 'ppas' &&
+                        !_.isUndefined(tfunction) &&
+                    tfunction === 'Inline EDB-SPL') {
+                        return false;
+                        // Also clear and disable Argument field
+                    } else {
+                        return true;
+                    }
+                } else {
+                    // Disbale it
+                      return true;
+                }
+            }
+        },{
+          id: 'is_sys_trigger', label:'{{ _('System trigger?') }}', cell: 'string',
+          type: 'switch', disabled: 'inSchemaWithModelCheck', mode: ['properties']
+        },{
+          id: 'is_constarint', label:'{{ _('Constraint?') }}', cell: 'string',
+          type: 'switch', disabled: 'inSchemaWithModelCheck', mode: ['properties']
+        },{
+          id: 'description', label:'{{ _('Comment') }}', cell: 'string',
+          type: 'multiline', mode: ['properties', 'create', 'edit'],
+          disabled: 'inSchema'
+    }],
+        validate: function() {
+          var err = {},
+              msg = undefined;
+          this.errorModel.clear();
+
+          if(_.isUndefined(this.get('name'))
+              || String(this.get('name')).replace(/^\s+|\s+$/g, '') == '') {
+            msg = '{{ _('Name can not be empty.') }}';
+            this.errorModel.set('name', msg);
+            return msg;
+            }
+          if(_.isUndefined(this.get('tfunction'))
+              || String(this.get('tfunction')).replace(/^\s+|\s+$/g, '') == '') {
+            msg = '{{ _('Trigger function can not be empty.') }}';
+            this.errorModel.set('tfunction', msg);
+            return msg;
+          }
+
+          if(!this.get('evnt_turncate') && !this.get('evnt_delete') && !this.get('evnt_update') && !this.get('evnt_insert')) {
+          msg = '{{ _('Specify atleast one event.') }}';
+          this.errorModel.set('evnt_turncate', " ");
+          this.errorModel.set('evnt_delete', " ");
+          this.errorModel.set('evnt_update', " ");
+          this.errorModel.set('evnt_insert', msg);
+          return msg;
+          }
+          return null;
+        },
+        // We will check if we are under schema node & in 'create' mode
+        inSchema: function() {
+          if(this.node_info &&  'catalog' in this.node_info) {
+            return true;
+          }
+          return false;
+        },
+        // We will check if we are under schema node & in 'create' mode
+        inSchemaWithModelCheck: function(m) {
+          if(this.node_info &&  'schema' in this.node_info) {
+            // We will disable control if it's in 'edit' mode
+            if (m.isNew()) {
+              return false;
+            } else {
+              return true;
+            }
+          }
+          return true;
+        },
+        // Checks weather to enable/disable control
+        inSchemaWithColumnCheck: function(m) {
+          if(this.node_info &&  'schema' in this.node_info) {
+            // We will disable control if it's system columns
+            // ie: it's position is less then 1
+            if (m.isNew()) {
+              return false;
+            } else {
+              // if we are in edit mode
+              if (!_.isUndefined(m.get('attnum')) && m.get('attnum') >= 1 ) {
+                return false;
+              } else {
+                return true;
+              }
+           }
+          }
+          return true;
+        }
+      }),
+      // Below function will enable right click menu for creating column
+      canCreate: function(itemData, item, data) {
+          // If check is false then , we will allow create menu
+          if (data && data.check == false)
+            return true;
+
+          var t = pgBrowser.tree, i = item, d = itemData, parents = [];
+          // To iterate over tree to check parent node
+          while (i) {
+            // If it is schema then allow user to c reate table
+            if (_.indexOf(['schema'], d._type) > -1)
+              return true;
+            parents.push(d._type);
+            i = t.hasParent(i) ? t.parent(i) : null;
+            d = i ? t.itemData(i) : null;
+          }
+          // If node is under catalog then do not allow 'create' menu
+          if (_.indexOf(parents, 'catalog') > -1) {
+            return false;
+          } else {
+            return true;
+          }
+      },
+      // Check to whether trigger is disable ?
+      canCreate_with_trigger_enable: function(itemData, item, data) {
+        if(this.canCreate.apply(this, [itemData, item, data])) {
+          // We are here means we can create menu, now let's check condition
+          if(itemData.icon === 'icon-trigger-bad') {
+            return true;
+          } else {
+            return false;
+          }
+        }
+      },
+      // Check to whether trigger is enable ?
+      canCreate_with_trigger_disable: function(itemData, item, data) {
+        if(this.canCreate.apply(this, [itemData, item, data])) {
+          // We are here means we can create menu, now let's check condition
+          if(itemData.icon === 'icon-trigger') {
+            return true;
+          } else {
+            return false;
+          }
+        }
+      }
+  });
+ }
+
+  return pgBrowser.Nodes['trigger'];
+});
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/datatype/sql/9.1_plus/get_types.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/datatype/sql/9.1_plus/get_types.sql
index b8952d2..f465a46 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/datatype/sql/9.1_plus/get_types.sql
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/datatype/sql/9.1_plus/get_types.sql
@@ -5,7 +5,8 @@ FROM
         format_type(t.oid,NULL) AS typname,
         CASE WHEN typelem > 0 THEN typelem ELSE t.oid END as elemoid,
         typlen, typtype, t.oid, nspname,
-        (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup
+        (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup,
+        CASE WHEN t.typcollation != 0 THEN TRUE ELSE FALSE END AS is_collatable
     FROM
         pg_type t
     JOIN
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/macros/schemas/privilege.macros b/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/macros/schemas/privilege.macros
index 183ec2f..dc18a31 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/macros/schemas/privilege.macros
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/macros/schemas/privilege.macros
@@ -6,6 +6,10 @@
 GRANT {{ privs|join(', ') }} ON {{ type }} {{ conn|qtIdent(schema, param) }} TO {{ conn|qtIdent(role) }};
 {% endif %}
 {% if with_grant_privs %}
+{% if privs %}
+{# This empty if is to add new line in between #}
+
+{% endif %}
 GRANT {{ with_grant_privs|join(', ') }} ON {{ type }} {{ conn|qtIdent(schema, param) }} TO {{ conn|qtIdent(role) }} WITH GRANT OPTION;
 {% endif %}
 {%- endmacro %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/schema/js/schema.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/schema/js/schema.js
index dc393d5..210f3e6 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/schema/js/schema.js
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/schema/js/schema.js
@@ -4,6 +4,256 @@ define(
         'pgadmin.browser.collection',
         'pgadmin.browser.server.privilege'],
 function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
+
+
+    // VaccumSettings Collection to display all settings parameters as Grid
+    var VacuumCollectionControl = Backform.VacuumCollectionControl =
+      Backform.Control.extend({
+
+      grid_columns:undefined,
+
+      initialize: function() {
+        Backform.Control.prototype.initialize.apply(this, arguments);
+        var self = this,
+            m = this.model;
+            url = self.field.get('url');
+
+        if (url && m.isNew()) {
+          var node = self.field.get('node'),
+              node_data = self.field.get('node_data'),
+              node_info = self.field.get('node_info'),
+              full_url = node.generate_url.apply(
+                node, [
+                  null, url, node_data, false, node_info
+                ]),
+              data;
+          m.trigger('pgadmin-view:fetching', m, self.field);
+
+          // fetch default values for autovacuum fields
+          $.ajax({
+            async: false,
+            url: full_url,
+            success: function (res) {
+              data = res;
+            },
+            error: function() {
+              m.trigger('pgadmin-view:fetch:error', m, self.field);
+            }
+          });
+          m.trigger('pgadmin-view:fetched', m, self.field);
+
+          // Add fetched models into collection
+          if (data && _.isArray(data)) {
+            m.get(self.field.get('name')).reset(data, {silent: true});
+          }
+        }
+      },
+
+      render: function() {
+        var self = this,
+            m = this.model,
+            attributes = self.field.attributes;
+
+        // remove grid
+        if(self.grid) {
+          self.grid.remove();
+          delete self.grid;
+          self.grid = undefined;
+        }
+
+        self.$el.empty();
+
+        var gridHeader = _.template([
+            '<div class="subnode-header">',
+            '  <label class="control-label col-sm-4"><%-label%></label>',
+            '</div>'].join("\n")),
+            gridBody = $('<div class="pgadmin-control-group backgrid form-group col-xs-12 object subnode"></div>').append(
+                gridHeader(attributes)
+                );
+
+        // Initialize a new Grid instance
+        var grid = self.grid = new Backgrid.Grid({
+          columns: self.grid_columns,
+          collection: self.model.get(self.field.get('name')),
+          className: "backgrid table-bordered"
+        });
+
+        // render grid
+        self.$el.append($(gridBody).append(grid.render().$el));
+
+        return self;
+      }
+    });
+
+  // We will use this function in VacuumSettings Control
+  // to convert data type on the fly
+  var cellFunction = Backform.cellFunction = function(model) {
+    var self = this,
+        m = model,
+        vartype = model.get('column_type');
+
+    switch(vartype) {
+      case "integer":
+        return Backgrid.IntegerCell;
+      break;
+      case "number":
+        return Backgrid.NumberCell;
+      break;
+      case "string":
+        return Backgrid.StringCell;
+      break;
+      default:
+        return Backgrid.Cell;
+      break;
+    }
+  };
+
+  // Define Security Model with fields and validation for VacuumSettings Control
+  var VacuumTableModel =  Backform.VacuumTableModel = pgAdmin.Browser.Node.Model.extend({
+    defaults: {
+      name: undefined,
+      setting: undefined,
+      label:undefined,
+      value: undefined,
+      column_type: undefined
+    },
+
+    toJSON: function(){
+      var d = pgAdmin.Browser.Node.Model.prototype.toJSON.apply(this);
+      delete d.label;
+      delete d.setting;
+      delete d.column_type;
+      return d;
+    }
+  });
+
+   // Extend the browser's collection class for VacuumSettingsModel
+    var VacuumSettingsSchema = Backform.VacuumSettingsSchema =
+     [{
+        id: 'autovacuum_custom', label: '{{ _("Custom auto-vacuum?") }}',
+        group: '{{ _("Table") }}', mode: ['edit', 'create'],
+        type: 'switch',
+        disabled: function(m) {
+          if(!m.top.inSchema.apply(this, [m])) {
+            return false;
+          }
+          return true;
+        }
+      },{
+        id: 'autovacuum_enabled', label: '{{ _("Enabled?") }}',
+        group: '{{ _("Table") }}', mode: ['edit', 'create'],
+        type: 'switch',
+        deps: ['autovacuum_custom'],
+        disabled: function(m) {
+          if(!m.top.inSchema.apply(this, [m]) &&
+            m.get('autovacuum_custom') == true) {
+            return false;
+          }
+
+          // We also need to unset rest of all
+          setTimeout(function() {
+            m.set('autovacuum_enabled', false);
+          }, 10);
+          return true;
+        }
+      },{
+        id: 'vacuum_table', label: '{{ _("Vacuum Table") }}',
+        model: Backform.VacuumTableModel, editable: false, type: 'collection',
+        canEdit: true, group: '{{ _("Table") }}',
+        mode: ['edit', 'create'], url: 'get_table_vacuum',
+        control: Backform.VacuumCollectionControl.extend({
+          grid_columns :[
+            {
+              name: 'label', label: '{{ _("Label") }}',
+              headerCell: Backgrid.Extension.CustomHeaderCell,
+              cell: 'string', editable: false, cellHeaderClasses:'width_percent_40'
+            },
+            {
+              name: 'value', label: '{{ _("Value") }}',
+              cellHeaderClasses:'width_percent_30',
+              cellFunction: Backform.cellFunction, editable: function(m) {
+                return m.handler.get('autovacuum_enabled');
+              }, headerCell: Backgrid.Extension.CustomHeaderCell
+            },
+            {
+              name: 'setting', label: '{{ _("Default value") }}',
+              cellHeaderClasses:'width_percent_30',
+              headerCell: Backgrid.Extension.CustomHeaderCell,
+              cellFunction: Backform.cellFunction, editable: false
+            }
+          ]
+        }),
+        deps: ['autovacuum_enabled']
+      },{
+        id: 'toast_autovacuum', label: '{{ _("Custom auto-vaccum?") }}',
+        group: '{{ _("Toast Table") }}', mode: ['edit', 'create'],
+        type: 'switch',
+        disabled: function(m) {
+          // We need to check additional condition to toggle enable/disable
+          // for table auto-vacuum
+          if(!m.top.inSchema.apply(this, [m]) && m.isNew()) {
+            return false;
+          } else if(!m.top.inSchema.apply(this, [m]) &&
+              (m.get('toast_autovacuum_enabled') === true ||
+              m.top.get('hastoasttable') === true)) {
+            return false;
+          }
+          return true;
+        }
+      },{
+        id: 'toast_autovacuum_enabled', label: '{{ _("Enabled?") }}',
+        group: '{{ _("Toast Table") }}', mode: ['edit', 'create'],
+        type: 'switch',
+        deps:['toast_autovacuum'],
+        disabled: function(m) {
+          // If in schema & in create mode then enable it
+          if(!m.top.inSchema.apply(this, [m]) &&
+              m.get('toast_autovacuum') === true) {
+            return false;
+          }
+
+          if (m.isNew() || m.get('hastoasttable')) {
+            // we also need to unset rest of all
+            setTimeout(function() {
+              m.set('toast_autovacuum_enabled', false);
+            }, 10);
+          }
+        return true;
+        }
+      },{
+        id: 'vacuum_toast', label: '{{ _("Vacuum Toast Table") }}',
+        model: Backform.VacuumTableModel, type: 'collection', editable: function(m) {
+          return m.isNew();
+        },
+        canEdit: true, group: '{{ _("Toast Table") }}',
+        mode: ['properties', 'edit', 'create'], url: 'get_toast_table_vacuum',
+        control: Backform.VacuumCollectionControl.extend({
+          grid_columns :[
+            {
+              name: 'label', label: '{{ _("Label") }}',
+              headerCell: Backgrid.Extension.CustomHeaderCell,
+              cell: 'string', editable: false, cellHeaderClasses:'width_percent_40'
+            },
+            {
+              name: 'value', label: '{{ _("Value") }}',
+              cellHeaderClasses:'width_percent_30',
+              headerCell: Backgrid.Extension.CustomHeaderCell,
+              cellFunction: Backform.cellFunction, editable: function(m) {
+                return m.handler.get('toast_autovacuum_enabled');
+              }
+            },
+            {
+              name: 'setting', label: '{{ _("Default value") }}',
+              cellHeaderClasses:'width_percent_30',
+              headerCell: Backgrid.Extension.CustomHeaderCell,
+              cellFunction: Backform.cellFunction, editable: false
+            }
+          ]
+        }),
+        deps: ['toast_autovacuum_enabled']
+      }
+    ];
+
    // Extend the browser's collection class for SecurityLabel control
     var SecurityModel = Backform.SecurityModel = pgAdmin.Browser.Node.Model.extend({
     defaults: {
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/vacuum_settings/sql/vacuum_defaults.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/vacuum_settings/sql/vacuum_defaults.sql
new file mode 100644
index 0000000..e60598c
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/vacuum_settings/sql/vacuum_defaults.sql
@@ -0,0 +1,2 @@
+{# ============= Fetch list of default values for autovacuum parameters =============== #}
+SELECT name, setting::numeric AS setting FROM pg_settings WHERE name IN({{ columns }}) ORDER BY name
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/vacuum_settings/vacuum_fields.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/vacuum_settings/vacuum_fields.json
new file mode 100644
index 0000000..83571f4
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/templates/vacuum_settings/vacuum_fields.json
@@ -0,0 +1,39 @@
+{# ===== Define name, label and column type of vacuum settings ===== #}
+{# Usage:
+
+  'Type":
+  {
+    "key": ["label", "column_type"
+  }
+
+  Where
+    -  "Type" either table/toast
+    -  "key" refers to the name of columns we fetch in properties.sql
+    -  "label" It is the name of properties to display in grid.
+    -  "column_type" Type of column, we have to provide the grid what type of value to rendered
+#}
+{# ===== Define name, label and column type of vacuum settings ===== #}
+{
+  "table":
+  {
+    "autovacuum_vacuum_threshold": ["autovacuum_vacuum_threshold", "VACCUM base threshold", "integer"],
+    "autovacuum_analyze_threshold": ["autovacuum_analyze_threshold", "ANALYZE base threshold", "integer"],
+    "autovacuum_vacuum_scale_factor": ["autovacuum_vacuum_scale_factor", "VACCUM scale factor", "number"],
+    "autovacuum_analyze_scale_factor": ["autovacuum_analyze_scale_factor", "ANALYZE scale factor", "number"],
+    "autovacuum_vacuum_cost_delay": ["autovacuum_vacuum_cost_delay", "VACCUM cost delay", "integer"],
+    "autovacuum_vacuum_cost_limit": ["autovacuum_vacuum_cost_limit", "VACCUM cost limit", "integer"],
+    "autovacuum_freeze_max_age": ["autovacuum_freeze_max_age", "FREEZE maximum age", "integer"],
+    "vacuum_freeze_min_age": ["autovacuum_freeze_min_age", "FREEZE minimum age", "integer"],
+    "vacuum_freeze_table_age": ["autovacuum_freeze_table_age", "FREEZE table age", "integer"]
+  },
+  "toast":
+  {
+    "autovacuum_vacuum_threshold": ["autovacuum_vacuum_threshold", "VACCUM base threshold", "integer"],
+    "autovacuum_vacuum_scale_factor": ["autovacuum_vacuum_scale_factor", "VACCUM scale factor", "number"],
+    "autovacuum_vacuum_cost_delay": ["autovacuum_vacuum_cost_delay", "VACCUM cost delay", "integer"],
+    "autovacuum_vacuum_cost_limit": ["autovacuum_vacuum_cost_limit", "VACCUM cost limit", "integer"],
+    "autovacuum_freeze_max_age": ["autovacuum_freeze_max_age", "FREEZE maximum age", "integer"],
+    "vacuum_freeze_min_age": ["autovacuum_freeze_min_age", "FREEZE minimum age", "integer"],
+    "vacuum_freeze_table_age": ["autovacuum_freeze_table_age", "FREEZE table age", "integer"]
+  }
+}
\ No newline at end of file
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 29c7936..17a35b6 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/utils.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/utils.py
@@ -134,7 +134,8 @@ class DataTypeReader:
                 res.append({
                     'label': row['typname'], 'value': row['typname'],
                     'typval': typeval, 'precision': precision,
-                    'length': length, 'min_val': min_val, 'max_val': max_val
+                    'length': length, 'min_val': min_val, 'max_val': max_val,
+                    'is_collatable': row['is_collatable']
                 })
 
         except Exception as e:
@@ -338,4 +339,156 @@ def parse_rule_definition(res):
         res_data['condition'] = condition
     except Exception as e:
         return internal_server_error(errormsg=str(e))
-    return res_data
\ No newline at end of file
+    return res_data
+
+
+class VacuumSettings:
+    """
+    VacuumSettings Class.
+
+    This class includes common utilities to fetch and parse
+    vacuum defaults settings.
+
+    Methods:
+    -------
+    * get_vacuum_table_settings(conn):
+      - Returns vacuum table defaults settings.
+
+    * get_vacuum_toast_settings(conn):
+      - Returns vacuum toast defaults settings.
+
+    * parse_vacuum_data(conn, result, type):
+      - Returns result of an associated array
+        of fields name, label, value and column_type.
+        It adds name, label, column_type properties of table/toast
+        vacuum into the array and returns it.
+        args:
+        * conn - It is db connection object
+        * result - Resultset of vacuum data
+        * type - table/toast vacuum type
+
+    """
+    def __init__(self):
+        pass
+
+    def get_vacuum_table_settings(self, conn):
+        """
+        Fetch the default values for autovacuum
+        fields, return an array of
+          - label
+          - name
+          - setting
+        values
+        """
+
+        # 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())+"'"
+        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['table'][row_name][0]
+            row['label'] = vacuum_fields['table'][row_name][1]
+            row['column_type'] = vacuum_fields['table'][row_name][2]
+
+        return res
+
+    def get_vacuum_toast_settings(self, conn):
+        """
+        Fetch the default values for autovacuum
+        fields, return an array of
+          - label
+          - name
+          - setting
+        values
+        """
+
+        # 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 parse_vacuum_data(self, conn, result, type):
+        """
+        This function returns result of an associated array
+        of fields name, label, value and column_type.
+        It adds name, label, column_type properties of table/toast
+        vacuum into the array and returns it.
+        args:
+        * conn - It is db connection object
+        * result - Resultset of vacuum data
+        * type - table/toast vacuum type
+        """
+
+        # 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[type].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)
+
+        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
+
+        return res['rows']
\ No newline at end of file
