public inbox for [email protected]
help / color / mirror / Atom feedFrom: Harshal Dhumal <[email protected]>
To: pgadmin-hackers <[email protected]>
Subject: Patch for index constraint (primary and unique key) [pgadmin4]
Date: Mon, 11 Apr 2016 16:56:56 +0530
Message-ID: <CAFiP3vwEHqMBaFOYj=LR6TxbAU1KK4QaUYtr6Z_NR2NRiQwMsw@mail.gmail.com> (raw)
List-Unsubscribe: <mailto:[email protected]?body=unsub%20pgadmin-hackers>
Hi,
PAF patch for exclusion constraint which takes care both primary and unique
key.
Note: This patch has dependency on Table, Column node and Index constraint.
--
*Harshal Dhumal*
*Software Engineer *
EenterpriseDB <http://www.enterprisedb.com;
--
Sent via pgadmin-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgadmin-hackers
Attachments:
[text/x-patch] index_constraint_11_April_V1.patch (55.1K, 3-index_constraint_11_April_V1.patch)
download | inline diff:
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/__init__.py
new file mode 100644
index 0000000..54b0bfd
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/__init__.py
@@ -0,0 +1,907 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+"""Implements Primary key constraint Node"""
+
+import json
+from flask import render_template, make_response, request, jsonify
+from flask.ext.babel import gettext as _
+from pgadmin.utils.ajax import make_json_response, \
+ make_response as ajax_response, internal_server_error
+from pgadmin.browser.utils import PGChildNodeView
+from pgadmin.utils.ajax import precondition_required
+from pgadmin.utils.driver import get_driver
+from config import PG_DEFAULT_DRIVER
+import pgadmin.browser.server_groups.servers.databases.schemas.tables as table
+from functools import wraps
+from pgadmin.browser.server_groups.servers.databases.schemas.tables.constraints.type \
+ import ConstraintRegistry, ConstraintTypeModule
+
+
+class IndexConstraintModule(ConstraintTypeModule):
+ """
+ class IndexConstraintModule(CollectionNodeModule)
+
+ A module class for Primary key constraint node derived from ConstraintTypeModule.
+
+ Methods:
+ -------
+ * __init__(*args, **kwargs)
+ - Method is used to initialize the PrimaryKeyConstraintModule and it's base module.
+
+ * get_nodes(gid, sid, did)
+ - Method is used to generate the browser collection node.
+
+ * node_inode()
+ - Method is overridden from its base class to make the node as leaf node.
+
+ * script_load()
+ - Load the module script for language, when any of the database node is
+ initialized.
+ """
+
+ NODE_TYPE = 'Index constraint'
+ COLLECTION_LABEL = _('index_constraint')
+
+ def __init__(self, *args, **kwargs):
+ """
+ Method is used to initialize the PrimaryKeyConstraintModule and it's base module.
+
+ Args:
+ *args:
+ **kwargs:
+
+ Returns:
+
+ """
+ self.min_ver = None
+ self.max_ver = None
+ super(IndexConstraintModule, self).__init__(*args, **kwargs)
+
+ def get_nodes(self, gid, sid, did, scid, tid):
+ """
+ Generate the collection node
+ """
+ pass
+
+ @property
+ def node_inode(self):
+ """
+ Override this property to make the node a leaf node.
+
+ Returns: False as this is the leaf node
+ """
+ return False
+
+ @property
+ def script_load(self):
+ """
+ Load the module script for primary_key, when any of the table node is
+ initialized.
+
+ Returns: node type of the server module.
+ """
+ return table.TableModule.NODE_TYPE
+
+
+class PrimaryKeyConstraintModule(IndexConstraintModule):
+ """
+ class PrimaryKeyConstraintModule(IndexConstraintModule)
+
+ A module class for the catalog schema node derived from IndexConstraintModule.
+ """
+
+ NODE_TYPE = 'primary_key'
+ COLLECTION_LABEL = _("Primary key")
+
+
+primary_key_blueprint = PrimaryKeyConstraintModule(__name__)
+
+
+class UniqueConstraintModule(IndexConstraintModule):
+ """
+ class UniqueConstraintModule(IndexConstraintModule)
+
+ A module class for the catalog schema node derived from IndexConstraintModule.
+ """
+
+ NODE_TYPE = 'unique_constraint'
+ COLLECTION_LABEL = _("Unique constraint")
+
+
+unique_constraint_blueprint = UniqueConstraintModule(__name__)
+
+
+class IndexConstraintView(PGChildNodeView):
+ """
+ class PrimaryKeyConstraintView(PGChildNodeView)
+
+ A view class for Primary key constraint node derived from PGChildNodeView. This class is
+ responsible for all the stuff related to view like creating, updating Primary key constraint
+ node, showing properties, showing sql in sql pane.
+
+ Methods:
+ -------
+ * __init__(**kwargs)
+ - Method is used to initialize the PrimaryKeyConstraintView and it's base view.
+
+ * module_js()
+ - This property defines (if javascript) exists for this node.
+ Override this property for your own logic
+
+ * check_precondition()
+ - This function will behave as a decorator which will checks
+ database connection before running view, it will also attaches
+ manager,conn & template_path properties to self
+
+ * list()
+ - This function returns primary key constraint nodes within that
+ collection as http response.
+
+ * get_list()
+ - This function is used to list all the language nodes within that collection
+ and return list of primary key constraint nodes.
+
+ * nodes()
+ - This function returns child node within that collection.
+ Here return all primary key constraint node as http response.
+
+ * get_nodes()
+ - returns all primary key constraint nodes' list.
+
+ * properties()
+ - This function will show the properties of the selected primary key.
+
+ * update()
+ - This function will update the data for the selected primary key.
+
+ * msql()
+ - This function is used to return modified SQL for the selected primary key.
+
+ * get_sql()
+ - This function will generate sql from model data.
+
+ * sql():
+ - This function will generate sql to show it in sql pane for the selected primary key.
+
+ * get_indices():
+ - This function returns indices for current table.
+
+ """
+
+ node_type = 'index_constraint'
+
+ node_label = _('Index constraint')
+
+ parent_ids = [
+ {'type': 'int', 'id': 'gid'},
+ {'type': 'int', 'id': 'sid'},
+ {'type': 'int', 'id': 'did'},
+ {'type': 'int', 'id': 'scid'},
+ {'type': 'int', 'id': 'tid'}
+ ]
+ ids = [{'type': 'int', 'id': 'cid'}
+ ]
+
+ operations = dict({
+ 'obj': [
+ {'get': 'properties', 'delete': 'delete', 'put': 'update'},
+ {'get': 'list', 'post': 'create'}
+ ],
+ 'delete': [{'delete': 'delete'}],
+ 'children': [{'get': 'children'}],
+ 'nodes': [{'get': 'node'}, {'get': 'nodes'}],
+ 'sql': [{'get': 'sql'}],
+ 'msql': [{'get': 'msql'}, {'get': 'msql'}],
+ 'stats': [{'get': 'statistics'}],
+ 'dependency': [{'get': 'dependencies'}],
+ 'dependent': [{'get': 'dependents'}],
+ 'module.js': [{}, {}, {'get': 'module_js'}],
+ 'indices': [{}, {'get': 'get_indices'}]
+ })
+
+ def module_js(self):
+ """
+ This property defines (if javascript) exists for this node.
+ Override this property for your own logic.
+ """
+ return make_response(
+ render_template(
+ "index_constraint/js/index_constraint.js",
+ _=_,
+ node_type=self.node_type,
+ node_label=self.node_label
+ ),
+ 200, {'Content-Type': 'application/x-javascript'}
+ )
+
+ def check_precondition(f):
+ """
+ This function will behave as a decorator which will checks
+ database connection before running view, it will also attaches
+ manager,conn & template_path properties to self
+ """
+ @wraps(f)
+ def wrap(*args, **kwargs):
+ # Here args[0] will hold self & kwargs will hold gid,sid,did
+ self = args[0]
+ self.manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(
+ kwargs['sid']
+ )
+ self.conn = self.manager.connection(did=kwargs['did'])
+
+ # If DB not connected then return error to browser
+ if not self.conn.connected():
+ return precondition_required(
+ _(
+ "Connection to the server has been lost!"
+ )
+ )
+
+ self.template_path = 'index_constraint/sql'
+ # We need parent's name eg table name and schema name
+ SQL = render_template("/".join([self.template_path,
+ 'get_parent.sql']),
+ tid=kwargs['tid'])
+ status, rset = self.conn.execute_2darray(SQL)
+ if not status:
+ return internal_server_error(errormsg=rset)
+
+ for row in rset['rows']:
+ self.schema = row['schema']
+ self.table = row['table']
+ return f(*args, **kwargs)
+
+ return wrap
+
+ def end_transaction(self):
+ SQL = render_template(
+ "/".join([self.template_path, 'end.sql']))
+ # End transaction if any.
+ self.conn.execute_scalar(SQL)
+
+ @check_precondition
+ def properties(self, gid, sid, did, scid, tid, cid=None):
+ """
+ This function is used to list all the primary key
+ nodes within that collection.
+
+ Args:
+ gid: Server Group ID
+ sid: Server ID
+ did: Database ID
+ scid: Schema ID
+ tid: Table ID
+ cid: Primary key constraint ID
+
+ Returns:
+
+ """
+ sql = render_template("/".join([self.template_path, 'properties.sql']),
+ tid=tid,
+ cid=cid,
+ constraint_type= self.constraint_type)
+ status, res = self.conn.execute_dict(sql)
+
+ if not status:
+ return internal_server_error(errormsg=res)
+
+ result = res['rows'][0]
+
+ sql = render_template(
+ "/".join([self.template_path, 'get_constraint_cols.sql']),
+ cid=cid,
+ colcnt=result['indnatts'])
+ status, res = self.conn.execute_dict(sql)
+
+ if not status:
+ return internal_server_error(errormsg=res)
+
+ columns = []
+ for row in res['rows']:
+ columns.append({"column": row['column'].strip('"')})
+
+ result['columns'] = columns
+
+ return ajax_response(
+ response=result,
+ status=200
+ )
+
+ @check_precondition
+ def list(self, gid, sid, did, scid, tid, cid=None):
+ """
+ This function returns all primary keys
+ nodes within that collection as a http response.
+
+ Args:
+ gid: Server Group ID
+ sid: Server ID
+ did: Database ID
+ scid: Schema ID
+ tid: Table ID
+ cid: Primary key constraint ID
+
+ Returns:
+
+ """
+ try:
+ res = self.get_node_list(gid, sid, did, scid, tid, cid)
+ return ajax_response(
+ response=res,
+ status=200
+ )
+ except Exception as e:
+ return internal_server_error(errormsg=str(e))
+
+ @check_precondition
+ def get_node_list(self, gid, sid, did, scid, tid, cid=None):
+ """
+ This function returns all primary keys
+ nodes within that collection as a list.
+
+ Args:
+ gid: Server Group ID
+ sid: Server ID
+ did: Database ID
+ scid: Schema ID
+ tid: Table ID
+ cid: Primary key constraint ID
+
+ Returns:
+
+ """
+ SQL = render_template("/".join([self.template_path, 'properties.sql']),
+ tid=tid,
+ constraint_type= self.constraint_type)
+ status, res = self.conn.execute_dict(SQL)
+
+ return res['rows']
+
+ @check_precondition
+ def nodes(self, gid, sid, did, scid, tid, cid=None):
+ """
+ This function returns all event trigger nodes as a
+ http response.
+
+ Args:
+ gid: Server Group ID
+ sid: Server ID
+ did: Database ID
+ scid: Schema ID
+ tid: Table ID
+ cid: Primary key constraint ID
+
+ Returns:
+
+ """
+ try:
+ res = self.get_nodes(gid, sid, did, scid, tid, cid)
+ return make_json_response(
+ data=res,
+ status=200
+ )
+ except Exception as e:
+ return internal_server_error(errormsg=str(e))
+
+ @check_precondition
+ def get_nodes(self, gid, sid, did, scid, tid, cid=None):
+ """
+ This function returns all event trigger nodes as a list.
+
+ Args:
+ gid: Server Group ID
+ sid: Server ID
+ did: Database ID
+ scid: Schema ID
+ tid: Table ID
+ cid: Primary key constraint ID
+
+ Returns:
+
+ """
+ res = []
+ SQL = render_template("/".join([self.template_path, 'nodes.sql']),
+ tid=tid,
+ constraint_type=self.constraint_type)
+ status, rset = self.conn.execute_2darray(SQL)
+
+ for row in rset['rows']:
+ res.append(
+ self.blueprint.generate_browser_node(
+ row['oid'],
+ tid,
+ row['name'],
+ icon="icon-%s" % self.node_type
+ ))
+ return res
+
+ @check_precondition
+ def create(self, gid, sid, did, scid, tid, cid=None):
+ """
+ This function will create a primary key.
+
+ Args:
+ gid: Server Group ID
+ sid: Server ID
+ did: Database ID
+ scid: Schema ID
+ tid: Table ID
+ cid: Primary key constraint ID
+
+ Returns:
+
+ """
+ required_args = [
+ [u'columns', u'index'] # Either of one should be there.
+ ]
+
+ data = request.form if request.form else json.loads(request.data.decode())
+
+ for arg in required_args:
+ if isinstance(arg, list):
+ for param in arg:
+ if (param in data and
+ (not isinstance(data[param], list) or
+ (isinstance(data[param], list) and
+ len(data[param]) > 0))):
+ break
+ else:
+ return make_json_response(
+ status=400,
+ success=0,
+ errormsg=_(
+ "Couldn't find at least one required parameter (%s)." % str(param)
+ )
+ )
+
+ elif arg not in data:
+ return make_json_response(
+ status=400,
+ success=0,
+ errormsg=_(
+ "Couldn't find the required parameter (%s)." % arg
+ )
+ )
+
+ data['schema'] = self.schema
+ data['table'] = self.table
+ try:
+ if 'name' not in data or data['name'] == "":
+ SQL = render_template(
+ "/".join([self.template_path, 'begin.sql']))
+ # Start transaction.
+ status, res = self.conn.execute_scalar(SQL)
+ if not status:
+ self.end_transaction()
+ return internal_server_error(errormsg=res)
+
+ # The below SQL will execute CREATE DDL only
+ SQL = render_template(
+ "/".join([self.template_path, 'create.sql']),
+ data=data, conn=self.conn,
+ constraint_name=self.constraint_name
+ )
+
+ status, msg = self.conn.execute_scalar(SQL)
+ if not status:
+ self.end_transaction()
+ return internal_server_error(errormsg=msg)
+
+ if 'name' not in data or data['name'] == "":
+ sql = render_template(
+ "/".join([self.template_path,
+ 'get_oid_with_transaction.sql'],
+ ),
+ constraint_type=self.constraint_type,
+ tid=tid)
+
+ status, res = self.conn.execute_dict(sql)
+ if not status:
+ self.end_transaction()
+ return internal_server_error(errormsg=res)
+
+ self.end_transaction()
+
+ data['name'] = res['rows'][0]['name']
+
+ else:
+ sql = render_template("/".join([self.template_path, 'get_oid.sql']),
+ tid=tid,
+ constraint_type=self.constraint_type,
+ name=data['name'])
+ status, res = self.conn.execute_dict(sql)
+ if not status:
+ self.end_transaction()
+ return internal_server_error(errormsg=res)
+
+ sql = render_template("/".join([self.template_path, 'grant.sql']),
+ data=data,
+ conn=self.conn)
+ sql = sql.strip('\n').strip(' ')
+
+ if sql != '':
+ status, result = self.conn.execute_scalar(sql)
+ if not status:
+ self.end_transaction()
+ return internal_server_error(errormsg=result)
+
+ return jsonify(
+ node=self.blueprint.generate_browser_node(
+ res['rows'][0]['oid'],
+ tid,
+ data['name'],
+ icon="icon-%s" % self.node_type
+ )
+ )
+
+ except Exception as e:
+ self.end_transaction()
+ return make_json_response(
+ status=400,
+ success=0,
+ errormsg=e
+ )
+
+ @check_precondition
+ def update(self, gid, sid, did, scid, tid, cid=None):
+ """
+ This function will update the data for the selected
+ primary key.
+
+ Args:
+ gid: Server Group ID
+ sid: Server ID
+ did: Database ID
+ scid: Schema ID
+ tid: Table ID
+ cid: Primary key constraint ID
+
+ Returns:
+
+ """
+ data = request.form if request.form else json.loads(request.data.decode())
+
+ try:
+ data['schema'] = self.schema
+ data['table'] = self.table
+ sql = self.get_sql(data, tid, cid)
+ sql = sql.strip('\n').strip(' ')
+ if sql != "":
+ status, res = self.conn.execute_scalar(sql)
+ if not status:
+ return internal_server_error(errormsg=res)
+
+ sql = render_template("/".join([self.template_path, 'get_oid.sql']),
+ tid=tid,
+ constraint_type=self.constraint_type,
+ name=data['name'])
+ status, res = self.conn.execute_dict(sql)
+ if not status:
+ return internal_server_error(errormsg=res)
+
+ return make_json_response(
+ success=1,
+ info="Constraint updated",
+ data={
+ 'id': cid,
+ 'tid': tid,
+ 'scid': scid,
+ 'sid': sid,
+ 'gid': gid,
+ 'did': did
+ }
+ )
+ else:
+ return make_json_response(
+ success=1,
+ info="Nothing to update",
+ data={
+ 'id': cid,
+ 'tid': tid,
+ 'scid': scid,
+ 'sid': sid,
+ 'gid': gid,
+ 'did': did
+ }
+ )
+
+ except Exception as e:
+ return internal_server_error(errormsg=str(e))
+
+ @check_precondition
+ def delete(self, gid, sid, did, scid, tid, cid=None):
+ """
+ This function will delete an existing primary key.
+
+ Args:
+ gid: Server Group ID
+ sid: Server ID
+ did: Database ID
+ scid: Schema ID
+ tid: Table ID
+ cid: Primary key constraint ID
+
+ Returns:
+
+ """
+ # Below code will decide if it's simple drop or drop with cascade call
+ if self.cmd == 'delete':
+ # This is a cascade operation
+ cascade = True
+ else:
+ cascade = False
+ try:
+ sql = render_template("/".join([self.template_path, 'get_name.sql']),
+ tid=tid,
+ constraint_type = self.constraint_type,
+ cid=cid)
+ status, res = self.conn.execute_dict(sql)
+ if not status:
+ return internal_server_error(errormsg=res)
+
+ data = res['rows'][0]
+ data['schema'] = self.schema
+ data['table'] = self.table
+
+ sql = render_template("/".join([self.template_path, 'delete.sql']),
+ data=data,
+ cascade=cascade)
+ status, res = self.conn.execute_scalar(sql)
+ if not status:
+ return internal_server_error(errormsg=res)
+
+ return make_json_response(
+ success=1,
+ info=_("{0} dropped.".format(self.node_label)),
+ data={
+ 'id': cid,
+ 'sid': sid,
+ 'gid': gid,
+ 'did': did
+ }
+ )
+
+ except Exception as e:
+ return internal_server_error(errormsg=str(e))
+
+ @check_precondition
+ def msql(self, gid, sid, did, scid, tid, cid=None):
+ """
+ This function returns modified SQL for the selected
+ primary key.
+
+ Args:
+ gid: Server Group ID
+ sid: Server ID
+ did: Database ID
+ scid: Schema ID
+ tid: Table ID
+ cid: Primary key constraint ID
+
+ Returns:
+
+ """
+ data = {}
+ for k, v in request.args.items():
+ try:
+ data[k] = json.loads(v)
+ except ValueError:
+ data[k] = v
+
+ data['schema'] = self.schema
+ data['table'] = self.table
+ try:
+ sql = self.get_sql(data, tid, cid)
+ sql = sql.strip('\n').strip(' ')
+
+ return make_json_response(
+ data=sql,
+ status=200
+ )
+
+ except Exception as e:
+ return internal_server_error(errormsg=str(e))
+
+ def get_sql(self, data, tid, cid=None):
+ """
+ This function will generate sql from model data.
+
+ Args:
+ data: Contains the data of the selected primary key constraint.
+ tid: Table ID.
+ cid: Primary key constraint ID
+
+ Returns:
+
+ """
+ if cid is not None:
+ sql = render_template("/".join([self.template_path, 'properties.sql']),
+ tid=tid,
+ cid=cid,
+ constraint_type= self.constraint_type)
+ status, res = self.conn.execute_dict(sql)
+ if not status:
+ return internal_server_error(errormsg=res)
+
+ old_data = res['rows'][0]
+ required_args = [u'name']
+ for arg in required_args:
+ if arg not in data:
+ data[arg] = old_data[arg]
+
+ sql = render_template("/".join([self.template_path, 'update.sql']),
+ data=data,
+ o_data=old_data)
+ else:
+ required_args = [
+ [u'columns', u'index'] # Either of one should be there.
+ ]
+
+ for arg in required_args:
+ if isinstance(arg, list):
+ for param in arg:
+ if (param in data and
+ ((isinstance(data[param], str) and
+ data[param] != "") or
+ (isinstance(data[param], list) and
+ len(data[param]) > 0))):
+ break
+ else:
+ return _('-- definition incomplete')
+
+ elif arg not in data:
+ return _('-- definition incomplete')
+
+ sql = render_template("/".join([self.template_path, 'create.sql']),
+ data=data,
+ conn=self.conn,
+ constraint_name=self.constraint_name)
+ sql += "\n"
+ sql += render_template("/".join([self.template_path, 'grant.sql']),
+ data=data,
+ conn=self.conn)
+
+ return sql
+
+ @check_precondition
+ def sql(self, gid, sid, did, scid, tid, cid=None):
+ """
+ This function generates sql to show in the sql pane for the selected
+ primary key.
+
+ Args:
+ gid: Server Group ID
+ sid: Server ID
+ did: Database ID
+ scid: Schema ID
+ tid: Table ID
+ cid: Primary key constraint ID
+
+ Returns:
+
+ """
+ try:
+ SQL = render_template(
+ "/".join([self.template_path, 'properties.sql']),
+ tid=tid,
+ conn=self.conn,
+ cid=cid,
+ constraint_type=self.constraint_type)
+ status, res = self.conn.execute_dict(SQL)
+ if not status:
+ return internal_server_error(errormsg=res)
+
+ data = res['rows'][0]
+ data['schema'] = self.schema
+ data['table'] = self.table
+
+ sql = render_template(
+ "/".join([self.template_path, 'get_constraint_cols.sql']),
+ cid=cid, colcnt=data['indnatts'])
+
+ status, res = self.conn.execute_dict(sql)
+
+ if not status:
+ return internal_server_error(errormsg=res)
+
+ columns = []
+ for row in res['rows']:
+ columns.append({"column": row['column'].strip('"')})
+
+ data['columns'] = columns
+
+ SQL = render_template(
+ "/".join([self.template_path, 'create.sql']),
+ data=data,
+ constraint_name=self.constraint_name)
+ SQL += "\n"
+ SQL += render_template(
+ "/".join([self.template_path, 'grant.sql']),
+ data=data, conn=self.conn)
+
+ sql_header = "-- Constraint: {0}\n\n-- ".format(data['name'])
+
+ sql_header += render_template(
+ "/".join([self.template_path, 'delete.sql']),
+ data=data)
+ sql_header += "\n"
+
+ SQL = sql_header + SQL
+
+ return ajax_response(response=SQL)
+
+ except Exception as e:
+ return internal_server_error(errormsg=str(e))
+
+ @check_precondition
+ def get_indices(self, gid, sid, did, scid, tid, cid=None):
+ """
+ This function returns indices for current table.
+
+ Args:
+ gid: Server Group ID
+ sid: Server ID
+ did: Database ID
+ scid: Schema ID
+ tid: Table ID
+ cid: Primary key constraint ID
+
+ Returns:
+
+ """
+ res = [{'label': '', 'value': ''}]
+ sql = render_template("/".join([self.template_path,
+ 'get_indices.sql']),
+ tid=tid)
+ status, rest = self.conn.execute_2darray(sql)
+
+ if not status:
+ return internal_server_error(errormsg=rest)
+
+ for row in rest['rows']:
+ res.append(
+ {'label': row['relname'], 'value': row['relname']}
+ )
+ return make_json_response(
+ data=res,
+ status=200
+ )
+
+
+class PrimaryKeyConstraintView(IndexConstraintView):
+ node_type = 'primary_key'
+
+ node_label = _('Primary key')
+
+ constraint_name = "PRIMARY KEY"
+
+ constraint_type = "p"
+
+
+class UniqueConstraintView(IndexConstraintView):
+ node_type = 'unique_constraint'
+
+ node_label = _('Unique constraint')
+
+ constraint_name = "UNIQUE"
+
+ constraint_type = "u"
+
+
+primary_key_constraint = ConstraintRegistry(
+ 'primary_key', PrimaryKeyConstraintModule, PrimaryKeyConstraintView
+ )
+
+unique_constraint = ConstraintRegistry(
+ 'unique_constraint', UniqueConstraintModule, UniqueConstraintView
+ )
+
+PrimaryKeyConstraintView.register_node_view(primary_key_blueprint)
+UniqueConstraintView.register_node_view(unique_constraint_blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/static/img/primary_key.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/static/img/primary_key.png
new file mode 100644
index 0000000000000000000000000000000000000000..b57f59778554c3b0ee1b872a4174cbe631ee64e2
GIT binary patch
literal 443
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbMf<N%)#S0Mf1eD~=McE?xh-aAwO
z?)k2F&$r(_Q+<4;&bQAOzI-_L>D`Vm@3!4NRdR5F#O>qdUq7Aw{C>xWm$N>;n)Uh3
z;xBI(e|bIY^Q(!UUNnAw(e(Yp+IP=)e*Jjj^V^Ldo=^DrV#4P)3vM4z`1*Fitz!|N
zUo?Mt)qC$u?bnY-Kfl}j@%4gFujk!8nS1w4)!Qd4-ac7$_f*mGm0D_V?`Q*^#aI&L
z7tG-B>_!@p!&%@FSq!8-z}W3%wjGcW@9E+gB5^r6VF6b{N>Y-`Gvm!0Hf=0cIJvo?
zsPOZLPmT=s%*?{88RjpTu%Tncj2$gYMC1b;qT2k!{Nfw~JtJL3mox?X#ySUk&+eD!
zaI9ft<CBfGtz|aJUirArf`Q@2TGkzB-UgQgtx_#<jVMV;EJ?LWE=mPb3`Pcq2D*ku
zx(0?JMg~?U##Sb#+6Jap1_txq>8(Q1kei>9nN|tWU|<Q>090*aWnc!;aB6z!8lVOS
MPgg&ebxsLQ07e(akpKVy
literal 0
HcmV?d00001
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/static/img/unique_constraint.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/static/img/unique_constraint.png
new file mode 100644
index 0000000000000000000000000000000000000000..e82857235ed1d5bb351b981c447ec3370d495fa9
GIT binary patch
literal 422
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbK}V}MVHE0AtpdP65|Z{ONGc?&PK
z9lkT?%wyl?6GdCEg|9qcv+MTqD^L55-OJi^HFW8P+MRbYmt2Wha=CWfUF*U_tvl~U
zF1%W|<$g;4`J&}FqUK+(-}In$+k@yiHybuQDqDIhZuaelb&vDr-HMxer)=5dRj1!9
zI{IqDj_1wmp7v~dv0(q3HOJoP31mnB9l=-<<QL4~@a#q!ki%Kv5m^kRJ;2!QWVRiU
z5##CN7$R}Gx6hRCKmd<(eQa7<+K&H>+NGIBA*;;oEjPCQ(Bz!3V!CK3^T!Lkmz5Z{
zJ+895(X7z(qO)VNNwR|esV?<b%bs?wlaJ6nmU+y3!<yT5bHqK~Dx3X_HeV^s{Hn_4
zgbmOh)e_f;l9a@fRIB8oR3OD*WMF8ZYiOivU>IU#U}a)#Wn!vrU}|MxFz=n-DijU5
n`6-!cl@JXEmS7D))h1R3W)KahriZQpYGCkm^>bP0l+XkKGQ6yC
literal 0
HcmV?d00001
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/js/index_constraint.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/js/index_constraint.js
new file mode 100644
index 0000000..ca8f29e
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/js/index_constraint.js
@@ -0,0 +1,297 @@
+define(
+ ['jquery', 'underscore', 'underscore.string', 'pgadmin',
+ 'pgadmin.browser', 'alertify', 'pgadmin.browser.collection'],
+function($, _, S, pgAdmin, pgBrowser, alertify) {
+
+ // Extend the browser's node class for index constraint node
+ if (!pgBrowser.Nodes['{{node_type}}']) {
+ pgAdmin.Browser.Nodes['{{node_type}}'] = pgBrowser.Node.extend({
+ type: '{{node_type}}',
+ label: '{{ node_label }}',
+ collection_type: 'coll-constraints',
+ hasSQL: true,
+ hasDepends: false,
+ parent_type: 'table',
+ canDrop: true,
+ canDropCascade: true,
+ Init: function() {
+ /* Avoid multiple registration of menus */
+ if (this.initialized)
+ return;
+
+ this.initialized = true;
+
+ pgBrowser.add_menus([{
+ name: 'create_{{node_type}}_on_coll', node: 'coll-constraints', module: this,
+ applies: ['object', 'context'], callback: 'show_obj_properties',
+ category: 'create', priority: 4, label: '{{ node_label }}',
+ icon: 'wcTabIcon icon-{{node_type}}', data: {action: 'create', check: true}
+ {% if node_type == 'primary_key'%}
+ ,enable: 'canCreate'
+ {% endif %}
+ }
+ ]);
+ },
+ {% if node_type == 'primary_key'%}
+ canCreate: function(node, item, data) {
+ // There should be only one primary key per table.
+ var children = pgBrowser.tree.children(arguments[1], false),
+ primary_key_found = false;
+
+ _.each(children, function(child){
+ data = pgBrowser.tree.itemData($(child));
+ if (!primary_key_found && data._type == "primary_key") {
+ primary_key_found = true;
+ }
+ });
+
+ return !primary_key_found;
+ },
+ {% endif %}
+ // Define the model for index constraint node
+ model: pgAdmin.Browser.Node.Model.extend({
+ defaults: {
+ name: undefined,
+ oid: undefined,
+ comment: undefined,
+ spcname: "pg_default",
+ index: undefined,
+ fillfactor: undefined,
+ condeferrable: undefined,
+ condeferred: undefined,
+ columns: []
+ },
+
+ // Define the schema for the index constraint node
+ schema: [{
+ id: 'name', label: '{{ _('Name') }}', type: 'text',
+ mode: ['properties', 'create', 'edit']
+ },{
+ id: 'oid', label:'{{ _('OID') }}', cell: 'string',
+ type: 'text' , mode: ['properties']
+ },{
+ id: 'comment', label:'{{ _('Comment') }}', cell: 'string',
+ type: 'multiline', mode: ['properties', 'create', 'edit']
+ },{
+ id: 'columns', label: '{{ _('Columns') }}',
+ type: 'collection', group: '{{ _('Definition') }}', editable:true,
+ canDelete: true, canAdd: true,
+ control: Backform.MultiSelectAjaxControl.extend({
+ formatter: {
+ fromRaw: function (rawData, model) {
+ var res = _.isObject(rawData) ?
+ rawData : JSON.parse(rawData);
+
+ return _.pluck(res, 'column');
+ },
+ toRaw: function (formattedData, model) {
+ return formattedData;
+ }
+ },
+ defaults: _.extend(
+ {},
+ Backform.NodeListByNameControl.prototype.defaults,
+ {
+ select2: {
+ multiple: true,
+ allowClear: true,
+ width: 'style',
+ placeholder: '{{ _('Select the column(s)') }}',
+ }
+ }
+ ),
+ onChange: function(e) {
+ var model = this.model,
+ $el = $(e.target),
+ attrArr = this.field.get("name").split('.'),
+ name = attrArr.shift(),
+ path = attrArr.join('.'),
+ vals = this.getValueFromDOM(),
+ collection = model.get(name),
+ removed = [];
+
+ this.stopListening(this.model, "change:" + name, this.render);
+
+ /*
+ * Iterate through all the values, and find out how many are already
+ * present in the collection.
+ */
+ collection.each(function(m) {
+ var column = m.get('column'),
+ idx = _.indexOf(vals, column);
+
+ if (idx > -1) {
+ vals.splice(idx, 1);
+ } else {
+ removed.push(column);
+ }
+ });
+
+ /*
+ * Adding new values
+ */
+ _.each(vals, function(v) {
+ collection.add({column: v});
+ });
+
+ /*
+ * Removing unwanted!
+ */
+ _.each(removed, function(v) {
+ collection.remove(collection.where({column: v}));
+ });
+
+ this.listenTo(this.model, "change:" + name, this.render);
+ }
+ }),
+ deps: ['index'], node: 'column',
+ model: pgBrowser.Node.Model.extend({
+ defaults: {
+ column: undefined
+ },
+ validate: function() {
+ var columns = this.handler.get('columns');
+ if ((!_.isUndefined(columns) && !_.isNull(columns) && columns.length > 0)) {
+ this.handler.errorModel.unset("columns");
+ this.handler.errorModel.clear();
+ } else {
+ var msg = '{{ _('Please specify column(s).') }}';
+ this.handler.errorModel.set('columns', msg);
+ return msg;
+ }
+ return null;
+ }
+ }),
+ transform : function(data){
+ var res = [];
+ if (data && _.isArray(data)) {
+ _.each(data, function(d) {
+ res.push({label: d.label, value: d.label});
+ })
+ }
+ return res;
+ },
+ select2:{allowClear:false},
+ disabled: function(m) {
+ // We can't update columns of existing index constraint.
+ if (!m.isNew()) {
+ return true;
+ }
+ // Disable if index is selected.
+ var index = m.get('index');
+ if(_.isUndefined(index) || index == '') {
+ return false;
+ } else {
+ var col = m.get('columns');
+ col.reset();
+ return true;
+ }
+ }
+ },{
+ id: 'spcname', label: '{{ _('Tablespace') }}',
+ type: 'text', group: '{{ _('Definition') }}',
+ control: 'node-list-by-name', node: 'tablespace',
+ deps: ['index'],
+ select2:{allowClear:false},
+ filter: function(m) {
+ // Don't show pg_global tablespace in selection.
+ if (m.label == "pg_global") return false;
+ else return true;
+ },
+ disabled: function(m) {
+ // Disable if index is selected.
+ var index = m.get('index');
+ if(_.isUndefined(index) || index == '') {
+ return false;
+ } else {
+ setTimeout(function(){
+ m.set('spcname', '');
+ },10);
+ return true;
+ }
+ }
+ },{
+ id: 'index', label: '{{ _('Index') }}',
+ type: 'text', group: '{{ _('Definition') }}',
+ control: 'node-ajax-options', url:"indices",
+ select2:{allowClear:true},
+ disabled: function(m) {
+ // We can't update index of existing index constraint.
+ return !m.isNew();
+ }
+ },{
+ id: 'fillfactor', label: '{{ _('Fill factor') }}', deps: ['index'],
+ type: 'int', group: '{{ _('Definition') }}', allowNull: true,
+ disabled: function(m) {
+ // Disable if index is selected.
+ var index = m.get('index');
+ if(_.isUndefined(index) || index == '') {
+ return false;
+ } else {
+ setTimeout(function(){
+ m.set('fillfactor', null);
+ },10);
+ return true;
+ }
+ }
+ },{
+ id: 'condeferrable', label: '{{ _('Deferrable') }}',
+ type: 'switch', group: '{{ _('Definition') }}', deps: ['index'],
+ disabled: function(m) {
+ // We can't update condeferrable of existing index constraint.
+ if (!m.isNew()) {
+ return true;
+ }
+ // Disable if index is selected.
+ var index = m.get('index');
+ if(_.isUndefined(index) || index == '') {
+ return false;
+ } else {
+ setTimeout(function(){
+ m.set('condeferrable', false);
+ },10);
+ return true;
+ }
+ }
+ },{
+ id: 'condeferred', label: '{{ _('Deferred') }}',
+ type: 'switch', group: '{{ _('Definition') }}',
+ deps: ['condeferrable'],
+ disabled: function(m) {
+ // We can't update condeferred of existing index constraint.
+ if (!m.isNew()) {
+ return true;
+ }
+ // Disable if condeferred is false or unselected.
+ if(m.get('condeferrable') == true) {
+ return false;
+ } else {
+ setTimeout(function(){
+ m.set('condeferred', false);
+ },10);
+ return true;
+ }
+ }
+ }
+ ],
+ validate: function() {
+ this.errorModel.clear();
+
+ var columns = this.get('columns'),
+ index = this.get('index');
+
+ if ((_.isUndefined(index) || String(index).replace(/^\s+|\s+$/g, '') == '') &&
+ (_.isUndefined(columns) || _.isNull(columns) || columns.length < 1)) {
+ var msg = '{{ _('Please specify columns.') }}';
+ this.errorModel.set('columns', msg);
+ return msg;
+ }
+
+ return null;
+ }
+ })
+ });
+ }
+
+ return pgBrowser.Nodes['{{node_type}}'];
+});
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/begin.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/begin.sql
new file mode 100644
index 0000000..58bfee1
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/begin.sql
@@ -0,0 +1 @@
+BEGIN;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/create.sql
new file mode 100644
index 0000000..61a717e
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/create.sql
@@ -0,0 +1,12 @@
+ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }}
+ ADD{% if data.name %} CONSTRAINT {{ conn|qtIdent(data.name) }}{% endif%} {{constraint_name}} {% if data.index %}USING INDEX {{ conn|qtIdent(data.index) }}{% else %}
+({% for columnobj in data.columns %}{% if loop.index != 1 %}
+, {% endif %}{{ conn|qtIdent(columnobj.column)}}{% endfor %}){% if data.fillfactor %}
+
+ WITH (FILLFACTOR={{data.fillfactor}}){% endif %}{% if data.spcname and data.spcname != "pg_default" %}
+
+ USING INDEX TABLESPACE {{ conn|qtIdent(data.spcname) }}{% endif %}{% endif %}{% if data.condeferrable %}
+
+ DEFERRABLE{% if data.condeferred %}
+ INITIALLY DEFERRED{% endif%}
+{% endif%};
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/delete.sql
new file mode 100644
index 0000000..2096795
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/delete.sql
@@ -0,0 +1,3 @@
+{% if data %}
+ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }} DROP CONSTRAINT {{ conn|qtIdent(data.name) }}{% if cascade%} CASCADE{% endif %};
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/end.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/end.sql
new file mode 100644
index 0000000..92d09d5
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/end.sql
@@ -0,0 +1 @@
+END;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/get_constraint_cols.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/get_constraint_cols.sql
new file mode 100644
index 0000000..4b2fee2
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/get_constraint_cols.sql
@@ -0,0 +1,7 @@
+{% for n in range(colcnt|int) %}
+{% if loop.index != 1 %}
+UNION SELECT pg_get_indexdef({{ cid|string }}, {{ loop.index|string }}, true) AS column
+{% else %}
+SELECT pg_get_indexdef({{ cid|string }} , {{ loop.index|string }} , true) AS column
+{% endif %}
+{% endfor %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/get_indices.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/get_indices.sql
new file mode 100644
index 0000000..b9cab21
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/get_indices.sql
@@ -0,0 +1,3 @@
+SELECT relname FROM pg_class, pg_index
+WHERE pg_class.oid=indexrelid
+AND indrelid={{ tid }}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/get_name.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/get_name.sql
new file mode 100644
index 0000000..a1beafb
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/get_name.sql
@@ -0,0 +1,15 @@
+SELECT cls.relname as name
+FROM pg_index idx
+JOIN pg_class cls ON cls.oid=indexrelid
+LEFT JOIN pg_depend dep ON (dep.classid = cls.tableoid AND
+ dep.objid = cls.oid AND
+ dep.refobjsubid = '0'
+ AND dep.refclassid=(SELECT oid
+ FROM pg_class
+ WHERE relname='pg_constraint') AND
+ dep.deptype='i')
+LEFT OUTER JOIN pg_constraint con ON (con.tableoid = dep.refclassid AND
+ con.oid = dep.refobjid)
+WHERE indrelid = {{tid}}::oid
+AND contype='{{constraint_type}}'
+AND cls.oid = {{cid}}::oid;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/get_oid.sql
new file mode 100644
index 0000000..861ff50
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/get_oid.sql
@@ -0,0 +1,4 @@
+SELECT ct.conindid as oid
+FROM pg_constraint ct
+WHERE contype='{{constraint_type}}' AND
+ct.conname = {{ name|qtLiteral }};
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/get_oid_with_transaction.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/get_oid_with_transaction.sql
new file mode 100644
index 0000000..9ad8020
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/get_oid_with_transaction.sql
@@ -0,0 +1,5 @@
+SELECT ct.conindid as oid,
+ ct.conname as name
+FROM pg_constraint ct
+WHERE contype='{{constraint_type}}' AND
+ conrelid = {{tid}}::oid LIMIT 1;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/get_parent.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/get_parent.sql
new file mode 100644
index 0000000..a652857
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/get_parent.sql
@@ -0,0 +1,7 @@
+SELECT nsp.nspname AS schema,
+ rel.relname AS table
+FROM
+ pg_class rel
+JOIN pg_namespace nsp
+ON rel.relnamespace = nsp.oid::int
+WHERE rel.oid = {{tid}}::int
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/grant.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/grant.sql
new file mode 100644
index 0000000..0fb0ea5
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/grant.sql
@@ -0,0 +1,4 @@
+{% if data.comment %}
+COMMENT ON CONSTRAINT {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(data.schema, data.table) }}
+ IS {{ data.comment|qtLiteral }};
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/nodes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/nodes.sql
new file mode 100644
index 0000000..ed96b44
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/nodes.sql
@@ -0,0 +1,14 @@
+SELECT cls.oid, cls.relname as name
+FROM pg_index idx
+JOIN pg_class cls ON cls.oid=indexrelid
+LEFT JOIN pg_depend dep ON (dep.classid = cls.tableoid AND
+ dep.objid = cls.oid AND
+ dep.refobjsubid = '0' AND
+ dep.refclassid=(SELECT oid
+ FROM pg_class
+ WHERE relname='pg_constraint') AND
+ dep.deptype='i')
+LEFT OUTER JOIN pg_constraint con ON (con.tableoid = dep.refclassid AND
+ con.oid = dep.refobjid)
+WHERE indrelid = {{tid}}::oid
+AND contype='{{constraint_type}}'
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/properties.sql
new file mode 100644
index 0000000..0eabdd7
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/properties.sql
@@ -0,0 +1,29 @@
+SELECT cls.oid,
+ cls.relname as name,
+ indnatts,
+ COALESCE(spcname, 'pg_default') as spcname,
+ CASE contype
+ WHEN 'p' THEN desp.description
+ WHEN 'u' THEN desp.description
+ WHEN 'x' THEN desp.description
+ ELSE des.description
+ END AS comment,
+ condeferrable,
+ condeferred,
+ substring(array_to_string(cls.reloptions, ',') from 'fillfactor=([0-9]*)') AS fillfactor
+FROM pg_index idx
+JOIN pg_class cls ON cls.oid=indexrelid
+JOIN pg_class tab ON tab.oid=indrelid
+LEFT OUTER JOIN pg_tablespace ta on ta.oid=cls.reltablespace
+JOIN pg_namespace n ON n.oid=tab.relnamespace
+JOIN pg_am am ON am.oid=cls.relam
+LEFT JOIN pg_depend dep ON (dep.classid = cls.tableoid AND dep.objid = cls.oid AND dep.refobjsubid = '0' AND dep.refclassid=(SELECT oid FROM pg_class WHERE relname='pg_constraint') AND dep.deptype='i')
+LEFT OUTER JOIN pg_constraint con ON (con.tableoid = dep.refclassid AND con.oid = dep.refobjid)
+LEFT OUTER JOIN pg_description des ON (des.objoid=cls.oid AND des.classoid='pg_class'::regclass)
+LEFT OUTER JOIN pg_description desp ON (desp.objoid=con.oid AND desp.objsubid = 0 AND desp.classoid='pg_constraint'::regclass)
+WHERE indrelid = {{tid}}::oid
+{% if cid %}
+AND cls.oid = {{cid}}::oid
+{% endif %}
+AND contype='{{constraint_type}}'
+ORDER BY cls.relname
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/update.sql
new file mode 100644
index 0000000..af76d8e
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/sql/update.sql
@@ -0,0 +1,22 @@
+{### SQL to update constraint object ###}
+{% if data %}
+{# ==== To update constraint name ==== #}
+{% if data.name != o_data.name %}
+ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }}
+ RENAME CONSTRAINT {{ conn|qtIdent(o_data.name) }} TO {{ conn|qtIdent(data.name) }};
+{% endif %}
+{# ==== To update constraint tablespace ==== #}
+{% if data.spcname and data.spcname != o_data.spcname %}
+ALTER INDEX {{ conn|qtIdent(data.schema, data.name) }}
+ SET TABLESPACE {{ conn|qtIdent(data.spcname) }};
+{% endif %}
+{% if data.fillfactor and data.fillfactor != o_data.fillfactor %}
+ALTER INDEX {{ conn|qtIdent(data.schema, data.name) }}
+ SET (FILLFACTOR={{ data.fillfactor }});
+{% endif %}
+{# ==== To update constraint comments ==== #}
+{% if data.comment and data.comment != o_data.comment %}
+COMMENT ON CONSTRAINT {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(data.schema, data.table) }}
+ IS {{ data.comment|qtLiteral }};
+{% endif %}
+{% endif %}
\ No newline at end of file
reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: [email protected]
Cc: [email protected]
Subject: Re: Patch for index constraint (primary and unique key) [pgadmin4]
In-Reply-To: <CAFiP3vwEHqMBaFOYj=LR6TxbAU1KK4QaUYtr6Z_NR2NRiQwMsw@mail.gmail.com>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox