diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/__init__.py
new file mode 100644
index 0000000..1a0738f
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/__init__.py
@@ -0,0 +1,544 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+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 NodeView
+from pgadmin.browser.collection import CollectionNodeModule
+import pgadmin.browser.server_groups.servers as servers
+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 ForeignDataWrapperModule(CollectionNodeModule):
+    NODE_TYPE = 'foreign_data_wrapper'
+    COLLECTION_LABEL = gettext("Foreign Data Wrappers")
+
+    def __init__(self, *args, **kwargs):
+        self.min_ver = None
+        self.max_ver = None
+
+        super(ForeignDataWrapperModule, self).__init__(*args, **kwargs)
+
+    def get_nodes(self, gid, sid, did):
+        """
+        Generate the collection node
+        Parameters:
+            gid
+            - Group ID
+            sid
+            - Server ID
+            did
+            - Database ID
+        """
+        yield self.generate_browser_collection_node(did)
+
+    @property
+    def script_load(self):
+        """
+        Load the module script for foreign data wrapper, when any of the database node is
+        initialized.
+        """
+        return servers.ServerModule.NODE_TYPE
+
+blueprint = ForeignDataWrapperModule(__name__)
+
+
+class ForeignDataWrapperView(NodeView):
+    node_type = blueprint.node_type
+
+    parent_ids = [
+            {'type': 'int', 'id': 'gid'},
+            {'type': 'int', 'id': 'sid'},
+            {'type': 'int', 'id': 'did'}
+            ]
+    ids = [
+            {'type': 'int', 'id': 'fid'}
+            ]
+
+    operations = dict({
+        'obj': [
+            {'get': 'properties', 'delete': 'delete', 'put': 'update'},
+            {'get': 'list', 'post': 'create'}
+        ],
+        'delete': [{
+           'delete': 'delete'
+        }],
+        'nodes': [{'get': 'node'}, {'get': 'nodes'}],
+        'children': [{'get': 'children'}],
+        'sql': [{'get': 'sql'}],
+        'msql': [{'get': 'msql'}, {'get': 'msql'}],
+        'stats': [{'get': 'statistics'}],
+        'dependency': [{'get': 'dependencies'}],
+        'dependent': [{'get': 'dependents'}],
+        'module.js': [{}, {}, {'get': 'module_js'}],
+        'get_handlers': [{}, {'get': 'get_handlers'}],
+        'get_validators': [{}, {'get': 'get_validators'}]
+    })
+
+    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_data_wrappers/js/foreign_data_wrappers.js",
+                    _=gettext
+                    ),
+                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(
+                    gettext(
+                            "Connection to the server has been lost!"
+                    )
+                )
+
+            ver = self.manager.version
+            # we will set template path for sql scripts
+            if ver >= 90300:
+                self.template_path = 'foreign_data_wrappers/sql/9.3_plus'
+            else:
+                self.template_path = 'foreign_data_wrappers/sql/9.1_plus'
+
+            return f(*args, **kwargs)
+        return wrap
+
+    @check_precondition
+    def list(self, gid, sid, did):
+        sql = render_template("/".join([self.template_path, 'properties.sql']), conn=self.conn)
+        status, res = self.conn.execute_dict(sql)
+
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        for row in res['rows']:
+            if row['fdwoptions'] is not None:
+                row['fdwoptions'] = self.tokenize_options(row['fdwoptions'])
+
+        return ajax_response(
+                response=res['rows'],
+                status=200
+                )
+
+    @check_precondition
+    def nodes(self, gid, sid, did):
+        res = []
+        sql = render_template("/".join([self.template_path, 'properties.sql']), conn=self.conn)
+        status, r_set = self.conn.execute_2darray(sql)
+        if not status:
+            return internal_server_error(errormsg=r_set)
+
+        for row in r_set['rows']:
+            res.append(
+                    self.blueprint.generate_browser_node(
+                        row['fdwoid'],
+                        did,
+                        row['name'],
+                        icon="icon-foreign_data_wrapper"
+                    ))
+
+        return make_json_response(
+                data=res,
+                status=200
+                )
+
+    def tokenize_options(self, option_value):
+        """
+        This function will tokenize the string stored in database
+        e.g. database store the value as below
+        key1=value1, key2=value2, key3=value3, ....
+        This function will extract key and value from above string
+        Parameters:
+            option_value
+            - key value option/value pair read from database
+        """
+        if option_value is not None:
+            option_str = option_value.split(',')
+            fdw_options = []
+            for fdw_option in option_str:
+                k, v = fdw_option.split('=', 1)
+                fdw_options.append({'fdwoption': k, 'fdwvalue': v})
+            return fdw_options
+
+    @check_precondition
+    def properties(self, gid, sid, did, fid):
+        sql = render_template("/".join([self.template_path, 'properties.sql']), fid=fid, conn=self.conn)
+        status, res = self.conn.execute_dict(sql)
+
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        if res['rows'][0]['fdwoptions'] is not None:
+            res['rows'][0]['fdwoptions'] = self.tokenize_options(res['rows'][0]['fdwoptions'])
+
+        sql = render_template("/".join([self.template_path, 'acl.sql']), fid=fid)
+        status, fdw_acl_res = self.conn.execute_dict(sql)
+        if not status:
+            return internal_server_error(errormsg=fdw_acl_res)
+
+        for row in fdw_acl_res['rows']:
+            privilege = parse_priv_from_db(row)
+            if row['deftype'] in res['rows'][0]:
+                res['rows'][0][row['deftype']].append(privilege)
+            else:
+                res['rows'][0][row['deftype']] = [privilege]
+
+        return ajax_response(
+                response=res['rows'][0],
+                status=200
+                )
+
+    @check_precondition
+    def create(self, gid, sid, did):
+        """
+        This function will creates new the foreign data wrapper object
+        Parameters:
+            gid
+            - Group ID
+            sid
+            - Server ID
+            did
+            - Database ID
+        """
+
+        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:
+
+            if 'fdwacl' in data:
+                data['fdwacl'] = parse_priv_to_db(data['fdwacl'])
+
+            sql = render_template("/".join([self.template_path, 'create.sql']), data=data, conn=self.conn)
+            status, res = self.conn.execute_dict(sql)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            sql = render_template("/".join([self.template_path, 'properties.sql']), fname=data['name'], conn=self.conn)
+
+            status, r_set = self.conn.execute_dict(sql)
+            if not status:
+                return internal_server_error(errormsg=r_set)
+
+            for row in r_set['rows']:
+                return jsonify(
+                    node=self.blueprint.generate_browser_node(
+                        row['fdwoid'],
+                        did,
+                        row['name'],
+                        icon='icon-foreign_data_wrapper'
+                    )
+                )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def update(self, gid, sid, did, fid):
+        """
+        This function will update foreign data wrapper object
+        Parameters:
+            gid
+            - Group ID
+            sid
+            - Server ID
+            did
+            - Database ID
+            fid
+            - Foreign data wrapper ID
+        """
+        data = request.form if request.form else json.loads(request.data.decode())
+        sql = self.getSQL(gid, sid, data, did, fid)
+        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="Foreign Data Wrapper updated",
+                    data={
+                        'id':  fid,
+                        'did': did,
+                        'sid': sid,
+                        'gid': gid
+                    }
+                )
+            else:
+                return make_json_response(
+                    success=1,
+                    info="Nothing to update",
+                    data={
+                        'id':  fid,
+                        'did': did,
+                        'sid': sid,
+                        'gid': gid
+                    }
+                )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def delete(self, gid, sid, did, fid):
+        """
+        This function will drop the foreign data wrapper object
+        Parameters:
+            gid
+            - Group ID
+            sid
+            - Server ID
+            did
+            - Database ID
+            fid
+            - Foreign data wrapper ID
+        """
+        if self.cmd == 'delete':
+            # This is a cascade operation
+            cascade = True
+        else:
+            cascade = False
+
+        try:
+            # Get name of foreign data wrapper from fid
+            sql = render_template("/".join([self.template_path, 'delete.sql']), fid=fid, conn=self.conn)
+            status, name = self.conn.execute_scalar(sql)
+            if not status:
+                return internal_server_error(errormsg=name)
+            # drop foreign data wrapper node
+            sql = render_template("/".join([self.template_path, 'delete.sql']), name=name, 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("Foreign Data Wrapper dropped"),
+                data={
+                    'id': fid,
+                    'did': did,
+                    'sid': sid,
+                    'gid': gid,
+                }
+            )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def msql(self, gid, sid, did, fid=None):
+        """
+        This function to return modified SQL
+        Parameters:
+            gid
+            - Group ID
+            sid
+            - Server ID
+            did
+            - Database ID
+            fid
+            - Foreign data wrapper ID
+        """
+        data = {}
+        for k, v in request.args.items():
+            try:
+                data[k] = json.loads(v)
+            except ValueError:
+                data[k] = v
+
+        sql = self.getSQL(gid, sid, data, did, fid)
+        if sql and sql.strip('\n') and sql.strip(' '):
+            return make_json_response(data=sql,status=200)
+        else:
+            return make_json_response(data='-- Modified SQL --',status=200)
+
+    def getSQL(self, gid, sid, data, did, fid=None):
+        """
+        This function will generate sql from model data
+        Parameters:
+            gid
+            - Group ID
+            sid
+            - Server ID
+            data
+            - data received from client
+            did
+            - Database ID
+            fid
+            - Foreign data wrapper ID
+        """
+        required_args = [
+            'name'
+        ]
+        try:
+            if fid is not None:
+                sql = render_template("/".join([self.template_path, 'properties.sql']), fid=fid, conn=self.conn)
+                status, res = self.conn.execute_dict(sql)
+                if not status:
+                    return internal_server_error(errormsg=res)
+
+                if res['rows'][0]['fdwoptions'] is not None:
+                    res['rows'][0]['fdwoptions'] = self.tokenize_options(res['rows'][0]['fdwoptions'])
+
+                for key in ['fdwacl']:
+                    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'])
+                        if 'changed' in data[key]:
+                          data[key]['changed'] = parse_priv_to_db(data[key]['changed'])
+                        if 'deleted' in data[key]:
+                          data[key]['deleted'] = parse_priv_to_db(data[key]['deleted'])
+
+                old_data = res['rows'][0]
+                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:
+                for key in ['fdwacl']:
+                    if key in data and data[key] is not None:
+                        data[key] = parse_priv_to_db(data[key])
+
+                sql = render_template("/".join([self.template_path, 'create.sql']), data=data, conn=self.conn)
+                sql += "\n"
+            return sql
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def sql(self, gid, sid, did, fid):
+        """
+        This function will generate sql for sql panel
+        Parameters:
+            gid
+            - Group ID
+            sid
+            - Server ID
+            did
+            - Database ID
+            fid
+            - Foreign data wrapper ID
+        """
+        sql = render_template("/".join([self.template_path, 'properties.sql']), fid=fid, conn=self.conn)
+        status, res = self.conn.execute_dict(sql)
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        if res['rows'][0]['fdwoptions'] is not None:
+            res['rows'][0]['fdwoptions'] = self.tokenize_options(res['rows'][0]['fdwoptions'])
+
+        sql = render_template("/".join([self.template_path, 'acl.sql']), fid=fid)
+        status, fdw_acl_res = self.conn.execute_dict(sql)
+        if not status:
+            return internal_server_error(errormsg=fdw_acl_res)
+
+        for row in fdw_acl_res['rows']:
+            privilege = parse_priv_from_db(row)
+            if row['deftype'] in res['rows'][0]:
+                res['rows'][0][row['deftype']].append(privilege)
+            else:
+                res['rows'][0][row['deftype']] = [privilege]
+
+        # To format privileges
+        if 'fdwacl' in res['rows'][0]:
+            res['rows'][0]['fdwacl'] = parse_priv_to_db(res['rows'][0]['fdwacl'])
+
+        sql = ''
+        sql = render_template("/".join([self.template_path, 'create.sql']), data=res['rows'][0], conn=self.conn)
+        sql += "\n"
+
+        sql_header = """
+-- Foreign Data Wrapper: {0}
+
+-- DROP FOREIGN DATA WRAPPER {0}
+
+""".format(res['rows'][0]['name'])
+
+        sql = sql_header + sql
+
+        return ajax_response(response=sql)
+
+    @check_precondition
+    def get_validators(self, gid, sid, did):
+        res = [{'label': '', 'value': ''}]
+        try:
+            sql = render_template("/".join([self.template_path, 'validators.sql']), conn=self.conn)
+            status, r_set = self.conn.execute_2darray(sql)
+
+            if not status:
+                return internal_server_error(errormsg=r_set)
+
+            for row in r_set['rows']:
+                res.append({'label': row['fdwvalue'], 'value': row['fdwvalue']})
+
+            return make_json_response( data=res, status=200)
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def get_handlers(self, gid, sid, did):
+        res = [{'label': '', 'value': ''}]
+        try:
+            sql = render_template("/".join([self.template_path, 'handlers.sql']), conn=self.conn)
+            status, r_set = self.conn.execute_2darray(sql)
+
+            if not status:
+                return internal_server_error(errormsg=r_set)
+
+            for row in r_set['rows']:
+                res.append({'label': row['fdwhan'], 'value': row['fdwhan']})
+
+            return make_json_response(
+                   data=res,
+                   status=200
+                   )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+ForeignDataWrapperView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/__init__.py
new file mode 100644
index 0000000..736de16
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/__init__.py
@@ -0,0 +1,547 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+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 NodeView
+from pgadmin.browser.collection import CollectionNodeModule
+import pgadmin.browser.server_groups.servers as servers
+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 ForeignServerModule(CollectionNodeModule):
+    NODE_TYPE = 'foreign_server'
+    COLLECTION_LABEL = gettext("Foreign Servers")
+
+    def __init__(self, *args, **kwargs):
+        self.min_ver = None
+        self.max_ver = None
+
+        super(ForeignServerModule, self).__init__(*args, **kwargs)
+
+    def get_nodes(self, gid, sid, did, fid):
+        """
+        Generate the collection node
+        Parameters:
+            gid
+            - Group ID
+            sid
+            - Server ID
+            did
+            - Database ID
+            fid
+            - Foreign data wrapper ID
+        """
+        yield self.generate_browser_collection_node(fid)
+
+    @property
+    def script_load(self):
+        """
+        Load the module script for foreign server, when any of the foreign data wrapper node is
+        initialized.
+        """
+        return servers.ServerModule.NODE_TYPE
+
+blueprint = ForeignServerModule(__name__)
+
+
+class ForeignServerView(NodeView):
+    node_type = blueprint.node_type
+
+    parent_ids = [
+            {'type': 'int', 'id': 'gid'},
+            {'type': 'int', 'id': 'sid'},
+            {'type': 'int', 'id': 'did'},
+            {'type': 'int', 'id': 'fid'}
+            ]
+    ids = [
+            {'type': 'int', 'id': 'fsid'}
+            ]
+
+    operations = dict({
+        'obj': [
+            {'get': 'properties', 'delete': 'delete', 'put': 'update'},
+            {'get': 'list', 'post': 'create'}
+        ],
+        'delete': [{
+           'delete': 'delete'
+        }],
+        'nodes': [{'get': 'node'}, {'get': 'nodes'}],
+        'children': [{'get': 'children'}],
+        '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(
+                    "foreign_servers/js/foreign_servers.js",
+                    _=gettext
+                    ),
+                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(
+                    gettext(
+                            "Connection to the server has been lost!"
+                    )
+                )
+
+            ver = self.manager.version
+            # we will set template path for sql scripts
+            if ver >= 90300:
+                self.template_path = 'foreign_servers/sql/9.3_plus'
+            else:
+                self.template_path = 'foreign_servers/sql/9.1_plus'
+
+            return f(*args, **kwargs)
+        return wrap
+
+    @check_precondition
+    def list(self, gid, sid, did, fid):
+        sql = render_template("/".join([self.template_path, 'properties.sql']), fid=fid, conn=self.conn)
+        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, fid):
+        res = []
+        sql = render_template("/".join([self.template_path, 'properties.sql']), fid=fid, conn=self.conn)
+        status, r_set = self.conn.execute_2darray(sql)
+
+        if not status:
+            return internal_server_error(errormsg=r_set)
+
+        for row in r_set['rows']:
+            res.append(
+                    self.blueprint.generate_browser_node(
+                        row['fsrvid'],
+                        fid,
+                        row['name'],
+                        icon="icon-foreign_server"
+                    ))
+
+        return make_json_response(
+                data=res,
+                status=200
+                )
+
+    def tokenizeOptions(self, option_value):
+        """
+        This function will tokenize the string stored in database
+        e.g. database store the value as below
+        key1=value1, key2=value2, key3=value3, ....
+        This function will extract key and value from above string
+        Parameters:
+            option_value
+            - key value option/value pair read from database
+        """
+        if option_value is not None:
+            option_str = option_value.split(',')
+            fs_rv_options = []
+            for fs_rv_option in option_str:
+                k, v = fs_rv_option.split('=', 1)
+                fs_rv_options.append({'fsrvoption': k, 'fsrvvalue': v})
+            return fs_rv_options
+
+    @check_precondition
+    def properties(self, gid, sid, did, fid, fsid):
+        sql = render_template("/".join([self.template_path, 'properties.sql']), fsid=fsid, conn=self.conn)
+        status, res = self.conn.execute_dict(sql)
+
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        if res['rows'][0]['fsrvoptions'] is not None:
+            res['rows'][0]['fsrvoptions'] = self.tokenizeOptions(res['rows'][0]['fsrvoptions'])
+
+        sql = render_template("/".join([self.template_path, 'acl.sql']), fsid=fsid)
+        status, fs_rv_acl_res = self.conn.execute_dict(sql)
+
+        if not status:
+            return internal_server_error(errormsg=fs_rv_acl_res)
+
+        for row in fs_rv_acl_res['rows']:
+            privilege = parse_priv_from_db(row)
+            if row['deftype'] in res['rows'][0]:
+                res['rows'][0][row['deftype']].append(privilege)
+            else:
+                res['rows'][0][row['deftype']] = [privilege]
+
+        return ajax_response(
+                response=res['rows'][0],
+                status=200
+                )
+
+    @check_precondition
+    def create(self, gid, sid, did, fid):
+        """
+        This function will creates new foreign server object
+        Parameters:
+            gid
+            - Group ID
+            sid
+            - Server ID
+            did
+            - Database ID
+            fid
+            - Foreign data wrapper ID
+        """
+
+        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:
+            if 'fsrvacl' in data:
+                data['fsrvacl'] = parse_priv_to_db(data['fsrvacl'])
+
+            sql = render_template("/".join([self.template_path, 'properties.sql']), fdwid=fid, conn=self.conn)
+            status, res1 = self.conn.execute_dict(sql)
+            if not status:
+                return internal_server_error(errormsg=res1)
+
+            fdw_data = res1['rows'][0]
+
+            sql = render_template("/".join([self.template_path, 'create.sql']), data=data, fdwdata=fdw_data,
+                                  conn=self.conn)
+            status, res = self.conn.execute_scalar(sql)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            sql = render_template("/".join([self.template_path, 'properties.sql']), data=data, fdwdata=fdw_data,
+                                  conn=self.conn)
+            status, r_set = self.conn.execute_dict(sql)
+            if not status:
+                return internal_server_error(errormsg=r_set)
+
+            return jsonify(
+                node=self.blueprint.generate_browser_node(
+                    r_set['rows'][0]['fsrvid'],
+                    fid,
+                    r_set['rows'][0]['name'],
+                    icon="icon-foreign_server"
+                )
+            )
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def update(self, gid, sid, did, fid, fsid):
+        """
+        This function will update foreign server object
+        Parameters:
+            gid
+            - Group ID
+            sid
+            - Server ID
+            did
+            - Database ID
+            fid
+            - Foreign data wrapper ID
+            fsid
+            - Foreign server ID
+        """
+        data = request.form if request.form else json.loads(request.data.decode())
+        sql = self.getSQL(gid, sid, data, did, fid, fsid)
+        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="Foreign server updated",
+                    data={
+                        'id':  fsid,
+                        'fid': fid,
+                        'did': did,
+                        'sid': sid,
+                        'gid': gid
+                    }
+                )
+            else:
+                return make_json_response(
+                    success=1,
+                    info="Nothing to update",
+                    data={
+                        'id':  fsid,
+                        'fid': fid,
+                        'did': did,
+                        'sid': sid,
+                        'gid': gid
+                    }
+                )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def delete(self, gid, sid, did, fid, fsid):
+        """
+        This function will drop the foreign server object
+        Parameters:
+            gid
+            - Group ID
+            sid
+            - Server ID
+            did
+            - Database ID
+            fid
+            - Foreign data wrapper ID
+            fsid
+            - Foreign server ID
+        """
+        if self.cmd == 'delete':
+            # This is a cascade operation
+            cascade = True
+        else:
+            cascade = False
+
+        try:
+            # Get name of foreign data wrapper from fid
+            sql = render_template("/".join([self.template_path, 'delete.sql']), fsid=fsid, conn=self.conn)
+            status, name = self.conn.execute_scalar(sql)
+            if not status:
+                return internal_server_error(errormsg=name)
+            # drop foreign server
+            sql = render_template("/".join([self.template_path, 'delete.sql']), name=name, 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("Foreign Server dropped"),
+                data={
+                    'id': fsid,
+                    'fid': fid,
+                    'did': did,
+                    'sid': sid,
+                    'gid': gid,
+                }
+            )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def msql(self, gid, sid, did, fid, fsid=None):
+        """
+        This function to return modified SQL
+        Parameters:
+            gid
+            - Group ID
+            sid
+            - Server ID
+            did
+            - Database ID
+            fid
+            - Foreign data wrapper ID
+            fsid
+            - Foreign server ID
+        """
+        data = {}
+        for k, v in request.args.items():
+            try:
+                data[k] = json.loads(v)
+            except ValueError:
+                data[k] = v
+
+        sql = self.getSQL(gid, sid, data, did, fid, fsid)
+        if sql and sql.strip('\n') and sql.strip(' '):
+            return make_json_response(
+                    data=sql,
+                    status=200
+                    )
+        else:
+            return make_json_response(
+                    data='-- Modified SQL --',
+                    status=200
+                    )
+
+    def getSQL(self, gid, sid, data, did, fid, fsid=None):
+        """
+        This function will generate sql from model data
+        Parameters:
+            gid
+            - Group ID
+            sid
+            - Server ID
+            data
+            - Data received from client
+            did
+            - Database ID
+            fid
+            - Foreign data wrapper ID
+            fsid
+            - Foreign server ID
+        """
+        required_args = [
+            'name'
+        ]
+        try:
+            if fsid is not None:
+                sql = render_template("/".join([self.template_path, 'properties.sql']), fsid=fsid, conn=self.conn)
+                status, res = self.conn.execute_dict(sql)
+                if not status:
+                    return internal_server_error(errormsg=res)
+
+                if res['rows'][0]['fsrvoptions'] is not None:
+                    res['rows'][0]['fsrvoptions'] = self.tokenizeOptions(res['rows'][0]['fsrvoptions'])
+
+                for key in ['fsrvacl']:
+                    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'])
+                        if 'changed' in data[key]:
+                          data[key]['changed'] = parse_priv_to_db(data[key]['changed'])
+                        if 'deleted' in data[key]:
+                          data[key]['deleted'] = parse_priv_to_db(data[key]['deleted'])
+
+                old_data = res['rows'][0]
+                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:
+                sql = render_template("/".join([self.template_path, 'properties.sql']), fdwid=fid, conn=self.conn)
+                status, res = self.conn.execute_dict(sql)
+                if not status:
+                    return internal_server_error(errormsg=res)
+
+                fdw_data = res['rows'][0]
+
+                for key in ['fsrvacl']:
+                    if key in data and data[key] is not None:
+                        data[key] = parse_priv_to_db(data[key])
+
+                sql = render_template("/".join([self.template_path, 'create.sql']), data=data, fdwdata=fdw_data,
+                                      conn=self.conn)
+                sql += "\n"
+            return sql
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def sql(self, gid, sid, did, fid, fsid):
+        """
+        This function will generate sql for sql panel
+        Parameters:
+            gid
+            - Group ID
+            sid
+            - Server ID
+            data
+            - Data received from client
+            did
+            - Database ID
+            fid
+            - Foreign data wrapper ID
+            fsid
+            - Foreign server ID
+        """
+        sql = render_template("/".join([self.template_path, 'properties.sql']), fsid=fsid, conn=self.conn)
+        status, res = self.conn.execute_dict(sql)
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        if res['rows'][0]['fsrvoptions'] is not None:
+            res['rows'][0]['fsrvoptions'] = self.tokenizeOptions(res['rows'][0]['fsrvoptions'])
+
+        sql = render_template("/".join([self.template_path, 'acl.sql']), fsid=fsid)
+        status, fs_rv_acl_res = self.conn.execute_dict(sql)
+        if not status:
+            return internal_server_error(errormsg=fs_rv_acl_res)
+
+        for row in fs_rv_acl_res['rows']:
+            privilege = parse_priv_from_db(row)
+            if row['deftype'] in res['rows'][0]:
+                res['rows'][0][row['deftype']].append(privilege)
+            else:
+                res['rows'][0][row['deftype']] = [privilege]
+
+        # To format privileges
+        if 'fsrvacl' in res['rows'][0]:
+            res['rows'][0]['fsrvacl'] = parse_priv_to_db(res['rows'][0]['fsrvacl'])
+
+        sql = render_template("/".join([self.template_path, 'properties.sql']), fdwid=fid, conn=self.conn)
+        status, res1 = self.conn.execute_dict(sql)
+        if not status:
+            return internal_server_error(errormsg=res1)
+
+        fdw_data = res1['rows'][0]
+
+        sql = ''
+        sql = render_template("/".join([self.template_path, 'create.sql']), data=res['rows'][0], fdwdata=fdw_data,
+                              conn=self.conn)
+        sql += "\n"
+
+        sql_header = """
+-- Foreign Server: {0}
+
+-- DROP SERVER {0}
+
+""".format(res['rows'][0]['name'])
+
+        sql = sql_header + sql
+
+        return ajax_response(response=sql)
+
+ForeignServerView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/static/img/coll-foreign_server.png b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/static/img/coll-foreign_server.png
new file mode 100644
index 0000000000000000000000000000000000000000..c1071768f4d2ed9797585b8725bfce1d3dbfafab
GIT binary patch
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/static/img/foreign_server.png b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/static/img/foreign_server.png
new file mode 100644
index 0000000000000000000000000000000000000000..dda392a2280c994f48d89e3ed67bbfcbe14ba045
GIT binary patch
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/js/foreign_servers.js b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/js/foreign_servers.js
new file mode 100644
index 0000000..2754a03
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/js/foreign_servers.js
@@ -0,0 +1,140 @@
+define(
+        ['jquery', 'underscore', 'underscore.string', 'pgadmin', 'pgadmin.browser', 'alertify', 'pgadmin.browser.collection',
+        'pgadmin.browser.server.privilege'],
+function($, _, S, pgAdmin, pgBrowser, alertify) {
+
+    var OptionsModel = pgAdmin.Browser.Node.Model.extend({
+        defaults: {
+          fsrvoption: undefined,
+          fsrvvalue: undefined
+        },
+        schema: [
+          {id: 'fsrvoption', label:'Options', type:'text', group: null, editable: true},
+          {id: 'fsrvvalue', label:'Value', type: 'text', group:null, extraHeaderClasses: 'cellwidth-40', editable: true},
+        ],
+        validate: function() {
+          if (_.isUndefined(this.get('fsrvvalue')) ||
+            _.isNull(this.get('fsrvvalue')) ||
+            String(this.get('fsrvvalue')).replace(/^\s+|\s+$/g, '') == '') {
+            var msg = 'Please enter some value!';
+            this.errorModel.set('fsrvvalue', msg);
+            return msg;
+          } else {
+            this.errorModel.unset('fsrvvalue');
+          }
+          return null;
+        }
+    });
+
+  if (!pgBrowser.Nodes['coll-foreign_server']) {
+    var foreign_data_wrappers = pgAdmin.Browser.Nodes['coll-foreign_server'] =
+      pgAdmin.Browser.Collection.extend({
+        node: 'foreign_server',
+        label: '{{ _('Foreign Servers') }}',
+        type: 'coll-foreign_server',
+        columns: ['name','fsrvoid','fsrvowner','description']
+      });
+  };
+
+  if (!pgBrowser.Nodes['foreign_server']) {
+    pgAdmin.Browser.Nodes['foreign_server'] = pgAdmin.Browser.Node.extend({
+      parent_type: 'foreign_data_wrapper',
+      type: 'foreign_server',
+      label: '{{ _('Foreign Server') }}',
+      hasSQL:  true,
+      canDrop: true,
+      canDropCascade: true,
+      Init: function() {
+        /* Avoid mulitple registration of menus */
+        if (this.initialized)
+            return;
+
+        this.initialized = true;
+
+        pgBrowser.add_menus([{
+          name: 'create_foreign_server_on_coll', node: 'coll-foreign_server', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('Foreign Server...') }}',
+          icon: 'wcTabIcon pg-icon-foreign_server', data: {action: 'create'}
+        },{
+          name: 'create_foreign_server', node: 'foreign_server', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('Foreign Server...') }}',
+          icon: 'wcTabIcon pg-icon-foreign_server', data: {action: 'create'}
+        },{
+          name: 'create_foreign_server', node: 'foreign_data_wrapper', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('Foreign Server...') }}',
+          icon: 'wcTabIcon pg-icon-foreign_server', data: {action: 'create'}
+        }
+        ]);
+      },
+      model: pgAdmin.Browser.Node.Model.extend({
+        defaults: {
+          name: undefined,
+          fsrvtype: undefined,
+          fsrvversion: undefined,
+          fsrvvalue: undefined,
+          fsrvoptions: [],
+          fsrvowner: undefined,
+          description: undefined,
+          fsrvacl: []
+        },
+        schema: [{
+          id: 'name', label: '{{ _('Name') }}', cell: 'string',
+          type: 'text', disabled: function(m) {
+            if (this.mode == 'edit' && this.node_info.server.version < 90200) {
+              return true;
+            }
+            else
+              return false;
+          }
+        },{
+          id: 'fsrvid', label:'{{ _('Oid') }}', cell: 'string',
+          type: 'text', disabled: true
+        },{
+          id: 'fsrvowner', label:'{{ _('Owner') }}', type: 'text',
+          control: Backform.NodeListByNameControl, node: 'role',
+          mode: ['edit', 'create', 'properties'], select2: { allowClear: false }
+        },{
+          id: 'fsrvtype', label:'{{ _('Type') }}', cell: 'string',
+          group: 'Definition', type: 'text', mode: ['edit','create','properties'], disabled: function(m) {
+            return !m.isNew();
+          }
+        },{
+          id: 'fsrvversion', label:'{{ _('Version') }}', cell: 'string',
+          group: 'Definition', type: 'text'
+        },{
+          id: 'description', label:'{{ _('Comment') }}', cell: 'string',
+          type: 'multiline'
+        },{
+          id: 'fsrvoptions', label: 'Options', type: 'collection', group: "Options",
+          model: OptionsModel, control: 'unique-col-collection', mode: ['edit', 'create', 'properties'],
+          canAdd: true, canDelete: true, uniqueCol : ['fsrvoption'],
+          columns: ['fsrvoption','fsrvvalue']
+         },{
+            id: 'fsrvacl', label: 'Privileges', type: 'collection', group: "Privileges",
+            model: pgAdmin.Browser.Node.PrivilegeRoleModel.extend({privileges: ['U']}), control: 'unique-col-collection',
+            mode: ['properties', 'edit', 'create'], canAdd: true, canDelete: true, uniqueCol : ['grantee']
+         }
+        ],
+        validate: function() {
+          var name = this.get('name');
+
+          if (_.isUndefined(name) || _.isNull(name) ||
+            String(name).replace(/^\s+|\s+$/g, '') == '') {
+            var msg = '{{ _('Name can not be empty!') }}';
+            this.errorModel.set('name', msg);
+            return msg;
+          } else {
+            this.errorModel.unset('name');
+          }
+          return null;
+        }
+      })
+  });
+
+  }
+
+  return pgBrowser.Nodes['coll-foreign_server'];
+});
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.1_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.1_plus/acl.sql
new file mode 100644
index 0000000..6d8ae08
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.1_plus/acl.sql
@@ -0,0 +1,27 @@
+SELECT 'fsrvacl' 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 'USAGE' THEN 'U'
+		ELSE 'UNKNOWN'
+		END AS privilege_type
+	FROM
+		(SELECT srvacl FROM pg_foreign_server fsrv
+		    LEFT OUTER JOIN pg_shdescription descr ON (
+			fsrv.oid=descr.objoid AND descr.classoid='pg_foreign_server'::regclass)
+{% if fsid %}
+  WHERE fsrv.oid = {{ fsid|qtLiteral }}::OID
+{% endif %}
+		) 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(srvacl) as d FROM pg_foreign_server fsrv1
+                {% if fsid %}
+                        WHERE fsrv1.oid = {{ fsid|qtLiteral }}::OID ) a
+                {% endif %}
+                ) 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
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.1_plus/create.sql
new file mode 100644
index 0000000..cffa47b
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.1_plus/create.sql
@@ -0,0 +1,42 @@
+{# ============= Create foreign server ============= #}
+{% import 'macros/privilege.macros' as PRIVILEGE %}
+{% if data %}
+CREATE SERVER {{ conn|qtIdent(data.name) }}{% if data.fsrvtype %}
+
+    TYPE {{ data.fsrvtype|qtLiteral }}{% endif %}{% if data.fsrvversion %}
+
+    VERSION {{ data.fsrvversion|qtLiteral }}{%-endif %}{% if fdwdata %}
+
+    FOREIGN DATA WRAPPER {{ conn|qtIdent(fdwdata.name) }}{% endif %}{% if data.fsrvoptions %}
+
+{% set addAlter = "False" %}
+{% for variable in data.fsrvoptions %}
+{% if variable.fsrvoption and variable.fsrvoption != '' %}
+{% if addAlter == "False" %}
+    OPTIONS ({% set addAlter = "True" %}{% endif %}
+{{ conn|qtIdent(variable.fsrvoption) }} {{variable.fsrvvalue|qtLiteral}}{% if not loop.last %},{% else %}){% endif %}
+{% endif %}
+{% endfor %}
+{% endif %}{% if data %};{% endif %}
+
+
+{# ============= Set the owner for foreign server ============= #}
+{% if data.fsrvowner %}
+ALTER SERVER {{ conn|qtIdent(data.name) }}
+    OWNER TO {{ conn|qtIdent(data.fsrvowner) }};
+{% endif %}
+
+{# ============= Set the comment for foreign server ============= #}
+{% if data.description %}
+COMMENT ON SERVER {{ conn|qtIdent(data.name) }}
+    IS {{ data.description|qtLiteral }};
+{% endif %}
+
+{# ============= Set the ACL for foreign server ============= #}
+{% if data.fsrvacl %}
+{% for priv in data.fsrvacl %}
+{{ PRIVILEGE.APPLY(conn, 'FOREIGN SERVER', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}
+{% endfor %}
+{% endif %}
+
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.1_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.1_plus/delete.sql
new file mode 100644
index 0000000..ce89201
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.1_plus/delete.sql
@@ -0,0 +1,9 @@
+{# ============= Give foreign server name from foreign server id ============= #}
+{% if fsid %}
+SELECT srvname as name FROM pg_foreign_server srv LEFT OUTER JOIN pg_foreign_data_wrapper fdw on fdw.oid=srvfdw
+WHERE srv.oid={{fsid}}::int;
+{% endif %}
+{# ============= Delete/Drop cascade foreign server ============= #}
+{% if name %}
+DROP SERVER {{ conn|qtIdent(name) }} {% if cascade %} CASCADE {% endif %};
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.1_plus/properties.sql
new file mode 100644
index 0000000..2033ef2
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.1_plus/properties.sql
@@ -0,0 +1,26 @@
+{# ============= Give all the properties of foreign server ============= #}
+{% if fdwid %}
+SELECT fdw.oid as fdwoid, fdwname as name
+FROM pg_foreign_data_wrapper fdw
+LEFT OUTER JOIN pg_description des ON (des.objoid=fdw.oid AND des.objsubid=0 AND des.classoid='pg_foreign_data_wrapper'::regclass)
+WHERE fdw.oid={{fdwid}}::int
+{% else %}
+SELECT srv.oid as fsrvid, srvname as name, srvtype as fsrvtype, srvversion as fsrvversion, fdw.fdwname as fdwname, description,
+array_to_string(srvoptions, ',') AS fsrvoptions,
+pg_get_userbyid(srvowner) as fsrvowner
+FROM pg_foreign_server srv
+LEFT OUTER JOIN pg_foreign_data_wrapper fdw on fdw.oid=srvfdw
+LEFT OUTER JOIN pg_description des ON (des.objoid=srv.oid AND des.objsubid=0 AND des.classoid='pg_foreign_server'::regclass)
+{% if data and fdwdata %}
+WHERE fdw.fdwname = {{ fdwdata.name|qtLiteral }}::text and srvname = {{ data.name|qtLiteral }}::text
+{% elif fdwdata %}
+WHERE fdw.fdwname = {{fdwdata.name|qtLiteral}}::text
+{% endif %}
+{% if fid %}
+WHERE srvfdw={{fid}}::int
+{% endif %}
+{% if fsid %}
+WHERE srv.oid={{fsid}}::int
+{% endif %}
+ORDER BY srvname;
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.1_plus/update.sql
new file mode 100644
index 0000000..319b0a4
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.1_plus/update.sql
@@ -0,0 +1,82 @@
+{% import 'macros/privilege.macros' as PRIVILEGE %}
+{% if data %}
+{# ============= Update foreign server name ============= #}
+{% if data.name != o_data.name %}
+ALTER SERVER {{ conn|qtIdent(o_data.name) }}
+    RENAME TO {{ conn|qtIdent(data.name) }};
+
+{% endif %}
+{# ============= Update foreign server owner ============= #}
+{% if data.fsrvowner and data.fsrvowner != o_data.fsrvowner %}
+ALTER SERVER {{ conn|qtIdent(data.name) }}
+    OWNER TO {{ conn|qtIdent(data.fsrvowner) }};
+
+{% endif %}
+{# ============= Update foreign server version ============= #}
+{% if data.fsrvversion and data.fsrvversion != o_data.fsrvversion %}
+ALTER SERVER {{ conn|qtIdent(data.name) }}
+    VERSION {{ data.fsrvversion|qtLiteral }};
+
+{% endif %}
+{# ============= Update foreign server comments ============= #}
+{% if data.description and data.description != o_data.description %}
+COMMENT ON SERVER {{ conn|qtIdent(data.name) }}
+    IS {{ data.description|qtLiteral }};
+
+{% endif %}
+{# ============= Update foreign server options and values ============= #}
+{% if data.fsrvoptions and data.fsrvoptions.added %}
+{% set addAlter = "False" %}
+{% for variable in data.fsrvoptions.added %}
+{% if variable.fsrvoption and variable.fsrvoption != '' %}
+{% if addAlter == "False" %}
+ALTER SERVER {{ conn|qtIdent(data.name) }}
+    OPTIONS ({% set addAlter = "True" %}{%endif%}
+ADD {{ conn|qtIdent(variable.fsrvoption) }} {{variable.fsrvvalue|qtLiteral}}{% if not loop.last %},{% else %});{% endif %}
+{% endif %}
+{% endfor %}
+{% endif %}
+{% if data.fsrvoptions and data.fsrvoptions.changed %}
+{% set addAlter = "False" %}
+{% for variable in data.fsrvoptions.changed %}
+{% if variable.fsrvoption and variable.fsrvoption != '' %}
+{% if addAlter == "False" %}
+ALTER SERVER {{ conn|qtIdent(data.name) }}
+    OPTIONS ({% set addAlter = "True" %}{%endif%}
+ADD {{conn|qtIdent(variable.fsrvoption)}} {{variable.fsrvvalue|qtLiteral}}{% if not loop.last %},{% else %});{% endif %}
+{% endif %}
+{% endfor %}
+{% endif %}
+{% if data.fsrvoptions and data.fsrvoptions.deleted %}
+{% set addAlter = "False" %}
+{% for variable in data.fsrvoptions.deleted %}
+{% if variable.fsrvoption and variable.fsrvoption != '' %}
+{% if addAlter == "False" %}
+ALTER SERVER {{ conn|qtIdent(data.name) }}
+    OPTIONS ({% set addAlter = "True" %}{%endif%}
+DROP {{conn|qtIdent(variable.fsrvoption)}}{% if not loop.last %},{% else %});{% endif %}
+{% endif %}
+{% endfor %}
+{% endif %}
+
+{# Change the privileges #}
+{% if data.fsrvacl %}
+{% if 'deleted' in data.fsrvacl %}
+{% for priv in data.fsrvacl.deleted %}
+{{ PRIVILEGE.RESETALL(conn, 'FOREIGN SERVER', priv.grantee, data.name) }}
+{% endfor %}
+{% endif %}
+{% if 'changed' in data.fsrvacl %}
+{% for priv in data.fsrvacl.changed %}
+{{ PRIVILEGE.RESETALL(conn, 'FOREIGN SERVER', priv.grantee, data.name) }}
+{{ PRIVILEGE.APPLY(conn, 'FOREIGN SERVER', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}
+{% endfor %}
+{% endif %}
+{% if 'added' in data.fsrvacl %}
+{% for priv in data.fsrvacl.added %}
+{{ PRIVILEGE.APPLY(conn, 'FOREIGN SERVER', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}
+{% endfor %}
+{% endif %}
+{% endif %}
+
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.3_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.3_plus/acl.sql
new file mode 100644
index 0000000..85dddef
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.3_plus/acl.sql
@@ -0,0 +1,21 @@
+SELECT 'fsrvacl' 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 'USAGE' THEN 'U'
+		ELSE 'UNKNOWN'
+		END AS privilege_type
+	FROM
+		(SELECT srvacl FROM pg_foreign_server fsrv
+		    LEFT OUTER JOIN pg_shdescription descr ON (
+			fsrv.oid=descr.objoid AND descr.classoid='pg_foreign_server'::regclass)
+{% if fsid %}
+  WHERE fsrv.oid = {{ fsid|qtLiteral }}::OID
+{% endif %}
+		) acl,
+		aclexplode(srvacl) 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
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.3_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.3_plus/create.sql
new file mode 100644
index 0000000..cffa47b
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.3_plus/create.sql
@@ -0,0 +1,42 @@
+{# ============= Create foreign server ============= #}
+{% import 'macros/privilege.macros' as PRIVILEGE %}
+{% if data %}
+CREATE SERVER {{ conn|qtIdent(data.name) }}{% if data.fsrvtype %}
+
+    TYPE {{ data.fsrvtype|qtLiteral }}{% endif %}{% if data.fsrvversion %}
+
+    VERSION {{ data.fsrvversion|qtLiteral }}{%-endif %}{% if fdwdata %}
+
+    FOREIGN DATA WRAPPER {{ conn|qtIdent(fdwdata.name) }}{% endif %}{% if data.fsrvoptions %}
+
+{% set addAlter = "False" %}
+{% for variable in data.fsrvoptions %}
+{% if variable.fsrvoption and variable.fsrvoption != '' %}
+{% if addAlter == "False" %}
+    OPTIONS ({% set addAlter = "True" %}{% endif %}
+{{ conn|qtIdent(variable.fsrvoption) }} {{variable.fsrvvalue|qtLiteral}}{% if not loop.last %},{% else %}){% endif %}
+{% endif %}
+{% endfor %}
+{% endif %}{% if data %};{% endif %}
+
+
+{# ============= Set the owner for foreign server ============= #}
+{% if data.fsrvowner %}
+ALTER SERVER {{ conn|qtIdent(data.name) }}
+    OWNER TO {{ conn|qtIdent(data.fsrvowner) }};
+{% endif %}
+
+{# ============= Set the comment for foreign server ============= #}
+{% if data.description %}
+COMMENT ON SERVER {{ conn|qtIdent(data.name) }}
+    IS {{ data.description|qtLiteral }};
+{% endif %}
+
+{# ============= Set the ACL for foreign server ============= #}
+{% if data.fsrvacl %}
+{% for priv in data.fsrvacl %}
+{{ PRIVILEGE.APPLY(conn, 'FOREIGN SERVER', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}
+{% endfor %}
+{% endif %}
+
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.3_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.3_plus/delete.sql
new file mode 100644
index 0000000..ce89201
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.3_plus/delete.sql
@@ -0,0 +1,9 @@
+{# ============= Give foreign server name from foreign server id ============= #}
+{% if fsid %}
+SELECT srvname as name FROM pg_foreign_server srv LEFT OUTER JOIN pg_foreign_data_wrapper fdw on fdw.oid=srvfdw
+WHERE srv.oid={{fsid}}::int;
+{% endif %}
+{# ============= Delete/Drop cascade foreign server ============= #}
+{% if name %}
+DROP SERVER {{ conn|qtIdent(name) }} {% if cascade %} CASCADE {% endif %};
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.3_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.3_plus/properties.sql
new file mode 100644
index 0000000..2033ef2
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.3_plus/properties.sql
@@ -0,0 +1,26 @@
+{# ============= Give all the properties of foreign server ============= #}
+{% if fdwid %}
+SELECT fdw.oid as fdwoid, fdwname as name
+FROM pg_foreign_data_wrapper fdw
+LEFT OUTER JOIN pg_description des ON (des.objoid=fdw.oid AND des.objsubid=0 AND des.classoid='pg_foreign_data_wrapper'::regclass)
+WHERE fdw.oid={{fdwid}}::int
+{% else %}
+SELECT srv.oid as fsrvid, srvname as name, srvtype as fsrvtype, srvversion as fsrvversion, fdw.fdwname as fdwname, description,
+array_to_string(srvoptions, ',') AS fsrvoptions,
+pg_get_userbyid(srvowner) as fsrvowner
+FROM pg_foreign_server srv
+LEFT OUTER JOIN pg_foreign_data_wrapper fdw on fdw.oid=srvfdw
+LEFT OUTER JOIN pg_description des ON (des.objoid=srv.oid AND des.objsubid=0 AND des.classoid='pg_foreign_server'::regclass)
+{% if data and fdwdata %}
+WHERE fdw.fdwname = {{ fdwdata.name|qtLiteral }}::text and srvname = {{ data.name|qtLiteral }}::text
+{% elif fdwdata %}
+WHERE fdw.fdwname = {{fdwdata.name|qtLiteral}}::text
+{% endif %}
+{% if fid %}
+WHERE srvfdw={{fid}}::int
+{% endif %}
+{% if fsid %}
+WHERE srv.oid={{fsid}}::int
+{% endif %}
+ORDER BY srvname;
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.3_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.3_plus/update.sql
new file mode 100644
index 0000000..319b0a4
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.3_plus/update.sql
@@ -0,0 +1,82 @@
+{% import 'macros/privilege.macros' as PRIVILEGE %}
+{% if data %}
+{# ============= Update foreign server name ============= #}
+{% if data.name != o_data.name %}
+ALTER SERVER {{ conn|qtIdent(o_data.name) }}
+    RENAME TO {{ conn|qtIdent(data.name) }};
+
+{% endif %}
+{# ============= Update foreign server owner ============= #}
+{% if data.fsrvowner and data.fsrvowner != o_data.fsrvowner %}
+ALTER SERVER {{ conn|qtIdent(data.name) }}
+    OWNER TO {{ conn|qtIdent(data.fsrvowner) }};
+
+{% endif %}
+{# ============= Update foreign server version ============= #}
+{% if data.fsrvversion and data.fsrvversion != o_data.fsrvversion %}
+ALTER SERVER {{ conn|qtIdent(data.name) }}
+    VERSION {{ data.fsrvversion|qtLiteral }};
+
+{% endif %}
+{# ============= Update foreign server comments ============= #}
+{% if data.description and data.description != o_data.description %}
+COMMENT ON SERVER {{ conn|qtIdent(data.name) }}
+    IS {{ data.description|qtLiteral }};
+
+{% endif %}
+{# ============= Update foreign server options and values ============= #}
+{% if data.fsrvoptions and data.fsrvoptions.added %}
+{% set addAlter = "False" %}
+{% for variable in data.fsrvoptions.added %}
+{% if variable.fsrvoption and variable.fsrvoption != '' %}
+{% if addAlter == "False" %}
+ALTER SERVER {{ conn|qtIdent(data.name) }}
+    OPTIONS ({% set addAlter = "True" %}{%endif%}
+ADD {{ conn|qtIdent(variable.fsrvoption) }} {{variable.fsrvvalue|qtLiteral}}{% if not loop.last %},{% else %});{% endif %}
+{% endif %}
+{% endfor %}
+{% endif %}
+{% if data.fsrvoptions and data.fsrvoptions.changed %}
+{% set addAlter = "False" %}
+{% for variable in data.fsrvoptions.changed %}
+{% if variable.fsrvoption and variable.fsrvoption != '' %}
+{% if addAlter == "False" %}
+ALTER SERVER {{ conn|qtIdent(data.name) }}
+    OPTIONS ({% set addAlter = "True" %}{%endif%}
+ADD {{conn|qtIdent(variable.fsrvoption)}} {{variable.fsrvvalue|qtLiteral}}{% if not loop.last %},{% else %});{% endif %}
+{% endif %}
+{% endfor %}
+{% endif %}
+{% if data.fsrvoptions and data.fsrvoptions.deleted %}
+{% set addAlter = "False" %}
+{% for variable in data.fsrvoptions.deleted %}
+{% if variable.fsrvoption and variable.fsrvoption != '' %}
+{% if addAlter == "False" %}
+ALTER SERVER {{ conn|qtIdent(data.name) }}
+    OPTIONS ({% set addAlter = "True" %}{%endif%}
+DROP {{conn|qtIdent(variable.fsrvoption)}}{% if not loop.last %},{% else %});{% endif %}
+{% endif %}
+{% endfor %}
+{% endif %}
+
+{# Change the privileges #}
+{% if data.fsrvacl %}
+{% if 'deleted' in data.fsrvacl %}
+{% for priv in data.fsrvacl.deleted %}
+{{ PRIVILEGE.RESETALL(conn, 'FOREIGN SERVER', priv.grantee, data.name) }}
+{% endfor %}
+{% endif %}
+{% if 'changed' in data.fsrvacl %}
+{% for priv in data.fsrvacl.changed %}
+{{ PRIVILEGE.RESETALL(conn, 'FOREIGN SERVER', priv.grantee, data.name) }}
+{{ PRIVILEGE.APPLY(conn, 'FOREIGN SERVER', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}
+{% endfor %}
+{% endif %}
+{% if 'added' in data.fsrvacl %}
+{% for priv in data.fsrvacl.added %}
+{{ PRIVILEGE.APPLY(conn, 'FOREIGN SERVER', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}
+{% endfor %}
+{% endif %}
+{% endif %}
+
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/__init__.py
new file mode 100644
index 0000000..2909d29
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/__init__.py
@@ -0,0 +1,571 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+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 NodeView
+from pgadmin.browser.collection import CollectionNodeModule
+import pgadmin.browser.server_groups.servers as servers
+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 UserMappingModule(CollectionNodeModule):
+    NODE_TYPE = 'user_mapping'
+    COLLECTION_LABEL = gettext("User Mappings")
+
+    def __init__(self, *args, **kwargs):
+        self.min_ver = None
+        self.max_ver = None
+
+        super(UserMappingModule, self).__init__(*args, **kwargs)
+
+    def get_nodes(self, gid, sid, did, fid, fsid):
+        """
+        Generate the collection node
+        Parameters:
+            gid
+            - Group ID
+            sid
+            - Server ID
+            did
+            - Database ID
+            fid
+            - Foreign data wrapper ID
+            fsid
+            - Foreign server ID
+        """
+        yield self.generate_browser_collection_node(fsid)
+
+    @property
+    def node_inode(self):
+        """
+        node_inode
+
+        Override this property to make the node as leaf node.
+        """
+        return False
+
+    @property
+    def script_load(self):
+        """
+        Load the module script for user-mapping, when any of the foreign server node is
+        initialized.
+        """
+        return servers.ServerModule.NODE_TYPE
+
+blueprint = UserMappingModule(__name__)
+
+
+class UserMappingView(NodeView):
+    node_type = blueprint.node_type
+
+    parent_ids = [
+            {'type': 'int', 'id': 'gid'},
+            {'type': 'int', 'id': 'sid'},
+            {'type': 'int', 'id': 'did'},
+            {'type': 'int', 'id': 'fid'},
+            {'type': 'int', 'id': 'fsid'}
+            ]
+    ids = [
+            {'type': 'int', 'id': 'umid'}
+            ]
+
+    operations = dict({
+        'obj': [
+            {'get': 'properties', 'delete': 'delete', 'put': 'update'},
+            {'get': 'list', 'post': 'create'}
+        ],
+        'delete': [{
+           'delete': 'delete'
+        }],
+        'nodes': [{'get': 'node'}, {'get': 'nodes'}],
+        'children': [{'get': 'children'}],
+        'sql': [{'get': 'sql'}],
+        'msql': [{'get': 'msql'}, {'get': 'msql'}],
+        'stats': [{'get': 'statistics'}],
+        'dependency': [{'get': 'dependencies'}],
+        'dependent': [{'get': 'dependents'}],
+        'module.js': [{}, {}, {'get': 'module_js'}],
+        'getroles': [{}, {'get': 'getroles'}]
+    })
+
+    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(
+                    "user_mappings/js/user_mappings.js",
+                    _=gettext
+                    ),
+                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(
+                    gettext(
+                            "Connection to the server has been lost!"
+                    )
+                )
+
+            self.template_path = 'user_mappings/sql/9.1_plus'
+
+            ver = self.manager.version
+            # we will set template path for sql scripts
+            if ver >= 90100:
+                self.template_path = 'user_mappings/sql/9.1_plus'
+
+            return f(*args, **kwargs)
+        return wrap
+
+    @check_precondition
+    def list(self, gid, sid, did, fid, fsid):
+        sql = render_template("/".join([self.template_path, 'properties.sql']), fsid=fsid, conn=self.conn)
+        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, fid, fsid):
+        res = []
+        sql = render_template("/".join([self.template_path, 'properties.sql']), fsid=fsid, conn=self.conn)
+        status, r_set = self.conn.execute_2darray(sql)
+
+        if not status:
+            return internal_server_error(errormsg=r_set)
+
+        for row in r_set['rows']:
+            res.append(
+                    self.blueprint.generate_browser_node(
+                        row['um_oid'],
+                        fsid,
+                        row['name'],
+                        icon="icon-user_mapping"
+                    ))
+
+        return make_json_response(
+                data=res,
+                status=200
+                )
+
+    def tokenizeOptions(self, option_value):
+        """
+        This function will tokenize the string stored in database
+        e.g. database store the value as below
+        key1=value1, key2=value2, key3=value3, ....
+        This function will extract key and value from above string
+        Parameters:
+            option_value
+            - key value option/value pair read from database
+        """
+        if option_value is not None:
+            option_str = option_value.split(',')
+            um_options = []
+            for um_option in option_str:
+                k, v = um_option.split('=', 1)
+                um_options.append({'umoption': k,'umvalue': v})
+            return um_options
+
+    @check_precondition
+    def properties(self, gid, sid, did, fid, fsid, umid):
+        sql = render_template("/".join([self.template_path, 'properties.sql']), umid=umid, conn=self.conn)
+        status, res = self.conn.execute_dict(sql)
+
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        if res['rows'][0]['name'] == 'public':
+            res['rows'][0]['name'] = 'PUBLIC'
+
+        if res['rows'][0]['umoptions'] is not None:
+            res['rows'][0]['umoptions'] = self.tokenizeOptions(res['rows'][0]['umoptions'])
+
+        return ajax_response(
+                response=res['rows'][0],
+                status=200
+                )
+
+    @check_precondition
+    def create(self, gid, sid, did, fid, fsid):
+        """
+        This function will creates new user mapping object
+        Parameters:
+            gid
+            - Group ID
+            sid
+            - Server ID
+            did
+            - Database ID
+            fid
+            - Foreign data wrapper ID
+            fsid
+            - Foreign server ID
+        """
+
+        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, 'properties.sql']), fserid=fsid, conn=self.conn)
+            status, res1 = self.conn.execute_dict(sql)
+
+            if not status:
+                return internal_server_error(errormsg=res1)
+
+            fdw_data = res1['rows'][0]
+
+            sql = render_template("/".join([self.template_path, 'create.sql']), data=data, fdwdata=fdw_data,
+                                  conn=self.conn)
+            status, res = self.conn.execute_scalar(sql)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            sql = render_template("/".join([self.template_path, 'properties.sql']), fsid=fsid, data=data,
+                                  conn=self.conn)
+            status, r_set = self.conn.execute_dict(sql)
+            if not status:
+                return internal_server_error(errormsg=r_set)
+
+            for row in r_set['rows']:
+                return jsonify(
+                    node=self.blueprint.generate_browser_node(
+                        row['um_oid'],
+                        fsid,
+                        row['name'],
+                        icon='icon-user_mapping'
+                )
+            )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def update(self, gid, sid, did, fid, fsid, umid):
+        """
+        This function will update user mapping object
+        Parameters:
+            gid
+            - Group ID
+            sid
+            - Server ID
+            did
+            - Database ID
+            fid
+            - Foreign data wrapper ID
+            fsid
+            - Foreign server ID
+            umid
+            - user mapping ID
+        """
+        data = request.form if request.form else json.loads(request.data.decode())
+        sql = self.getSQL(gid, sid, data, did, fid, fsid, umid)
+        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="User Mapping updated",
+                    data={
+                        'id':  umid,
+                        'fsid': fsid,
+                        'fid': fid,
+                        'did': did,
+                        'sid': sid,
+                        'gid': gid
+                    }
+                )
+            else:
+                return make_json_response(
+                    success=1,
+                    info="Nothing to update",
+                    data={
+                        'id':  umid,
+                        'fsid': fsid,
+                        'fid': fid,
+                        'did': did,
+                        'sid': sid,
+                        'gid': gid
+                    }
+                )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def delete(self, gid, sid, did, fid, fsid, umid):
+        """
+        This function will drop the user mapping object
+        Parameters:
+            gid
+            - Group ID
+            sid
+            - Server ID
+            did
+            - Database ID
+            fid
+            - Foreign data wrapper ID
+            fsid
+            - Foreign server ID
+            umid
+            - user mapping ID
+        """
+        if self.cmd == 'delete':
+            # This is a cascade operation
+            cascade = True
+        else:
+            cascade = False
+
+        try:
+            # Get name of foreign server from fsid
+            sql = render_template("/".join([self.template_path, 'delete.sql']), fsid=fsid, conn=self.conn)
+            status, name = self.conn.execute_scalar(sql)
+            if not status:
+                return internal_server_error(errormsg=name)
+
+            sql = render_template("/".join([self.template_path, 'properties.sql']), umid=umid, conn=self.conn)
+            status, res = self.conn.execute_dict(sql)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            data = res['rows'][0]
+
+            # drop user mapping
+            sql = render_template("/".join([self.template_path, 'delete.sql']), data=data, name=name, 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("User Mapping dropped"),
+                data={
+                    'id': umid,
+                    'fsid': fsid,
+                    'fid': fid,
+                    'did': did,
+                    'sid': sid,
+                    'gid': gid,
+                }
+            )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def msql(self, gid, sid, did, fid, fsid, umid=None):
+        """
+        This function to return modified SQL
+        Parameters:
+            gid
+            - Group ID
+            sid
+            - Server ID
+            did
+            - Database ID
+            fid
+            - Foreign data wrapper ID
+            fsid
+            - Foreign server ID
+            umid
+            - user mapping ID
+        """
+        data = {}
+        for k, v in request.args.items():
+            try:
+                data[k] = json.loads(v)
+            except ValueError:
+                data[k] = v
+
+        sql = self.getSQL(gid, sid, data, did, fid, fsid, umid)
+        if sql and sql.strip('\n') and sql.strip(' '):
+            return make_json_response(
+                    data=sql,
+                    status=200
+                    )
+        else:
+            return make_json_response(
+                    data='-- Modified SQL --',
+                    status=200
+                    )
+
+    def getSQL(self, gid, sid, data, did, fid, fsid, umid=None):
+        """
+        This function will generate sql from model data
+        Parameters:
+            gid
+            - Group ID
+            sid
+            - Server ID
+            did
+            - Database ID
+            fid
+            - Foreign data wrapper ID
+            fsid
+            - Foreign server ID
+            umid
+            - user mapping ID
+        """
+        required_args = [
+            'name'
+        ]
+        try:
+            if umid is not None:
+                sql = render_template("/".join([self.template_path, 'properties.sql']), umid=umid, conn=self.conn)
+                status, res = self.conn.execute_dict(sql)
+                if not status:
+                    return internal_server_error(errormsg=res)
+
+                if res['rows'][0]['umoptions'] is not None:
+                    res['rows'][0]['umoptions'] = self.tokenizeOptions(res['rows'][0]['umoptions'])
+
+                old_data = res['rows'][0]
+
+            sql = render_template("/".join([self.template_path, 'properties.sql']), fserid=fsid, conn=self.conn)
+            status, res1 = self.conn.execute_dict(sql)
+            if not status:
+                return internal_server_error(errormsg=res1)
+
+            fdw_data = res1['rows'][0]
+
+            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,
+                                          fdwdata=fdw_data, conn=self.conn)
+                else:
+                    sql = render_template("/".join([self.template_path, 'properties.sql']), fserid=fsid, conn=self.conn)
+                    status, res = self.conn.execute_dict(sql)
+                    if not status:
+                        return internal_server_error(errormsg=res)
+                    fdw_data = res['rows'][0]
+                    sql = render_template("/".join([self.template_path, 'create.sql']), data=data, fdwdata=fdw_data,
+                                          conn=self.conn)
+                    sql += "\n"
+                return sql
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def sql(self, gid, sid, did, fid, fsid, umid):
+        """
+        This function will generate sql for sql panel
+        Parameters:
+            gid
+            - Group ID
+            sid
+            - Server ID
+            did
+            - Database ID
+            fid
+            - Foreign data wrapper ID
+            fsid
+            - Foreign server ID
+            umid
+            - user mapping ID
+        """
+        sql = render_template("/".join([self.template_path, 'properties.sql']), umid=umid, conn=self.conn)
+        status, res = self.conn.execute_dict(sql)
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        if res['rows'][0]['umoptions'] is not None:
+            res['rows'][0]['umoptions'] = self.tokenizeOptions(res['rows'][0]['umoptions'])
+
+        sql = render_template("/".join([self.template_path, 'properties.sql']), fserid=fsid, conn=self.conn)
+        status, res1 = self.conn.execute_dict(sql)
+        if not status:
+            return internal_server_error(errormsg=res1)
+
+        fdw_data = res1['rows'][0]
+
+        sql = ''
+        sql = render_template("/".join([self.template_path, 'create.sql']), data=res['rows'][0], fdwdata=fdw_data,
+                              conn=self.conn)
+        sql += "\n"
+
+        sql_header = """
+-- User Mapping : {0}
+
+-- DROP USER MAPPING FOR {0} SERVER {1}
+
+""".format(res['rows'][0]['name'], fdw_data['name'])
+
+        sql = sql_header + sql
+
+        return ajax_response(response=sql)
+
+    @check_precondition
+    def getroles(self, gid, sid, did,fid, fsid):
+        res=[{'label': '', 'value': '' }]
+        res.append({'label': 'CURRENT_USER', 'value': 'CURRENT_USER'})
+        res.append({'label': 'PUBLIC', 'value': 'PUBLIC'})
+
+        try:
+            sql = render_template("/".join([self.template_path, 'role.sql']), conn=self.conn)
+            status, r_set = self.conn.execute_2darray(sql)
+            if not status:
+                return internal_server_error(errormsg=r_set)
+
+            for row in r_set['rows']:
+                res.append(
+                           { 'label': row['rolname'], 'value': row['rolname'] }
+                        )
+
+            return make_json_response(
+                   data=res,
+                   status=200
+                   )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+
+UserMappingView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/static/img/coll-user_mapping.png b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/static/img/coll-user_mapping.png
new file mode 100644
index 0000000000000000000000000000000000000000..0e68c2b12866ad4b480a41a7d1032a1df34a1f45
GIT binary patch
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/static/img/user_mapping.png b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/static/img/user_mapping.png
new file mode 100644
index 0000000000000000000000000000000000000000..e768c9bfc0b3e55f32f12bd037b7ecd52a9e430f
GIT binary patch
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/templates/user_mappings/js/user_mappings.js b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/templates/user_mappings/js/user_mappings.js
new file mode 100644
index 0000000..fe9401b
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/templates/user_mappings/js/user_mappings.js
@@ -0,0 +1,108 @@
+define(
+        ['jquery', 'underscore', 'underscore.string', 'pgadmin', 'pgadmin.browser', 'alertify', 'pgadmin.browser.collection'],
+function($, _, S, pgAdmin, pgBrowser, alertify) {
+
+    var OptionsModel = pgAdmin.Browser.Node.Model.extend({
+        defaults: {
+          umoption: undefined,
+          umvalue: undefined
+        },
+        schema: [
+          {id: 'umoption', label:'Options', type:'text', group: null, editable: true},
+          {id: 'umvalue', label:'Value', type: 'text', group:null, extraHeaderClasses: 'cellwidth-40', editable: true},
+        ],
+        validate: function() {
+          if (_.isUndefined(this.get('umvalue')) ||
+            _.isNull(this.get('umvalue')) ||
+            String(this.get('umvalue')).replace(/^\s+|\s+$/g, '') == '') {
+            var msg = 'Please enter some value!';
+            this.errorModel.set('umvalue', msg);
+            return msg;
+          } else {
+            this.errorModel.unset('umvalue');
+          }
+          return null;
+        }
+    });
+
+  if (!pgBrowser.Nodes['coll-user_mapping']) {
+    var foreign_data_wrappers = pgAdmin.Browser.Nodes['coll-user_mapping'] =
+      pgAdmin.Browser.Collection.extend({
+        node: 'user_mapping',
+        label: '{{ _('User Mappings') }}',
+        type: 'coll-user_mapping',
+        columns: ['name','um_oid']
+      });
+  };
+
+  if (!pgBrowser.Nodes['user_mapping']) {
+    pgAdmin.Browser.Nodes['user_mapping'] = pgAdmin.Browser.Node.extend({
+      parent_type: 'foreign_server',
+      type: 'user_mapping',
+      label: '{{ _('User Mapping') }}',
+      hasSQL:  true,
+      canDrop: true,
+      canDropCascade: true,
+      Init: function() {
+        /* Avoid mulitple registration of menus */
+        if (this.initialized)
+            return;
+
+        this.initialized = true;
+
+        pgBrowser.add_menus([{
+          name: 'create_user_mapping_on_coll', node: 'coll-user_mapping', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('User Mapping...') }}',
+          icon: 'wcTabIcon pg-icon-user_mapping', data: {action: 'create'}
+        },{
+          name: 'create_user_mapping', node: 'user_mapping', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('User Mapping...') }}',
+          icon: 'wcTabIcon pg-icon-user_mapping', data: {action: 'create'}
+        },{
+          name: 'create_user_mapping', node: 'foreign_server', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('User Mapping...') }}',
+          icon: 'wcTabIcon pg-icon-user_mapping', data: {action: 'create'}
+        }
+        ]);
+      },
+      model: pgAdmin.Browser.Node.Model.extend({
+        defaults: {
+          name: undefined,
+          um_options: []
+        },
+        schema: [{
+          id: 'name', label:'{{ _('User') }}', type: 'text', control: 'node-ajax-options',
+          mode: ['edit', 'create', 'properties'], url:'getroles',
+          disabled: function(m) { return !m.isNew(); }
+        },{
+          id: 'um_oid', label:'{{ _('Oid') }}', cell: 'string',
+          type: 'text', disabled: true
+        },{
+          id: 'umoptions', label: 'Options', type: 'collection', group: "Options",
+          model: OptionsModel, control: 'unique-col-collection', mode: ['create', 'edit', 'properties'],
+          canAdd: true, canDelete: true, uniqueCol : ['umoption']
+        }
+        ],
+        validate: function() {
+          var name = this.get('name');
+
+          if (_.isUndefined(name) || _.isNull(name) ||
+            String(name).replace(/^\s+|\s+$/g, '') == '') {
+            var msg = '{{ _('Name can not be empty!') }}';
+            this.errorModel.set('name', msg);
+            return msg;
+          } else {
+            this.errorModel.unset('name');
+          }
+          return null;
+        }
+      })
+  });
+
+  }
+
+  return pgBrowser.Nodes['coll-user_mapping'];
+});
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/templates/user_mappings/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/templates/user_mappings/sql/9.1_plus/create.sql
new file mode 100644
index 0000000..f467ae4
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/templates/user_mappings/sql/9.1_plus/create.sql
@@ -0,0 +1,13 @@
+{# ============= Create of user mapping for server ============= #}
+{% if data and fdwdata %}
+CREATE USER MAPPING FOR {% if data.name == "CURRENT_USER" or data.name == "PUBLIC" %}{{ data.name }}{% else %}{{ conn|qtIdent(data.name) }}{% endif %} SERVER {{ conn|qtIdent(fdwdata.name) }}{%endif%}{% if data.umoptions %}
+
+{% set addAlter = "False" %}
+{% for variable in data.umoptions %}
+{% if variable.umoption and variable.umoption != '' %}
+{% if addAlter == "False" %}
+    OPTIONS ({% set addAlter = "True" %}{% endif %}
+{{ conn|qtIdent(variable.umoption) }} {{variable.umvalue|qtLiteral}}{% if not loop.last %},{%else%}){% endif %}
+{% endif %}
+{% endfor %}
+{% endif %}{% if data %};{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/templates/user_mappings/sql/9.1_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/templates/user_mappings/sql/9.1_plus/delete.sql
new file mode 100644
index 0000000..099d265
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/templates/user_mappings/sql/9.1_plus/delete.sql
@@ -0,0 +1,9 @@
+{# ============= Get the foreing server name from id ============= #}
+{% if fsid %}
+SELECT srvname as name FROM pg_foreign_server srv LEFT OUTER JOIN pg_foreign_data_wrapper fdw on fdw.oid=srvfdw
+WHERE srv.oid={{fsid}}::int;
+{% endif %}
+{# ============= Drop/Delete cascade user mapping ============= #}
+{% if name and data %}
+DROP USER MAPPING FOR  {{ conn|qtIdent(data.name) }} SERVER {{ conn|qtIdent(name) }}
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/templates/user_mappings/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/templates/user_mappings/sql/9.1_plus/properties.sql
new file mode 100644
index 0000000..59f5b41
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/templates/user_mappings/sql/9.1_plus/properties.sql
@@ -0,0 +1,23 @@
+{# ============= Get the properties of user mapping ============= #}
+{% if fserid %}
+SELECT srv.oid as fsrvid, srvname as name
+FROM pg_foreign_server srv
+LEFT OUTER JOIN pg_description des ON (des.objoid=srv.oid AND des.objsubid=0 AND des.classoid='pg_foreign_server'::regclass)
+WHERE srv.oid = {{fserid}}::int
+{% endif %}
+{% if fsid or umid or fdwdata or data %}
+WITH umapData AS
+(
+SELECT u.oid AS um_oid, CASE WHEN u.umuser = 0::oid THEN 'public'::name ELSE a.rolname END AS name,
+array_to_string(u.umoptions, ',') AS umoptions FROM pg_user_mapping u
+LEFT JOIN pg_authid a ON a.oid = u.umuser {% if fsid %} WHERE u.umserver = {{fsid}}::int {% endif %} {% if umid %} WHERE u.oid= {{umid}}::int {% endif %}
+)
+select * from umapData
+{% if data %}
+WHERE {% if data.name == "CURRENT_USER" %} name = {{data.name}} {% elif data.name == "PUBLIC" %} name = {{data.name.lower()|qtLiteral}} {% else %} name = {{data.name|qtLiteral}} {% endif %}
+{% endif %}
+{% if fdwdata %}
+WHERE fdw.fdwname = {{fdwdata.name|qtLiteral}}::text
+{% endif %}
+ORDER BY 2;
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/templates/user_mappings/sql/9.1_plus/role.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/templates/user_mappings/sql/9.1_plus/role.sql
new file mode 100644
index 0000000..12be482
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/templates/user_mappings/sql/9.1_plus/role.sql
@@ -0,0 +1,2 @@
+{# ============= Get list of roles from database server ============= #}
+SELECT rolname FROM pg_roles ORDER BY rolname;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/templates/user_mappings/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/templates/user_mappings/sql/9.1_plus/update.sql
new file mode 100644
index 0000000..b255f5e
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/templates/user_mappings/sql/9.1_plus/update.sql
@@ -0,0 +1,34 @@
+{# ============= Update user mapping options and values ============= #}
+{% if o_data.name and data.umoptions and data.umoptions.added and fdwdata %}
+{% set addAlter = "False" %}
+{% for variable in data.umoptions.added %}
+{% if variable.umoption and variable.umoption != '' %}
+{% if addAlter == "False" %}
+ALTER USER MAPPING FOR {{ conn|qtIdent(o_data.name) }} SERVER {{ conn|qtIdent(fdwdata.name) }}
+    OPTIONS ({% set addAlter = "True" %}{% endif %}
+ADD {{ conn|qtIdent(variable.umoption) }} {{variable.umvalue|qtLiteral}}{% if not loop.last %},{% else %});{% endif %}
+{% endif %}
+{% endfor %}
+{% endif %}
+{% if data.umoptions and data.umoptions.changed and fdwdata %}
+{% set addAlter = "False" %}
+{% for variable in data.umoptions.changed %}
+{% if variable.umoption and variable.umoption != '' %}
+{% if addAlter == "False" %}
+ALTER USER MAPPING FOR {{ conn|qtIdent(o_data.name) }} SERVER {{ conn|qtIdent(fdwdata.name) }}
+    OPTIONS ({% set addAlter = "True" %}{%endif%}
+ADD {{conn|qtIdent(variable.umoption)}} {{variable.umvalue|qtLiteral}}{% if not loop.last %},{% else %});{% endif %}
+{%endif%}
+{% endfor %}
+{% endif %}
+{% if data.umoptions and data.umoptions.deleted and fdwdata %}
+{% set addAlter = "False" %}
+{% for variable in data.umoptions.deleted %}
+{% if variable.umoption and variable.umoption != '' %}
+{% if addAlter == "False" %}
+ALTER USER MAPPING FOR {{ conn|qtIdent(o_data.name) }} SERVER {{ conn|qtIdent(fdwdata.name) }}
+    OPTIONS ({% set addAlter = "True" %}{%endif%}
+DROP {{conn|qtIdent(variable.umoption)}}{% if not loop.last %},{% else %});{% endif %}
+{% endif %}
+{% endfor %}
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/static/img/coll-foreign_data_wrapper.png b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/static/img/coll-foreign_data_wrapper.png
new file mode 100644
index 0000000000000000000000000000000000000000..6b1c8543c69448b928acd21032fe50b21f032dd1
GIT binary patch
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/static/img/foreign_data_wrapper.png b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/static/img/foreign_data_wrapper.png
new file mode 100644
index 0000000000000000000000000000000000000000..0cb967671834e280190bbd5777c3ddc0ab07901d
GIT binary patch
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/js/foreign_data_wrappers.js b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/js/foreign_data_wrappers.js
new file mode 100644
index 0000000..8cf7219
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/js/foreign_data_wrappers.js
@@ -0,0 +1,138 @@
+define(
+        ['jquery', 'underscore', 'underscore.string', 'pgadmin', 'pgadmin.browser',
+        'alertify', 'pgadmin.browser.collection',
+        'pgadmin.browser.server.privilege'],
+function($, _, S, pgAdmin, pgBrowser, alertify) {
+
+    var OptionsModel = pgAdmin.Browser.Node.Model.extend({
+        defaults: {
+          fdwoption: undefined,
+          fdwvalue: undefined
+        },
+        schema: [
+          {id: 'fdwoption', label:'Options', type:'text', group: null, editable: true},
+          {id: 'fdwvalue', label:'Value', type: 'text', group:null, extraHeaderClasses: 'cellwidth-40', editable: true},
+        ],
+        validate: function() {
+          if (_.isUndefined(this.get('fdwvalue')) ||
+            _.isNull(this.get('fdwvalue')) ||
+            String(this.get('fdwvalue')).replace(/^\s+|\s+$/g, '') == '') {
+            var msg = 'Please enter some value!';
+            this.errorModel.set('fdwvalue', msg);
+            return msg;
+          } else {
+            this.errorModel.unset('fdwvalue');
+          }
+          return null;
+        }
+    });
+
+  if (!pgBrowser.Nodes['coll-foreign_data_wrapper']) {
+    var foreign_data_wrappers = pgAdmin.Browser.Nodes['coll-foreign_data_wrapper'] =
+      pgAdmin.Browser.Collection.extend({
+        node: 'foreign_data_wrapper',
+        label: '{{ _('Foreign Data Wrappers') }}',
+        type: 'coll-foreign_data_wrapper',
+        columns: ['name','fdwoid','fdwowner','description']
+      });
+  };
+
+  if (!pgBrowser.Nodes['foreign_data_wrapper']) {
+    pgAdmin.Browser.Nodes['foreign_data_wrapper'] = pgAdmin.Browser.Node.extend({
+      parent_type: 'database',
+      type: 'foreign_data_wrapper',
+      label: '{{ _('Foreign Data Wrapper') }}',
+      hasSQL:  true,
+      canDrop: true,
+      canDropCascade: true,
+      Init: function() {
+        /* Avoid mulitple registration of menus */
+        if (this.initialized)
+            return;
+
+        this.initialized = true;
+
+        pgBrowser.add_menus([{
+          name: 'create_foreign_data_wrapper_on_coll', node: 'coll-foreign_data_wrapper', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('Foreign Data Wrapper...') }}',
+          icon: 'wcTabIcon pg-icon-foreign_data_wrapper', data: {action: 'create'}
+        },{
+          name: 'create_foreign_data_wrapper', node: 'foreign_data_wrapper', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('Foreign Data Wrapper...') }}',
+          icon: 'wcTabIcon pg-icon-foreign_data_wrapper', data: {action: 'create'}
+        },{
+          name: 'create_foreign_data_wrapper', node: 'database', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('Foreign Data Wrapper...') }}',
+          icon: 'wcTabIcon pg-icon-foreign_data_wrapper', data: {action: 'create'}
+        }
+        ]);
+      },
+      model: pgAdmin.Browser.Node.Model.extend({
+        defaults: {
+          name: undefined,
+          fdwowner: undefined,
+          comment: undefined,
+          fdwvalue: undefined,
+          fdwhan: undefined,
+          fdwoption: undefined,
+          fdwacl: []
+        },
+        schema: [{
+          id: 'name', label: '{{ _('Name') }}', cell: 'string',
+          type: 'text', disabled: function(m) {
+            if (this.mode == 'edit' && this.node_info.server.version < 90200) {
+              return true;
+            }
+            else
+              return false;
+          }
+        },{
+          id: 'fdwoid', label:'{{ _('Oid') }}', cell: 'string',
+          type: 'text', disabled: true
+        },{
+          id: 'fdwowner', label:'{{ _('Owner') }}', type: 'text',
+          control: Backform.NodeListByNameControl, node: 'role',
+          mode: ['edit', 'create', 'properties'], select2: { allowClear: false }
+        },{
+          id: 'fdwhan', label:'{{ _('Handler') }}', type: 'text', control: 'node-ajax-options',
+          group: 'Definition', mode: ['edit', 'create', 'properties'], url:'get_handlers'
+        },{
+          id: 'description', label:'{{ _('Comment') }}', cell: 'string',
+          type: 'multiline'
+        },{
+          id: 'fdwoptions', label: 'Options', type: 'collection', group: "Options",
+          model: OptionsModel, control: 'unique-col-collection', mode: ['edit', 'create', 'properties'],
+          canAdd: true, canDelete: true, uniqueCol : ['fdwoption'],
+          columns: ['fdwoption','fdwvalue']
+        },{
+          id: 'fdwvalue', label:'{{ _('Validator') }}', type: 'text', control: 'node-ajax-options',
+          group: 'Definition', mode: ['edit', 'create', 'properties'], url:'get_validators'
+        },{
+            id: 'fdwacl', label: 'Privileges', type: 'collection', group: "Privileges",
+            model: pgAdmin.Browser.Node.PrivilegeRoleModel.extend({privileges: ['U']}), control: 'unique-col-collection',
+            mode: ['properties', 'edit', 'create'], canAdd: true, canDelete: true, uniqueCol : ['grantee']
+         }
+        ],
+        validate: function() {
+          var name = this.get('name');
+
+          if (_.isUndefined(name) || _.isNull(name) ||
+            String(name).replace(/^\s+|\s+$/g, '') == '') {
+            var msg = '{{ _('Name can not be empty!') }}';
+            this.errorModel.set('name', msg);
+            return msg;
+          } else {
+            this.errorModel.unset('name');
+          }
+          return null;
+        }
+      })
+  });
+
+  }
+
+  return pgBrowser.Nodes['coll-foreign_data_wrapper'];
+});
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/acl.sql
new file mode 100644
index 0000000..9f38827
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/acl.sql
@@ -0,0 +1,27 @@
+SELECT 'fdwacl' 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 'USAGE' THEN 'U'
+		ELSE 'UNKNOWN'
+		END AS privilege_type
+	FROM
+		(SELECT fdwacl FROM pg_foreign_data_wrapper fdw
+		    LEFT OUTER JOIN pg_shdescription descr ON (
+			fdw.oid=descr.objoid AND descr.classoid='pg_foreign_data_wrapper'::regclass)
+{% if fid %}
+  WHERE fdw.oid = {{ fid|qtLiteral }}::OID
+{% endif %}
+		) 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(fdwacl) as d FROM pg_foreign_data_wrapper fdw1
+                {% if fid %}
+                        WHERE fdw1.oid = {{ fid|qtLiteral }}::OID ) a
+                {% endif %}
+                ) 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
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/create.sql
new file mode 100644
index 0000000..231f451
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/create.sql
@@ -0,0 +1,39 @@
+{# ============= Create foreign data wrapper ============= #}
+{% import 'macros/privilege.macros' as PRIVILEGE %}
+{% if data.name %}
+CREATE FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}{% if data.fdwvalue %}
+
+    VALIDATOR {{ conn|qtIdent(data.fdwvalue) }}{%endif%}{% if data.fdwhan %}
+
+    HANDLER {{ conn|qtIdent(data.fdwhan) }}{% endif %}{% if data.fdwoptions %}
+
+{% set addAlter = "False" %}
+{% for variable in data.fdwoptions %}
+{% if variable.fdwoption and variable.fdwoption != '' %}
+{% if addAlter == "False" %}
+    OPTIONS ({% set addAlter = "True" %}{% endif %}
+{{ conn|qtIdent(variable.fdwoption) }} {{variable.fdwvalue|qtLiteral}}{% if not loop.last %},{% else %}){% endif %}
+{% endif %}
+{% endfor %}{% endif %}{%if data %};{%endif%}
+
+
+{# ============= Set the owner for foreign data wrapper ============= #}
+{% if data.fdwowner %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    OWNER TO {{ conn|qtIdent(data.fdwowner) }};
+{% endif %}
+
+{# ============= Comment on of foreign data wrapper object ============= #}
+{% if data.description %}
+COMMENT ON FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    IS {{ data.description|qtLiteral }};
+{% endif %}
+
+{# ============= Create ACL for foreign data wrapper ============= #}
+{% if data.fdwacl %}
+{% for priv in data.fdwacl %}
+{{ PRIVILEGE.APPLY(conn, 'FOREIGN DATA WRAPPER', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}
+{% endfor %}
+{% endif %}
+
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/delete.sql
new file mode 100644
index 0000000..5677c99
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/delete.sql
@@ -0,0 +1,8 @@
+{# ============= Get foreign data wrapper from fid ============= #}
+{% if fid %}
+SELECT fdwname as name from pg_foreign_data_wrapper WHERE oid={{fid}}::int;
+{% endif %}
+{# ============= Delete/Drop cascade foreign data wrapper ============= #}
+{% if name %}
+DROP FOREIGN DATA WRAPPER {{ conn|qtIdent(name) }} {% if cascade %} CASCADE {% endif %};
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/handlers.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/handlers.sql
new file mode 100644
index 0000000..50d27c6
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/handlers.sql
@@ -0,0 +1,2 @@
+{# ============= Get the handlers of foreign data wrapper ============= #}
+SELECT proname as fdwhan FROM pg_proc p JOIN pg_namespace nsp ON nsp.oid=pronamespace WHERE pronargs=0 AND prorettype=3115;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/properties.sql
new file mode 100644
index 0000000..3024a76
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/properties.sql
@@ -0,0 +1,14 @@
+{# ============= Get all the properties of foreign data wrapper ============= #}
+SELECT fdw.oid as fdwoid, fdwname as name, fdwhandler, fdwvalidator, vh.proname as fdwhan, vp.proname as fdwvalue, description,
+           array_to_string(fdwoptions, ',') AS fdwoptions, pg_get_userbyid(fdwowner) as fdwowner
+FROM pg_foreign_data_wrapper fdw
+LEFT OUTER JOIN pg_proc vh on vh.oid=fdwhandler
+LEFT OUTER JOIN pg_proc vp on vp.oid=fdwvalidator
+LEFT OUTER JOIN pg_description des ON (des.objoid=fdw.oid AND des.objsubid=0 AND des.classoid='pg_foreign_data_wrapper'::regclass)
+{% if fid %}
+WHERE fdw.oid={{fid}}::int
+{% endif %}
+{% if fname %}
+WHERE fdw.fdwname={{ fname|qtLiteral }}::text
+{% endif %}
+ORDER BY fdwname
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/update.sql
new file mode 100644
index 0000000..fc76aaa
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/update.sql
@@ -0,0 +1,98 @@
+{% import 'macros/privilege.macros' as PRIVILEGE %}
+{% if data %}
+{# ============= Update foreign data wrapper name ============= #}
+{% if data.name != o_data.name %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(o_data.name) }}
+    RENAME TO {{ conn|qtIdent(data.name) }};
+
+{% endif %}
+{# ============= Update foreign data wrapper owner ============= #}
+{% if data.fdwowner and data.fdwowner != o_data.fdwowner %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    OWNER TO {{ conn|qtIdent(data.fdwowner) }};
+
+{% endif %}
+{# ============= Update foreign data wrapper validator ============= #}
+{% if data.fdwvalue and data.fdwvalue != o_data.fdwvalue %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    VALIDATOR {{ conn|qtIdent(data.fdwvalue) }};
+
+{% endif %}
+{% if data.fdwvalue == '' and data.fdwvalue != o_data.fdwvalue %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    NO VALIDATOR;
+
+{% endif %}
+{# ============= Update foreign data wrapper handler ============= #}
+{% if data.fdwhan and data.fdwhan != o_data.fdwhan %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    HANDLER {{ conn|qtIdent(data.fdwhan) }};
+
+{% endif %}
+{% if data.fdwhan == '' and data.fdwhan != o_data.fdwhan %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    NO HANDLER;
+
+{% endif %}
+{# ============= Update foreign data wrapper comments ============= #}
+{% if data.description and data.description != o_data.description %}
+COMMENT ON FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    IS {{ data.description|qtLiteral }};
+
+{% endif %}
+{# ============= Update foreign data wrapper options and values ============= #}
+{% if data.fdwoptions and data.fdwoptions.added %}
+{% set addAlter = "False" %}
+{% for variable in data.fdwoptions.added %}
+{% if variable.fdwoption and variable.fdwoption != '' %}
+{% if addAlter == "False" %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    OPTIONS ({% set addAlter = "True" %}{% endif %}
+ADD {{ conn|qtIdent(variable.fdwoption) }} {{variable.fdwvalue|qtLiteral}}{% if not loop.last %},{% else %});{% endif %}
+{% endif %}
+{%endfor%}
+{% endif %}
+{% if data.fdwoptions and data.fdwoptions.changed %}
+{% set addAlter = "False" %}
+{% for variable in data.fdwoptions.changed %}
+{% if variable.fdwoption and variable.fdwoption != '' %}
+{% if addAlter == "False" %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    OPTIONS ({% set addAlter = "True" %}{% endif %}
+ADD {{ conn|qtIdent(variable.fdwoption) }} {{variable.fdwvalue|qtLiteral}}{% if not loop.last %},{% else %});{% endif %}
+{% endif %}
+{%endfor%}
+{% endif %}
+{% if data.fdwoptions and data.fdwoptions.deleted %}
+{% set addAlter = "False" %}
+{% for variable in data.fdwoptions.deleted %}
+{% if variable.fdwoption and variable.fdwoption != '' %}
+{% if addAlter == "False" %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    OPTIONS ({% set addAlter = "True" %}{%endif%}
+DROP {{ conn|qtIdent(variable.fdwoption) }}{% if not loop.last %},{% else %});{% endif %}
+{% endif %}
+{% endfor %}
+{% endif %}
+
+{# Change the privileges #}
+{% if data.fdwacl %}
+{% if 'deleted' in data.fdwacl %}
+{% for priv in data.fdwacl.deleted %}
+{{ PRIVILEGE.RESETALL(conn, 'FOREIGN DATA WRAPPER', priv.grantee, data.name) }}
+{% endfor %}
+{% endif %}
+{% if 'changed' in data.fdwacl %}
+{% for priv in data.fdwacl.changed %}
+{{ PRIVILEGE.RESETALL(conn, 'FOREIGN DATA WRAPPER', priv.grantee, data.name) }}
+{{ PRIVILEGE.APPLY(conn, 'FOREIGN DATA WRAPPER', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}
+{% endfor %}
+{% endif %}
+{% if 'added' in data.fdwacl %}
+{% for priv in data.fdwacl.added %}
+{{ PRIVILEGE.APPLY(conn, 'FOREIGN DATA WRAPPER', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}
+{% endfor %}
+{% endif %}
+{% endif %}
+
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/validators.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/validators.sql
new file mode 100644
index 0000000..6f3d019
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/validators.sql
@@ -0,0 +1,2 @@
+{# ============= Get the validators of foreign data wrapper ============= #}
+SELECT proname as fdwvalue FROM pg_proc p JOIN pg_namespace nsp ON nsp.oid=pronamespace WHERE proargtypes[0]=1009 AND proargtypes[1]=26;
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/acl.sql
new file mode 100644
index 0000000..081848b
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/acl.sql
@@ -0,0 +1,21 @@
+SELECT 'fdwacl' 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 'USAGE' THEN 'U'
+		ELSE 'UNKNOWN'
+		END AS privilege_type
+	FROM
+		(SELECT fdwacl FROM pg_foreign_data_wrapper fdw
+		    LEFT OUTER JOIN pg_shdescription descr ON (
+			fdw.oid=descr.objoid AND descr.classoid='pg_foreign_data_wrapper'::regclass)
+{% if fid %}
+  WHERE fdw.oid = {{ fid|qtLiteral }}::OID
+{% endif %}
+		) acl,
+		aclexplode(fdwacl) 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
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/create.sql
new file mode 100644
index 0000000..231f451
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/create.sql
@@ -0,0 +1,39 @@
+{# ============= Create foreign data wrapper ============= #}
+{% import 'macros/privilege.macros' as PRIVILEGE %}
+{% if data.name %}
+CREATE FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}{% if data.fdwvalue %}
+
+    VALIDATOR {{ conn|qtIdent(data.fdwvalue) }}{%endif%}{% if data.fdwhan %}
+
+    HANDLER {{ conn|qtIdent(data.fdwhan) }}{% endif %}{% if data.fdwoptions %}
+
+{% set addAlter = "False" %}
+{% for variable in data.fdwoptions %}
+{% if variable.fdwoption and variable.fdwoption != '' %}
+{% if addAlter == "False" %}
+    OPTIONS ({% set addAlter = "True" %}{% endif %}
+{{ conn|qtIdent(variable.fdwoption) }} {{variable.fdwvalue|qtLiteral}}{% if not loop.last %},{% else %}){% endif %}
+{% endif %}
+{% endfor %}{% endif %}{%if data %};{%endif%}
+
+
+{# ============= Set the owner for foreign data wrapper ============= #}
+{% if data.fdwowner %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    OWNER TO {{ conn|qtIdent(data.fdwowner) }};
+{% endif %}
+
+{# ============= Comment on of foreign data wrapper object ============= #}
+{% if data.description %}
+COMMENT ON FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    IS {{ data.description|qtLiteral }};
+{% endif %}
+
+{# ============= Create ACL for foreign data wrapper ============= #}
+{% if data.fdwacl %}
+{% for priv in data.fdwacl %}
+{{ PRIVILEGE.APPLY(conn, 'FOREIGN DATA WRAPPER', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}
+{% endfor %}
+{% endif %}
+
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/delete.sql
new file mode 100644
index 0000000..5677c99
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/delete.sql
@@ -0,0 +1,8 @@
+{# ============= Get foreign data wrapper from fid ============= #}
+{% if fid %}
+SELECT fdwname as name from pg_foreign_data_wrapper WHERE oid={{fid}}::int;
+{% endif %}
+{# ============= Delete/Drop cascade foreign data wrapper ============= #}
+{% if name %}
+DROP FOREIGN DATA WRAPPER {{ conn|qtIdent(name) }} {% if cascade %} CASCADE {% endif %};
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/handlers.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/handlers.sql
new file mode 100644
index 0000000..50d27c6
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/handlers.sql
@@ -0,0 +1,2 @@
+{# ============= Get the handlers of foreign data wrapper ============= #}
+SELECT proname as fdwhan FROM pg_proc p JOIN pg_namespace nsp ON nsp.oid=pronamespace WHERE pronargs=0 AND prorettype=3115;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/properties.sql
new file mode 100644
index 0000000..3024a76
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/properties.sql
@@ -0,0 +1,14 @@
+{# ============= Get all the properties of foreign data wrapper ============= #}
+SELECT fdw.oid as fdwoid, fdwname as name, fdwhandler, fdwvalidator, vh.proname as fdwhan, vp.proname as fdwvalue, description,
+           array_to_string(fdwoptions, ',') AS fdwoptions, pg_get_userbyid(fdwowner) as fdwowner
+FROM pg_foreign_data_wrapper fdw
+LEFT OUTER JOIN pg_proc vh on vh.oid=fdwhandler
+LEFT OUTER JOIN pg_proc vp on vp.oid=fdwvalidator
+LEFT OUTER JOIN pg_description des ON (des.objoid=fdw.oid AND des.objsubid=0 AND des.classoid='pg_foreign_data_wrapper'::regclass)
+{% if fid %}
+WHERE fdw.oid={{fid}}::int
+{% endif %}
+{% if fname %}
+WHERE fdw.fdwname={{ fname|qtLiteral }}::text
+{% endif %}
+ORDER BY fdwname
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/update.sql
new file mode 100644
index 0000000..fc76aaa
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/update.sql
@@ -0,0 +1,98 @@
+{% import 'macros/privilege.macros' as PRIVILEGE %}
+{% if data %}
+{# ============= Update foreign data wrapper name ============= #}
+{% if data.name != o_data.name %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(o_data.name) }}
+    RENAME TO {{ conn|qtIdent(data.name) }};
+
+{% endif %}
+{# ============= Update foreign data wrapper owner ============= #}
+{% if data.fdwowner and data.fdwowner != o_data.fdwowner %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    OWNER TO {{ conn|qtIdent(data.fdwowner) }};
+
+{% endif %}
+{# ============= Update foreign data wrapper validator ============= #}
+{% if data.fdwvalue and data.fdwvalue != o_data.fdwvalue %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    VALIDATOR {{ conn|qtIdent(data.fdwvalue) }};
+
+{% endif %}
+{% if data.fdwvalue == '' and data.fdwvalue != o_data.fdwvalue %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    NO VALIDATOR;
+
+{% endif %}
+{# ============= Update foreign data wrapper handler ============= #}
+{% if data.fdwhan and data.fdwhan != o_data.fdwhan %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    HANDLER {{ conn|qtIdent(data.fdwhan) }};
+
+{% endif %}
+{% if data.fdwhan == '' and data.fdwhan != o_data.fdwhan %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    NO HANDLER;
+
+{% endif %}
+{# ============= Update foreign data wrapper comments ============= #}
+{% if data.description and data.description != o_data.description %}
+COMMENT ON FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    IS {{ data.description|qtLiteral }};
+
+{% endif %}
+{# ============= Update foreign data wrapper options and values ============= #}
+{% if data.fdwoptions and data.fdwoptions.added %}
+{% set addAlter = "False" %}
+{% for variable in data.fdwoptions.added %}
+{% if variable.fdwoption and variable.fdwoption != '' %}
+{% if addAlter == "False" %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    OPTIONS ({% set addAlter = "True" %}{% endif %}
+ADD {{ conn|qtIdent(variable.fdwoption) }} {{variable.fdwvalue|qtLiteral}}{% if not loop.last %},{% else %});{% endif %}
+{% endif %}
+{%endfor%}
+{% endif %}
+{% if data.fdwoptions and data.fdwoptions.changed %}
+{% set addAlter = "False" %}
+{% for variable in data.fdwoptions.changed %}
+{% if variable.fdwoption and variable.fdwoption != '' %}
+{% if addAlter == "False" %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    OPTIONS ({% set addAlter = "True" %}{% endif %}
+ADD {{ conn|qtIdent(variable.fdwoption) }} {{variable.fdwvalue|qtLiteral}}{% if not loop.last %},{% else %});{% endif %}
+{% endif %}
+{%endfor%}
+{% endif %}
+{% if data.fdwoptions and data.fdwoptions.deleted %}
+{% set addAlter = "False" %}
+{% for variable in data.fdwoptions.deleted %}
+{% if variable.fdwoption and variable.fdwoption != '' %}
+{% if addAlter == "False" %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    OPTIONS ({% set addAlter = "True" %}{%endif%}
+DROP {{ conn|qtIdent(variable.fdwoption) }}{% if not loop.last %},{% else %});{% endif %}
+{% endif %}
+{% endfor %}
+{% endif %}
+
+{# Change the privileges #}
+{% if data.fdwacl %}
+{% if 'deleted' in data.fdwacl %}
+{% for priv in data.fdwacl.deleted %}
+{{ PRIVILEGE.RESETALL(conn, 'FOREIGN DATA WRAPPER', priv.grantee, data.name) }}
+{% endfor %}
+{% endif %}
+{% if 'changed' in data.fdwacl %}
+{% for priv in data.fdwacl.changed %}
+{{ PRIVILEGE.RESETALL(conn, 'FOREIGN DATA WRAPPER', priv.grantee, data.name) }}
+{{ PRIVILEGE.APPLY(conn, 'FOREIGN DATA WRAPPER', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}
+{% endfor %}
+{% endif %}
+{% if 'added' in data.fdwacl %}
+{% for priv in data.fdwacl.added %}
+{{ PRIVILEGE.APPLY(conn, 'FOREIGN DATA WRAPPER', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}
+{% endfor %}
+{% endif %}
+{% endif %}
+
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/validators.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/validators.sql
new file mode 100644
index 0000000..6f3d019
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/validators.sql
@@ -0,0 +1,2 @@
+{# ============= Get the validators of foreign data wrapper ============= #}
+SELECT proname as fdwvalue FROM pg_proc p JOIN pg_namespace nsp ON nsp.oid=pronamespace WHERE proargtypes[0]=1009 AND proargtypes[1]=26;
