Hi, PFA initial patch for check constraint.
Note: This patch has dependency on Table, Column node and Index constraint. As of now all (5) constraint nodes are completed (initial patches). -- *Harshal Dhumal* *Software Engineer * EenterpriseDB <http://www.enterprisedb.com>
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/__init__.py new file mode 100644 index 0000000..3e43d92 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/__init__.py @@ -0,0 +1,823 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2016, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## + +"""Implements the Check Constraint Module.""" + +import json +from flask import render_template, make_response, request, jsonify +from flask.ext.babel import gettext as _ +from pgadmin.utils.ajax import make_json_response, \ + make_response as ajax_response, internal_server_error +from pgadmin.browser.utils import PGChildNodeView +from pgadmin.browser.collection import CollectionNodeModule +import pgadmin.browser.server_groups.servers.databases.schemas.tables as table +from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.driver import get_driver +from config import PG_DEFAULT_DRIVER +from functools import wraps +from pgadmin.browser.server_groups.servers.databases.schemas.tables.constraints.type \ + import ConstraintRegistry, ConstraintTypeModule + + +class CheckConstraintModule(CollectionNodeModule): + """ + class CheckConstraintModule(CollectionNodeModule): + + This class represents The Check Constraint Module. + + Methods: + ------- + * __init__(*args, **kwargs) + - Initialize the Check Constraint Module. + + * get_nodes(gid, sid, did, scid) + - Generate the Check Constraint collection node. + + * node_inode(gid, sid, did, scid) + - Returns Check Constraint node as leaf node. + + * script_load() + - Load the module script for the Check Constraint, when any of the + Check node is initialized. + """ + NODE_TYPE = 'check_constraints' + COLLECTION_LABEL = _("Check Constraints") + + def __init__(self, *args, **kwargs): + super(CheckConstraintModule, self).__init__(*args, **kwargs) + self.min_ver = None + self.max_ver = None + + def get_nodes(self, gid, sid, did, scid, doid): + """ + Generate the Check Constraint collection node. + """ + yield self.generate_browser_collection_node(doid) + + @property + def node_inode(self): + """ + Returns Check Constraint node as leaf node. + """ + return False + + @property + def script_load(self): + """ + Load the module script for the Check Constraint, when any of the + Check node is initialized. + """ + return table.TableModule.NODE_TYPE + + @property + def csssnippets(self): + """ + Returns a snippet of css to include in the page + """ + return [ + render_template( + "check_constraint/css/check_constraint.css", + node_type=self.node_type + ) + ] + + +blueprint = CheckConstraintModule(__name__) + + +class CheckConstraintView(PGChildNodeView): + """ + class CheckConstraintView(PGChildNodeView): + + This class inherits PGChildNodeView to get the different routes for + the module. + + The class is responsible to Create, Read, Update and Delete operations for + the Check Constraint. + + Methods: + ------- + + * module_js(): + - Load JS file (check-constraints.js) for this module. + + * check_precondition(f): + - Works as a decorator. + - Checks database connection status. + - Attach connection object and template path. + + * list(gid, sid, did, scid, doid): + - List the Check Constraints. + + * nodes(gid, sid, did, scid): + - Returns all the Check Constraints to generate Nodes in the browser. + + * properties(gid, sid, did, scid, doid): + - Returns the Check Constraint properties. + + * create(gid, sid, did, scid): + - Creates a new Check Constraint object. + + * update(gid, sid, did, scid, doid): + - Updates the Check Constraint object. + + * delete(gid, sid, did, scid, doid): + - Drops the Check Constraint object. + + * sql(gid, sid, did, scid, doid=None): + - Returns the SQL for the Check Constraint object. + + * msql(gid, sid, did, scid, doid=None): + - Returns the modified SQL. + + * get_sql(gid, sid, data, scid, tid=None): + - Generates the SQL statements to create/update the Check Constraint. + object. + + * dependents(gid, sid, did, scid, tid, cid): + - Returns the dependents for the Check Constraint object. + + * dependencies(gid, sid, did, scid, tid, cid): + - Returns the dependencies for the Check Constraint object. + + * validate_check_constraint(gid, sid, did, scid, tid, cid): + - Validate check constraint. + """ + node_type = blueprint.node_type + + parent_ids = [ + {'type': 'int', 'id': 'gid'}, + {'type': 'int', 'id': 'sid'}, + {'type': 'int', 'id': 'did'}, + {'type': 'int', 'id': 'scid'}, + {'type': 'int', 'id': 'tid'} + ] + ids = [ + {'type': 'int', 'id': 'cid'} + ] + + operations = dict({ + 'obj': [ + {'get': 'properties', 'delete': 'delete', 'put': 'update'}, + {'get': 'list', 'post': 'create'} + ], + 'delete': [{'delete': 'delete'}], + 'children': [{'get': 'children'}], + 'nodes': [{'get': 'node'}, {'get': 'nodes'}], + 'sql': [{'get': 'sql'}], + 'msql': [{'get': 'msql'}, {'get': 'msql'}], + 'stats': [{'get': 'statistics'}], + 'dependency': [{'get': 'dependencies'}], + 'dependent': [{'get': 'dependents'}], + 'module.js': [{}, {}, {'get': 'module_js'}], + 'validate': [{'get': 'validate_check_constraint'}], + }) + + def module_js(self): + """ + Load JS file (check_constraint.js) for this module. + """ + return make_response( + render_template( + "check_constraint/js/check_constraint.js", + _=_ + ), + 200, {'Content-Type': 'application/x-javascript'} + ) + + def check_precondition(f): + """ + Works as a decorator. + Checks database connection status. + Attach connection object and template path. + """ + @wraps(f) + def wrap(*args, **kwargs): + self = args[0] + driver = get_driver(PG_DEFAULT_DRIVER) + self.manager = driver.connection_manager(kwargs['sid']) + self.conn = self.manager.connection(did=kwargs['did']) + self.qtIdent = driver.qtIdent + + # If DB not connected then return error to browser + if not self.conn.connected(): + return precondition_required( + _("Connection to the server has been lost!") + ) + + ver = self.manager.version + + # we will set template path for sql scripts + if ver >= 90200: + self.template_path = 'check_constraint/sql/9.2_plus' + elif ver >= 90100: + self.template_path = 'check_constraint/sql/9.1_plus' + + SQL = render_template("/".join([self.template_path, + 'get_parent.sql']), + tid=kwargs['tid']) + status, rset = self.conn.execute_2darray(SQL) + if not status: + return internal_server_error(errormsg=rset) + + self.schema = rset['rows'][0]['schema'] + self.table = rset['rows'][0]['table'] + + return f(*args, **kwargs) + + return wrap + + def end_transaction(self): + """ + End database transaction. + Returns: + + """ + SQL = "END;" + self.conn.execute_scalar(SQL) + + @check_precondition + def list(self, gid, sid, did, scid, tid, cid=None): + """ + List the Check Constraints. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + tid: Table Id + cid: Check Id + """ + try: + res = self.get_node_list(gid, sid, did, scid, tid, cid) + return ajax_response( + response=res, + status=200 + ) + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @check_precondition + def get_node_list(self, gid, sid, did, scid, tid, cid=None): + """ + This function returns all check constraints + nodes within that collection as a list. + + Args: + gid: Server Group ID + sid: Server ID + did: Database ID + scid: Schema ID + tid: Table ID + cid: Cehck constraint ID + + Returns: + + """ + SQL = render_template("/".join([self.template_path, 'properties.sql']), + tid=tid) + status, res = self.conn.execute_dict(SQL) + + return res['rows'] + + @check_precondition + def nodes(self, gid, sid, did, scid, tid, cid=None): + """ + Returns all the Check Constraints. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + tid: Table Id + cid: Check constraint Id. + """ + try: + res = self.get_nodes(gid, sid, did, scid, tid, cid) + return make_json_response( + data=res, + status=200 + ) + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @check_precondition + def get_nodes(self, gid, sid, did, scid, tid, cid=None): + """ + This function returns all event check constraint as a list. + + Args: + gid: Server Group ID + sid: Server ID + did: Database ID + scid: Schema ID + tid: Table ID + cid: Check constraint ID + + Returns: + + """ + res = [] + SQL = render_template("/".join([self.template_path, + 'nodes.sql']), + tid=tid) + status, rset = self.conn.execute_2darray(SQL) + + for row in rset['rows']: + if "convalidated" in row and row["convalidated"]: + icon = "icon-check_constraints_bad" + valid = False + else: + icon = "icon-check_constraints" + valid = True + res.append( + self.blueprint.generate_browser_node( + row['oid'], + tid, + row['name'], + icon=icon, + valid=valid + )) + return res + + @check_precondition + def properties(self, gid, sid, did, scid, tid, cid): + """ + Returns the Check Constraints property. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + tid: Check Id + cid: Check Constraint Id + """ + + SQL = render_template("/".join([self.template_path, + 'properties.sql']), + tid=tid, cid=cid) + status, res = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + data = res['rows'][0] + return ajax_response( + response=data, + status=200 + ) + + @check_precondition + def create(self, gid, sid, did, scid, tid, cid=None): + """ + This function will create a primary key. + + Args: + gid: Server Group ID + sid: Server ID + did: Database ID + scid: Schema ID + tid: Table ID + cid: Check constraint ID + + Returns: + + """ + required_args = ['consrc'] + + data = request.form if request.form else json.loads(request.data.decode()) + + for arg in required_args: + if arg not in data or data[arg] == '': + return make_json_response( + status=400, + success=0, + errormsg=_( + "Couldn't find the required parameter (%s)." % arg + ) + ) + + data['schema'] = self.schema + data['table'] = self.table + try: + if 'name' not in data or data['name'] == "": + SQL = "BEGIN;" + # Start transaction. + status, res = self.conn.execute_scalar(SQL) + if not status: + self.end_transaction() + return internal_server_error(errormsg=res) + + # The below SQL will execute CREATE DDL only + SQL = render_template( + "/".join([self.template_path, 'create.sql']), + data=data + ) + + status, msg = self.conn.execute_scalar(SQL) + if not status: + self.end_transaction() + return internal_server_error(errormsg=msg) + + if 'name' not in data or data['name'] == "": + sql = render_template( + "/".join([self.template_path, + 'get_oid_with_transaction.sql'], + ), + tid=tid) + + status, res = self.conn.execute_dict(sql) + if not status: + self.end_transaction() + return internal_server_error(errormsg=res) + + self.end_transaction() + + data['name'] = res['rows'][0]['name'] + + else: + sql = render_template("/".join([self.template_path, 'get_oid.sql']), + tid=tid, + name=data['name']) + status, res = self.conn.execute_dict(sql) + if not status: + self.end_transaction() + return internal_server_error(errormsg=res) + + if "convalidated" in res['rows'][0] and res['rows'][0]["convalidated"]: + icon = "icon-check_constraints_bad" + valid = False + else: + icon = "icon-check_constraints" + valid = True + + sql = render_template("/".join([self.template_path, '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, + valid=valid + ) + ) + + except Exception as e: + self.end_transaction() + return make_json_response( + status=400, + success=0, + errormsg=e + ) + + @check_precondition + def delete(self, gid, sid, did, scid, tid, cid): + """ + Drops the Check Constraint object. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + tid: Check Id + cid: Check Constraint Id + """ + try: + SQL = render_template("/".join([self.template_path, + 'properties.sql']), + tid=tid, cid=cid) + status, res = self.conn.execute_dict(SQL) + + if not status: + return internal_server_error(errormsg=res) + + data = res['rows'][0] + + SQL = render_template("/".join([self.template_path, + 'delete.sql']), + data=data) + status, res = self.conn.execute_scalar(SQL) + if not status: + return internal_server_error(errormsg=res) + + return make_json_response( + success=1, + info=_("Check Constraint dropped"), + data={ + 'id': tid, + 'scid': scid, + 'sid': sid, + 'gid': gid, + 'did': did + } + ) + + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @check_precondition + def update(self, gid, sid, did, scid, tid, cid): + """ + Updates the Check Constraint object. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + tid: Table Id + cid: Check Constraint Id + """ + data = request.form if request.form else json.loads(request.data.decode()) + + try: + data['schema'] = self.schema + data['table'] = self.table + + SQL = self.get_sql(gid, sid, data, scid, tid, cid) + SQL = SQL.strip('\n').strip(' ') + if SQL != "": + status, res = self.conn.execute_scalar(SQL) + if not status: + return internal_server_error(errormsg=res) + + sql = render_template("/".join([self.template_path, 'get_name.sql']), + cid=cid) + status, res = self.conn.execute_dict(sql) + if not status: + return internal_server_error(errormsg=res) + + if "convalidated" in res['rows'][0] and res['rows'][0]["convalidated"]: + icon = 'icon-check_constraints_)bad' + valid = False + else: + icon = 'icon-check_constraints' + valid = True + + return make_json_response( + success=1, + info="Check Constraint updated", + data={ + 'id': cid, + 'tid': tid, + 'scid': scid, + 'sid': sid, + 'gid': gid, + 'did': did, + 'icon': icon, + 'val id': valid + } + ) + else: + return make_json_response( + success=1, + info="Nothing to update", + data={ + 'id': cid, + 'tid': tid, + 'scid': scid, + 'sid': sid, + 'gid': gid, + 'did': did + } + ) + + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @check_precondition + def sql(self, gid, sid, did, scid, tid, cid=None): + """ + Returns the SQL for the Check Constraint object. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + tid: Table Id + cid: Check Constraint Id + """ + + SQL = render_template("/".join([self.template_path, + 'properties.sql']), + tid=tid, cid=cid) + status, res = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + data = res['rows'][0] + data['schema'] = self.schema + data['table'] = self.table + + SQL = render_template("/".join([self.template_path, + 'create.sql']), + data=data) + SQL += "\n" + SQL += render_template( + "/".join([self.template_path, 'grant.sql']), + data=data) + + sql_header = "-- Constraint: {0}\n\n-- ".format(data['name']) + + sql_header += render_template( + "/".join([self.template_path, 'delete.sql']), + data=data) + sql_header += "\n" + + SQL = sql_header + SQL + + return ajax_response(response=SQL) + + @check_precondition + def msql(self, gid, sid, did, scid, tid, cid=None): + """ + Returns the modified SQL. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + tid: Table Id + cid: Check Constraint Id + + Returns: + Check Constraint object in json format. + """ + data = {} + for k, v in request.args.items(): + try: + data[k] = json.loads(v) + except ValueError: + data[k] = v + + data['schema'] = self.schema + data['table'] = self.table + try: + sql = self.get_sql(gid, sid, data, scid, tid, cid) + sql = sql.strip('\n').strip(' ') + + return make_json_response( + data=sql, + status=200 + ) + + except Exception as e: + return internal_server_error(errormsg=str(e)) + + def get_sql(self, gid, sid, data, scid, tid, cid=None): + """ + Generates the SQL statements to create/update the Check Constraint. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + tid: Table Id + cid: Check Constraint Id + """ + try: + if cid is not None: + SQL = render_template("/".join([self.template_path, + 'properties.sql']), + tid=tid, cid=cid) + status, res = self.conn.execute_dict(SQL) + + if not status: + return False, internal_server_error(errormsg=res) + + old_data = res['rows'][0] + + SQL = render_template( + "/".join([self.template_path, 'update.sql']), + data=data, o_data=old_data, conn=self.conn + ) + else: + required_args = ['consrc'] + + for arg in required_args: + if arg not in data: + return _('-- definition incomplete') + elif isinstance(data[arg], list) and len(data[arg]) < 1: + return _('-- definition incomplete') + + SQL = render_template("/".join([self.template_path, + 'create.sql']), + data=data) + SQL += "\n" + SQL += render_template("/".join([self.template_path, 'grant.sql']), + data=data) + + return SQL + except Exception as e: + return False, internal_server_error(errormsg=str(e)) + + @check_precondition + def dependents(self, gid, sid, did, scid, tid, cid): + """ + This function get the dependents and return ajax response + for the Check Constraint node. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + tid: Table Id + cid: Check Constraint Id + """ + dependents_result = self.get_dependents(self.conn, cid) + return ajax_response( + response=dependents_result, + status=200 + ) + + @check_precondition + def dependencies(self, gid, sid, did, scid, tid, cid): + """ + This function get the dependencies and return ajax response + for the Check Constraint node. + + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + tid: Table Id + cid: Check Constraint Id + """ + dependencies_result = self.get_dependencies(self.conn, cid) + return ajax_response( + response=dependencies_result, + status=200 + ) + + @check_precondition + def validate_check_constraint(self, gid, sid, did, scid, tid, cid): + """ + Validate check constraint. + Args: + gid: Server Group Id + sid: Server Id + did: Database Id + scid: Schema Id + tid: Table Id + cid: Check Constraint Id + + Returns: + + """ + data = {} + try: + data['schema'] = self.schema + data['table'] = self.table + sql = render_template("/".join([self.template_path, 'get_name.sql']), cid=cid) + status, res = self.conn.execute_scalar(sql) + if not status: + return internal_server_error(errormsg=res) + + data['name'] = res + sql = render_template("/".join([self.template_path, 'validate.sql']), data=data) + status, res = self.conn.execute_dict(sql) + if not status: + return internal_server_error(errormsg=res) + + return make_json_response( + success=1, + info=_("Check constraint updated."), + data={ + 'id': cid, + 'tid': tid, + 'scid': scid, + 'did': did + } + ) + + except Exception as e: + return internal_server_error(errormsg=str(e)) + +constraint = ConstraintRegistry( + 'check_constraint', CheckConstraintModule, CheckConstraintView + ) +CheckConstraintView.register_node_view(blueprint) diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/static/img/check-constraints-bad.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/static/img/check-constraints-bad.png new file mode 100644 index 0000000000000000000000000000000000000000..32a045b8fafdc08640d53b2a86b1dcabcb0fe0fd GIT binary patch literal 579 zcmV-J0=)f+P)<h;3K|Lk000e1NJLTq000mG000mO0{{R3C@l|D00001b5ch_0Itp) z=>Px$AW%$HMR1Z9#Q*@REHmdHAm<<;=p`lTDl6$LE15$|nM6yxJ3#6&F}^)Qx<p3n zH#h4zIK)Ou#79fTM@#HJKkY(8?L$QEL`CjJMeasM?ng(;QB>|oNbX2U?n+AUOH1!e zOz%xi?@dncPEXKRS?^Cz#amtQQBm+xQt(q#@KaRqR8;U)Rq<9<@mE*YVq(`~V)0vB z+GS<)VPW%PV%=$Jag!JHXlV6qZS`($_HuH3pd<EncJ_C7f1@XWqbGu>Du=8uhpjJ) zvN4agH<i3UrMYgWyK<eyN1Vq+p2tbA!G5C3PO!m$q|HvV#D$~JOsv;ftk_qv-CeQX zT*cC%$J3;><6_L$t<Kr8)!w|r@o>cPam4X*+~mi`^K{Glc|xh<NdN!<0d!JMQvg8b z*k%9#00Cl4M??UK1szBL000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipf34<ROg z(p72z0056kL_t&-)1{2Z3c^qT1mDEody6IZuCW&s1V!`^4}$goe?(18@b2Db*j*w1 z%4M(p;&Zw?9ZaKAxo*x;COX}<8fzjqKRv^2kF1spymYHMjE2m7Hl|a~emCNwG8(i? z8I#``(kiBrEbh}(Qn8TL2+$}b3Hn^7p`K6R#_6zQ2$?ux;lXBYB>hkN@C%g?4vVBM R$bbL<002ovPDHLkV1min0OSAw literal 0 HcmV?d00001 diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/static/img/check-constraints.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/static/img/check-constraints.png new file mode 100644 index 0000000000000000000000000000000000000000..9d1d2a061c7948168d7b1c2474d769b31709f1cf GIT binary patch literal 406 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbK}X@F0NE08{VY2nhHc^eMaU%j`d zaI$#+HuEKC{pKEZKYn>h(+aIMH^MjGjcs3}f9Cqyt&fvx7AT*)xv^`L;hf{Hi_iP4 zxgK%&V?q65_4c*;8}G%;JMMY<SLM___M4Bi9{E^!<YUpX&n1ga`7PgFwEkdS!(#P< zNn&@N9OqiK(i&(nV@Z%-FoVOh8)-leXMsm#F_88EW4Dvpc0fjir;B5V#O36K1sn!O zhRVf}5jSsGPH?f<xudc|vBoY<&5cb=uTGB9v187J4II+it5?jhn8F{TsCZIWRad$D zg1*K9W%cu2NsD(hEfVT#*wm#pYw;D04+0E(uQE?s`Z6*ZXoqTvYeY#(Vo9o1a#1Rf zVlXl=G|)9P(lsy)F*2|+F}5->(Kax(GBB{1sVaw}AvZrIGp!P$!N3x%0i@c>zzm|{ T)b!9bKn)C@u6{1-oD!M<=4O^k literal 0 HcmV?d00001 diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/css/check_constraint.css b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/css/check_constraint.css new file mode 100644 index 0000000..0691868 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/css/check_constraint.css @@ -0,0 +1,15 @@ +.icon-check_bad, .icon-check_constraints_bad { + background-image: url('{{ url_for('NODE-%s.static' % node_type, filename='img/check-constraints-bad.png' )}}') !important; + background-repeat: no-repeat; + align-content: center; + vertical-align: middle; + height: 1.3em; +} + +.icon-check, .icon-check_constraints { + background-image: url('{{ url_for('NODE-%s.static' % node_type, filename='img/check-constraints.png' )}}') !important; + background-repeat: no-repeat; + align-content: center; + vertical-align: middle; + height: 1.3em; +} \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/js/check_constraint.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/js/check_constraint.js new file mode 100644 index 0000000..c529024 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/js/check_constraint.js @@ -0,0 +1,196 @@ +// Check Constraint Module: Node +define( + ['jquery', 'underscore', 'underscore.string', 'pgadmin', 'pgadmin.browser', 'alertify', 'pgadmin.browser.collection'], +function($, _, S, pgAdmin, pgBrowser, Alertify) { + + // Check Constraint Node + if (!pgBrowser.Nodes['check_constraints']) { + pgAdmin.Browser.Nodes['check_constraints'] = pgBrowser.Node.extend({ + type: 'check_constraints', + label: '{{ _('Check') }}', + collection_type: 'coll-constraints', + sqlAlterHelp: 'ddl-alter.html', + sqlCreateHelp: 'ddl-constraints.html', + hasSQL: true, + hasDepends: true, + parent_type: ['table'], + Init: function() { + // Avoid mulitple registration of menus + if (this.initialized) + return; + + this.initialized = true; + + pgBrowser.add_menus([{ + name: 'create_check_constraints_on_coll', node: 'coll-constraints', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 5, label: '{{ _('Check...') }}', + icon: 'wcTabIcon icon-check_constraints', data: {action: 'create', check: true}, + enable: 'canCreate' + },{ + name: 'validate_check_constraint', node: 'check_constraints', module: this, + applies: ['object', 'context'], callback: 'validate_check_constraint', + category: 'validate', priority: 4, label: '{{ _('Validate check constraint') }}', + icon: 'fa fa-link', enable : 'is_not_valid', data: {action: 'edit', check: true} + } + ]); + + }, + is_not_valid: function(itemData, item, data) { + if (this.canCreate(itemData, item, data)) { + return (itemData && !itemData.valid); + } else { + return false; + } + }, + callbacks: { + validate_check_constraint: function(args) { + var input = args || {}; + obj = this, + t = pgBrowser.tree, + i = input.item || t.selected(), + d = i && i.length == 1 ? t.itemData(i) : undefined; + + if (!d) { + return false; + } + var data = d; + $.ajax({ + url: obj.generate_url(i, 'validate', d, true), + type:'GET', + success: function(res) { + if (res.success == 1) { + Alertify.success("{{ _('" + res.info + "') }}"); + t.removeIcon(i); + data.valid = true; + data.icon = 'icon-check_constraints'; + t.addIcon(i, {icon: data.icon}); + setTimeout(function() {t.deselect(i);}, 10); + setTimeout(function() {t.select(i);}, 100); + } + }, + error: function(xhr, status, error) { + try { + var err = $.parseJSON(xhr.responseText); + if (err.success == 0) { + msg = S('{{ _(' + err.errormsg + ')}}').value(); + Alertify.error("{{ _('" + err.errormsg + "') }}"); + } + } catch (e) {} + t.unload(i); + } + }); + + return false; + } + }, + canDrop: pgBrowser.Nodes['schema'].canChildDrop, + model: pgAdmin.Browser.Node.Model.extend({ + defaults: { + name: undefined, + oid: undefined, + description: undefined, + consrc: undefined, + connoinherit: undefined, + convalidated: undefined + }, + // Check Constraint Schema + schema: [{ + id: 'name', label: '{{ _('Name') }}', type:'text', cell:'string', + disabled: 'isDisabled' + },{ + id: 'oid', label:'{{ _('OID') }}', cell: 'string', + type: 'text' , mode: ['properties'] + },{ + id: 'comment', label: '{{ _('Comment') }}', type: 'multiline', cell: + 'string', mode: ['properties', 'create', 'edit'], + deps:['name'], disabled:function(m) { + var name = m.get('name'); + if (!(name && name != '')) { + setTimeout(function(){ + m.set('comment', null); + },10); + return true; + } else { + return false; + } + } + },{ + id: 'consrc', label: '{{ _('Check') }}', type: 'multiline', cell: + 'string', group: '{{ _('Definition') }}', mode: ['properties', + 'create', 'edit'], disabled: function(m) { return !m.isNew(); } + },{ + id: 'connoinherit', label: '{{ _('No Inherit') }}', type: + 'switch', cell: 'boolean', group: '{{ _('Definition') }}', mode: + ['properties', 'create', 'edit'], min_version: 90200, + disabled: function(m) { + return !m.isNew(); + } + },{ + id: 'convalidated', label: "{{ _("Don't validate") }}", type: 'switch', cell: + 'boolean', group: '{{ _('Definition') }}', min_version: 90200, + disabled: function(m) { + return !(m.isNew() || m.get("convalidated")); + }, + mode: ['properties', 'create', 'edit'] + }], + // Client Side Validation + validate: function() { + var err = {}, + errmsg; + + if (_.isUndefined(this.get('consrc')) || String(this.get('consrc')).replace(/^\s+|\s+$/g, '') == '') { + err['consrc'] = '{{ _('Check can not be empty!') }}'; + errmsg = errmsg || err['consrc']; + } + + this.errorModel.clear().set(err); + + if (_.size(err)) { + this.trigger('on-status', {msg: errmsg}); + return errmsg; + } + + return null; + + }, + isDisabled: function(m){ + if (!m.isNew()) { + var server = this.node_info.server; + if (server.version < 90200) + { + return true; + } + } + return false; + } + }), + // Below function will enable right click menu for creating check constraint. + canCreate: function(itemData, item, data) { + // If check is false then , we will allow create menu + if (data && data.check == false) + return true; + + var t = pgBrowser.tree, i = item, d = itemData, parents = []; + // To iterate over tree to check parent node + while (i) { + // If it is schema then allow user to c reate table + if (_.indexOf(['schema'], d._type) > -1) + return true; + parents.push(d._type); + i = t.hasParent(i) ? t.parent(i) : null; + d = i ? t.itemData(i) : null; + } + // If node is under catalog then do not allow 'create' menu + if (_.indexOf(parents, 'catalog') > -1) { + return false; + } else { + return true; + } + } + }); + + } + + return pgBrowser.Nodes['check_constraints']; +}); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.1_plus/create.sql new file mode 100644 index 0000000..8d8c10a --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.1_plus/create.sql @@ -0,0 +1,4 @@ +{% if data %} +ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }} + ADD{% if data.name %} CONSTRAINT {{ conn|qtIdent(data.name) }}{% endif%} CHECK ({{ data.consrc }}); +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.1_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.1_plus/delete.sql new file mode 100644 index 0000000..5a85b4f --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.1_plus/delete.sql @@ -0,0 +1,3 @@ +{% if data %} +ALTER TABLE {{ conn|qtIdent(data.nspname, data.relname) }} DROP CONSTRAINT {{ conn|qtIdent(data.name) }}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.1_plus/get_name.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.1_plus/get_name.sql new file mode 100644 index 0000000..12dfa15 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.1_plus/get_name.sql @@ -0,0 +1,4 @@ +SELECT conname as name +FROM pg_constraint ct +WHERE contype = 'c' +AND ct.oid = {{cid}}::oid \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.1_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.1_plus/get_oid.sql new file mode 100644 index 0000000..fa521e6 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.1_plus/get_oid.sql @@ -0,0 +1,7 @@ +SELECT + oid, conname as name +FROM + pg_constraint +WHERE + conrelid = {{tid}}::oid + AND conname={{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.1_plus/get_oid_with_transaction.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.1_plus/get_oid_with_transaction.sql new file mode 100644 index 0000000..0f2e29f --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.1_plus/get_oid_with_transaction.sql @@ -0,0 +1,5 @@ +SELECT ct.oid, + ct.conname as name +FROM pg_constraint ct +WHERE contype='c' AND + conrelid = {{tid}}::oid LIMIT 1; \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.1_plus/get_parent.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.1_plus/get_parent.sql new file mode 100644 index 0000000..a652857 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.1_plus/get_parent.sql @@ -0,0 +1,7 @@ +SELECT nsp.nspname AS schema, + rel.relname AS table +FROM + pg_class rel +JOIN pg_namespace nsp +ON rel.relnamespace = nsp.oid::int +WHERE rel.oid = {{tid}}::int \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.1_plus/grant.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.1_plus/grant.sql new file mode 100644 index 0000000..0fb0ea5 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.1_plus/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/check_constraint/templates/check_constraint/sql/9.1_plus/nodes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.1_plus/nodes.sql new file mode 100644 index 0000000..0701c9f --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.1_plus/nodes.sql @@ -0,0 +1,6 @@ +SELECT c.oid, conname as name + FROM pg_constraint c +WHERE contype = 'c' +{% if tid %} + AND conrelid = {{ tid }}::oid +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.1_plus/properties.sql new file mode 100644 index 0000000..18cdb35 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.1_plus/properties.sql @@ -0,0 +1,13 @@ +SELECT c.oid, conname as name, relname, nspname, description as comment , + pg_get_expr(conbin, conrelid, true) as consrc + FROM pg_constraint c + JOIN pg_class cl ON cl.oid=conrelid + JOIN pg_namespace nl ON nl.oid=relnamespace +LEFT OUTER JOIN + pg_description des ON (des.objoid=c.oid AND + des.classoid='pg_constraint'::regclass) +WHERE contype = 'c' + AND conrelid = {{ tid }}::oid +{% if cid %} + AND c.oid = {{ cid }}::oid +{% endif %} \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.1_plus/update.sql new file mode 100644 index 0000000..711a2e0 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.1_plus/update.sql @@ -0,0 +1,2 @@ +COMMENT ON CONSTRAINT {{ conn|qtIdent(o_data.name) }} ON {{ conn|qtIdent(data.schema, data.table) }} + IS {{ data.comment|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.2_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.2_plus/create.sql new file mode 100644 index 0000000..2c7a57f --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.2_plus/create.sql @@ -0,0 +1,6 @@ +{% if data %} +ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }} + ADD{% if data.name %} CONSTRAINT {{ conn|qtIdent(data.name) }}{% endif%} CHECK ({{ data.consrc }}){% if data.convalidated %} + + NOT VALID{% endif %}{% if data.connoinherit %} NO INHERIT{% endif %}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.2_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.2_plus/delete.sql new file mode 100644 index 0000000..5a85b4f --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.2_plus/delete.sql @@ -0,0 +1,3 @@ +{% if data %} +ALTER TABLE {{ conn|qtIdent(data.nspname, data.relname) }} DROP CONSTRAINT {{ conn|qtIdent(data.name) }}; +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.2_plus/get_name.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.2_plus/get_name.sql new file mode 100644 index 0000000..a92f893 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.2_plus/get_name.sql @@ -0,0 +1,5 @@ +SELECT conname as name, + NOT convalidated as convalidated +FROM pg_constraint ct +WHERE contype = 'c' +AND ct.oid = {{cid}}::oid \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.2_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.2_plus/get_oid.sql new file mode 100644 index 0000000..46f32c9 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.2_plus/get_oid.sql @@ -0,0 +1,8 @@ +SELECT + oid, conname as name, + NOT convalidated as convalidated +FROM + pg_constraint +WHERE + conrelid = {{tid}}::oid + AND conname={{ name|qtLiteral }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.2_plus/get_oid_with_transaction.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.2_plus/get_oid_with_transaction.sql new file mode 100644 index 0000000..b497e3f --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.2_plus/get_oid_with_transaction.sql @@ -0,0 +1,6 @@ +SELECT ct.oid, + ct.conname as name, + NOT convalidated as convalidated +FROM pg_constraint ct +WHERE contype='c' AND + conrelid = {{tid}}::oid LIMIT 1; \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.2_plus/get_parent.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.2_plus/get_parent.sql new file mode 100644 index 0000000..a652857 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.2_plus/get_parent.sql @@ -0,0 +1,7 @@ +SELECT nsp.nspname AS schema, + rel.relname AS table +FROM + pg_class rel +JOIN pg_namespace nsp +ON rel.relnamespace = nsp.oid::int +WHERE rel.oid = {{tid}}::int \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.2_plus/grant.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.2_plus/grant.sql new file mode 100644 index 0000000..0fb0ea5 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.2_plus/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/check_constraint/templates/check_constraint/sql/9.2_plus/nodes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.2_plus/nodes.sql new file mode 100644 index 0000000..6fdc3c1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.2_plus/nodes.sql @@ -0,0 +1,7 @@ +SELECT c.oid, conname as name, + NOT convalidated as convalidated + FROM pg_constraint c +WHERE contype = 'c' +{% if tid %} + AND conrelid = {{ tid }}::oid +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.2_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.2_plus/properties.sql new file mode 100644 index 0000000..509d317 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.2_plus/properties.sql @@ -0,0 +1,14 @@ +SELECT c.oid, conname as name, relname, nspname, description as comment, + pg_get_expr(conbin, conrelid, true) as consrc, + connoinherit, NOT convalidated as convalidated + FROM pg_constraint c + JOIN pg_class cl ON cl.oid=conrelid + JOIN pg_namespace nl ON nl.oid=relnamespace +LEFT OUTER JOIN + pg_description des ON (des.objoid=c.oid AND + des.classoid='pg_constraint'::regclass) +WHERE contype = 'c' + AND conrelid = {{ tid }}::oid +{% if cid %} + AND c.oid = {{ cid }}::oid +{% endif %} \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.2_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.2_plus/update.sql new file mode 100644 index 0000000..e759035 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.2_plus/update.sql @@ -0,0 +1,12 @@ +{% set name = o_data.name %} +{% if data.name %} +{% set name = data.name %} +ALTER TABLE {{ conn|qtIdent(o_data.nspname, o_data.relname) }} + RENAME CONSTRAINT {{ conn|qtIdent(o_data.name) }} TO {{ conn|qtIdent(data.name) }};{% endif -%} +{% if 'convalidated' in data and o_data.convalidated != data.convalidated and not data.convalidated %} + +ALTER TABLE {{ conn|qtIdent(o_data.nspname, o_data.relname) }} + VALIDATE CONSTRAINT {{ conn|qtIdent(name) }};{% endif -%}{% if data.comment %} + +COMMENT ON CONSTRAINT {{ conn|qtIdent(name) }} ON {{ conn|qtIdent(data.schema, data.table) }} + IS {{ data.comment|qtLiteral }};{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.2_plus/validate.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.2_plus/validate.sql new file mode 100644 index 0000000..5a62c80 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/sql/9.2_plus/validate.sql @@ -0,0 +1,2 @@ +ALTER TABLE {{ conn|qtIdent(data.schema, data.table) }} + VALIDATE CONSTRAINT {{ conn|qtIdent(data.name) }}; \ No newline at end of file
-- Sent via pgadmin-hackers mailing list (pgadmin-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgadmin-hackers